feat: 国际进港查询运单修改页面及列表侧滑菜单

- 新增运单修改页面(编辑表单:代理人/特码/包装类型/运单类型/锁定状态/备注)
- 查询列表添加侧滑"修改"按钮入口
- 详情和修改页接口传参改用 prefix+no
- 详情页和修改页移除"库位"表单项
- 仓库信息入库时间取值改为 opDate

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-16 12:18:35 +08:00
parent baaa9c5615
commit 47cef6ee59
13 changed files with 879 additions and 42 deletions

View File

@@ -9,7 +9,6 @@ import com.lukouguoji.gjj.databinding.ActivityIntImpQueryDetailsBinding
import com.lukouguoji.gjj.viewModel.IntImpQueryDetailsViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.base.CustomVP2Adapter
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.router.ARouterConstants
/**
@@ -49,9 +48,10 @@ class IntImpQueryDetailsActivity :
companion object {
@JvmStatic
fun start(context: Context, maWbId: Long?) {
fun start(context: Context, prefix: String?, no: String?) {
val starter = Intent(context, IntImpQueryDetailsActivity::class.java)
.putExtra(Constant.Key.ID, maWbId?.toString() ?: "")
.putExtra("prefix", prefix ?: "")
.putExtra("no", no ?: "")
context.startActivity(starter)
}
}

View File

@@ -0,0 +1,37 @@
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.ActivityIntImpQueryEditBinding
import com.lukouguoji.gjj.viewModel.IntImpQueryEditViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
/**
* 国际进港运单修改页面
*/
class IntImpQueryEditActivity :
BaseBindingActivity<ActivityIntImpQueryEditBinding, IntImpQueryEditViewModel>() {
override fun layoutId() = R.layout.activity_int_imp_query_edit
override fun viewModelClass() = IntImpQueryEditViewModel::class.java
override fun initOnCreate(savedInstanceState: Bundle?) {
setBackArrow("国际进港运单修改")
binding.viewModel = viewModel
viewModel.initOnCreated(intent)
}
companion object {
@JvmStatic
fun start(context: Context, maWbId: Long?, prefix: String?, no: String?) {
val starter = Intent(context, IntImpQueryEditActivity::class.java)
.putExtra("maWbId", maWbId ?: 0L)
.putExtra("prefix", prefix ?: "")
.putExtra("no", no ?: "")
context.startActivity(starter)
}
}
}

View File

@@ -18,5 +18,11 @@ class IntImpQueryViewHolder(view: View) :
// 注册整行点击事件
notifyItemClick(position, binding.ll)
// 侧滑菜单 - 修改按钮
binding.btnEdit.setOnClickListener {
binding.swipeMenu.quickClose()
clickListener?.onItemClick(position, 2000) // type=2000表示修改操作
}
}
}

View File

@@ -6,7 +6,6 @@ import com.lukouguoji.gjj.fragment.IntImpQueryStorageFragment
import com.lukouguoji.gjj.fragment.IntImpQueryWarehouseFragment
import com.lukouguoji.gjj.fragment.IntImpQueryWaybillFragment
import com.lukouguoji.module_base.base.BaseViewModel
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.ktx.launchLoadingCollect
import com.lukouguoji.module_base.ktx.showToast
@@ -18,7 +17,8 @@ import com.lukouguoji.module_base.ktx.toRequestBody
class IntImpQueryDetailsViewModel : BaseViewModel() {
// ==================== 基础数据 ====================
var maWbId: String = "" // 运单主键ID
var prefix: String = "" // 运单号前缀
var no: String = "" // 运单号主体
// ==================== Tab管理 ====================
val currentTab = MutableLiveData(0) // 当前Tab索引 (0/1/2)
@@ -50,7 +50,8 @@ class IntImpQueryDetailsViewModel : BaseViewModel() {
* 初始化(从Intent获取maWbId)
*/
fun initOnCreated(intent: Intent) {
maWbId = intent.getStringExtra(Constant.Key.ID) ?: ""
prefix = intent.getStringExtra("prefix") ?: ""
no = intent.getStringExtra("no") ?: ""
}
/**
@@ -64,18 +65,12 @@ class IntImpQueryDetailsViewModel : BaseViewModel() {
* 加载详情数据
*/
fun loadDetails() {
if (maWbId.isEmpty()) {
showToast("运单ID为空")
if (prefix.isEmpty() || no.isEmpty()) {
showToast("运单号参数为空")
return
}
val maWbIdValue = maWbId.toLongOrNull()
if (maWbIdValue == null) {
showToast("运单ID格式错误")
return
}
val params = mapOf("maWbId" to maWbIdValue).toRequestBody()
val params = mapOf("prefix" to prefix, "no" to no).toRequestBody()
launchLoadingCollect({ NetApply.api.getIntImpQueryDetails(params) }) {
onSuccess = { result ->

View File

@@ -0,0 +1,368 @@
package com.lukouguoji.gjj.viewModel
import android.content.Intent
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.google.gson.Gson
import com.lukouguoji.module_base.base.BaseViewModel
import com.lukouguoji.module_base.bean.IntImpQueryEditBean
import com.lukouguoji.module_base.common.ConstantEvent
import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.impl.FlowBus
import com.lukouguoji.module_base.ktx.launchCollect
import com.lukouguoji.module_base.ktx.launchLoadingCollect
import com.lukouguoji.module_base.ktx.showToast
import com.lukouguoji.module_base.ktx.toRequestBody
import dev.utils.app.info.KeyValue
import kotlinx.coroutines.launch
/**
* 国际进港运单修改 ViewModel
*/
class IntImpQueryEditViewModel : BaseViewModel() {
// 数据Bean
val dataBean = MutableLiveData(IntImpQueryEditBean())
// 运单标识
var maWbId: Long = 0
var prefix: String = ""
var no: String = ""
// ==================== 下拉列表 ====================
val agentList = MutableLiveData<List<KeyValue>>(emptyList())
val spCodeList = MutableLiveData<List<KeyValue>>(emptyList())
val packageTypeList = MutableLiveData<List<KeyValue>>(emptyList())
val waybillTypeList = MutableLiveData<List<KeyValue>>(emptyList())
val lockStateList = MutableLiveData(
listOf(
KeyValue("未锁", "0"),
KeyValue("锁定", "1")
)
)
/**
* 初始化数据
*/
fun initOnCreated(intent: Intent) {
maWbId = intent.getLongExtra("maWbId", 0L)
prefix = intent.getStringExtra("prefix") ?: ""
no = intent.getStringExtra("no") ?: ""
if (prefix.isEmpty() || no.isEmpty()) {
showToast("运单号参数为空")
getTopActivity().finish()
return
}
// 加载下拉列表
loadAgentList()
loadSpCodeList()
loadPackageTypeList()
loadWaybillTypeList()
// 加载详情
loadDetails()
}
/**
* 加载代理人下拉列表
*/
private fun loadAgentList() {
launchCollect({ NetApply.api.getIntImpAgentList() }) {
onSuccess = { result ->
val list = result.data?.mapNotNull { bean ->
if (bean.name != null && bean.code != null) {
KeyValue(bean.name, bean.code)
} else null
} ?: emptyList()
agentList.value = list
// 详情已加载时匹配代理人
matchAgent()
}
}
}
/**
* 加载特码下拉列表
* flag=1(国际), ieFlag=I(进港)
*/
private fun loadSpCodeList() {
launchCollect({ NetApply.api.getSpecialCodeList(1, "I", "") }) {
onSuccess = { result ->
val list = result.data?.mapNotNull { bean ->
if (bean.name != null && bean.code != null) {
KeyValue(bean.name, bean.code)
} else null
} ?: emptyList()
spCodeList.value = list
matchSpCode()
}
}
}
/**
* 加载包装类型下拉列表(国际进港专用)
*/
private fun loadPackageTypeList() {
launchCollect({ NetApply.api.getGjjPackTypeList() }) {
onSuccess = { result ->
val list = result.data?.mapNotNull { bean ->
if (bean.packageName.isNotEmpty()) {
KeyValue(bean.packageName, bean.packageName)
} else null
} ?: emptyList()
packageTypeList.value = list
matchPackageType()
}
}
}
/**
* 加载运单类型下拉列表
* type=II(国际进港)
*/
private fun loadWaybillTypeList() {
launchCollect({ NetApply.api.getWaybillTypeList("II") }) {
onSuccess = { result ->
val list = result.data?.mapNotNull { bean ->
if (bean.name != null && bean.code != null) {
KeyValue(bean.name, bean.code)
} else null
} ?: emptyList()
waybillTypeList.value = list
matchWaybillType()
}
}
}
/**
* 加载运单详情数据
*/
private fun loadDetails() {
val params = mapOf("prefix" to prefix, "no" to no).toRequestBody()
launchLoadingCollect({ NetApply.api.getIntImpQueryDetails(params) }) {
onSuccess = { result ->
val data = result.data ?: emptyMap()
// 提取 maWb 对象
val maWb = data["maWb"] as? Map<String, Any> ?: emptyMap()
// 提取 maWbM 对象
val maWbM = data["maWbM"] as? Map<String, Any> ?: emptyMap()
// 提取 warehouseList(用于计算入库件数和入库重量)
val warehouseList = data["warehouseList"] as? List<Map<String, Any>> ?: emptyList()
// 合并数据
val mergedData = mutableMapOf<String, Any>()
mergedData.putAll(maWb)
mergedData.putAll(maWbM)
// 运单号: 组合 prefix + no
val prefix = maWb["prefix"] as? String ?: ""
val no = maWb["no"] as? String ?: ""
if (prefix.isNotEmpty() && no.isNotEmpty()) {
mergedData["wbNo"] = "$prefix$no"
}
// 代理人名称
if (!mergedData.containsKey("agentName") || (mergedData["agentName"] as? String).isNullOrEmpty()) {
maWb["agentCode"]?.let { mergedData["agentName"] = it }
}
// 运单件数/重量映射
val pc = maWb["pc"]
when (pc) {
is Number -> mergedData["awbPc"] = pc.toLong()
is String -> mergedData["awbPc"] = pc.toLongOrNull() ?: 0L
}
val weight = maWb["weight"]
when (weight) {
is Number -> mergedData["awbWeight"] = weight.toDouble()
is String -> mergedData["awbWeight"] = weight.toDoubleOrNull() ?: 0.0
}
// 入库件数和入库重量: 从 warehouseList 计算总和
if (warehouseList.isNotEmpty()) {
var totalPc = 0L
var totalWeight = 0.0
warehouseList.forEach { warehouse ->
val wPc = warehouse["pc"]
when (wPc) {
is Number -> totalPc += wPc.toLong()
is String -> totalPc += wPc.toLongOrNull() ?: 0L
}
val wWeight = warehouse["weight"]
when (wWeight) {
is Number -> totalWeight += wWeight.toDouble()
is String -> totalWeight += wWeight.toDoubleOrNull() ?: 0.0
}
}
mergedData["inPc"] = totalPc
mergedData["inWeight"] = totalWeight
}
// lockState 转换为 String(SPINNER 绑定用)
val lockState = mergedData["lockState"]
when (lockState) {
is Number -> mergedData["lockState"] = lockState.toInt().toString()
is String -> mergedData["lockState"] = lockState
}
// 转换为 Bean
val bean = Gson().fromJson(Gson().toJson(mergedData), IntImpQueryEditBean::class.java)
// 匹配下拉列表
matchAgent(bean)
matchSpCode(bean)
matchPackageType(bean)
matchWaybillType(bean)
matchLockState(bean)
dataBean.value = bean
}
}
}
/**
* 匹配代理人
*/
private fun matchAgent(bean: IntImpQueryEditBean? = dataBean.value) {
bean ?: return
val currentCode = bean.agentCode
if (currentCode.isNullOrEmpty()) return
val list = agentList.value ?: return
if (list.isEmpty()) return
val match = list.find { it.value == currentCode }
if (match != null) {
bean.agentName = match.key
bean.agentCode = match.value
}
}
/**
* 匹配特码
*/
private fun matchSpCode(bean: IntImpQueryEditBean? = dataBean.value) {
bean ?: return
val currentCode = bean.spCode
if (currentCode.isNullOrEmpty()) return
val list = spCodeList.value ?: return
if (list.isEmpty()) return
val match = list.find { it.value == currentCode }
if (match != null) {
bean.spCode = match.value
}
}
/**
* 匹配包装类型
*/
private fun matchPackageType(bean: IntImpQueryEditBean? = dataBean.value) {
bean ?: return
val currentType = bean.packageType
if (currentType.isNullOrEmpty()) return
val list = packageTypeList.value ?: return
if (list.isEmpty()) return
val match = list.find { it.value?.contains(currentType) == true }
if (match != null) {
bean.packageType = match.value
}
}
/**
* 匹配运单类型
*/
private fun matchWaybillType(bean: IntImpQueryEditBean? = dataBean.value) {
bean ?: return
val currentCode = bean.awbType
if (currentCode.isNullOrEmpty()) return
val list = waybillTypeList.value ?: return
if (list.isEmpty()) return
val match = list.find { it.value == currentCode }
if (match != null) {
bean.awbType = match.value
}
}
/**
* 匹配锁定状态
*/
private fun matchLockState(bean: IntImpQueryEditBean? = dataBean.value) {
bean ?: return
val currentState = bean.lockState
if (currentState.isNullOrEmpty()) return
val list = lockStateList.value ?: return
val match = list.find { it.value == currentState }
if (match != null) {
bean.lockState = match.value
}
}
/**
* 保存修改
*/
fun submit() {
val bean = dataBean.value ?: return
// 构建提交数据(只提交需要的字段)
val submitData = mutableMapOf<String, Any?>()
submitData["maWbId"] = if (maWbId != 0L) maWbId else bean.maWbId
submitData["activeId"] = bean.activeId
submitData["prefix"] = bean.prefix
submitData["no"] = bean.no
submitData["wbNo"] = bean.wbNo
submitData["agentCode"] = bean.agentCode
submitData["spCode"] = bean.spCode
submitData["packageType"] = bean.packageType
submitData["awbType"] = bean.awbType
submitData["lockState"] = bean.lockState?.toIntOrNull()
submitData["remark"] = bean.remark
submitData["fno"] = bean.fno
submitData["fdate"] = bean.fdate
submitData["flight"] = bean.flight
submitData["pc"] = bean.pc
submitData["weight"] = bean.weight
submitData["volume"] = bean.volume
submitData["origin"] = bean.origin
submitData["dest"] = bean.dest
submitData["range"] = bean.range
submitData["goods"] = bean.goods
submitData["goodsCn"] = bean.goodsCn
submitData["cargoType"] = bean.cargoType
submitData["by1"] = bean.by1
submitData["subCode"] = bean.subCode
submitData["cashWeight"] = bean.cashWeight
submitData["unNumber"] = bean.unNumber
submitData["businessType"] = bean.businessType
submitData["carId"] = bean.carId
launchLoadingCollect({
NetApply.api.modifyIntImpMaWb(submitData.toRequestBody())
}) {
onSuccess = {
showToast("修改成功")
viewModelScope.launch {
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
}
getTopActivity().finish()
}
}
}
/**
* 取消
*/
fun cancel() {
getTopActivity().finish()
}
}

View File

@@ -4,6 +4,7 @@ import android.app.Activity
import android.content.Intent
import androidx.lifecycle.MutableLiveData
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.activity.IntImpQueryEditActivity
import com.lukouguoji.gjj.dialog.IntImpQueryFilterDialogModel
import com.lukouguoji.gjj.holder.IntImpQueryViewHolder
import com.lukouguoji.gjj.activity.IntImpQueryDetailsActivity
@@ -152,7 +153,17 @@ class IntImpQueryViewModel : BasePageViewModel(), IOnItemClickListener {
override fun onItemClick(position: Int, type: Int) {
val list = pageModel.rv?.commonAdapter()?.items as? List<IntImpQueryBean> ?: return
val bean = list.getOrNull(position) ?: return
IntImpQueryDetailsActivity.start(getTopActivity(), bean.maWbId)
when (type) {
2000 -> {
// 侧滑菜单 - 修改操作
IntImpQueryEditActivity.start(getTopActivity(), bean.maWbId, bean.prefix, bean.no)
}
else -> {
// 默认点击 - 进入详情
IntImpQueryDetailsActivity.start(getTopActivity(), bean.prefix, bean.no)
}
}
}
fun initAgentList() {