feat: opt 出港查询-修改

This commit is contained in:
2026-01-07 19:05:21 +08:00
parent ff1c69f1dd
commit 774ba91aad
10 changed files with 260 additions and 35 deletions

View File

@@ -11,9 +11,11 @@ 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.launchLoadingCollect
import com.lukouguoji.module_base.ktx.launchCollect
import com.lukouguoji.module_base.ktx.showToast
import com.lukouguoji.module_base.ktx.toRequestBody
import com.lukouguoji.module_base.ktx.verifyNullOrEmpty
import dev.utils.app.info.KeyValue
import kotlinx.coroutines.launch
/**
@@ -24,6 +26,15 @@ class GjcQueryEditViewModel : BaseViewModel() {
// 数据Bean
val dataBean = MutableLiveData(GjcMaWb())
// 运单ID用于查询详情
var maWbId: Long = 0
// 包装类型下拉列表
val packageTypeList = MutableLiveData<List<KeyValue>>(emptyList())
// 运单类型下拉列表
val waybillTypeList = MutableLiveData<List<KeyValue>>(emptyList())
/**
* 初始化数据
*/
@@ -31,7 +42,17 @@ class GjcQueryEditViewModel : BaseViewModel() {
val jsonData = intent.getStringExtra(Constant.Key.DATA) ?: ""
if (jsonData.isNotEmpty()) {
try {
dataBean.value = Gson().fromJson(jsonData, GjcMaWb::class.java)
val tempBean = Gson().fromJson(jsonData, GjcMaWb::class.java)
maWbId = tempBean.maWbId ?: 0 // 保存ID用于查询详情
// 加载包装类型下拉列表
loadPackageTypeList()
// 加载运单类型下拉列表
loadWaybillTypeList()
// 调用详情接口获取完整数据
loadDetails()
} catch (e: Exception) {
showToast("数据解析失败")
getTopActivity().finish()
@@ -42,6 +63,165 @@ class GjcQueryEditViewModel : BaseViewModel() {
}
}
/**
* 加载包装类型下拉列表
*/
private fun loadPackageTypeList() {
launchCollect({ NetApply.api.getPackTypeList() }) {
onSuccess = { result ->
// 转换为 KeyValue 列表key 和 value 都使用 name忽略 code
val keyValueList = result.data?.mapNotNull { bean ->
bean.name?.let { name -> KeyValue(name, name) }
} ?: emptyList()
packageTypeList.value = keyValueList
}
}
}
/**
* 加载运单类型下拉列表
* 使用接口: POST /typeCode/awb?type=10 (10代表国际出港)
*/
private fun loadWaybillTypeList() {
launchCollect({ NetApply.api.getWaybillTypeList("10") }) {
onSuccess = { result ->
// 转换为 KeyValue 列表key 使用 name显示value 使用 code存储和提交
val keyValueList = result.data?.mapNotNull { bean ->
if (bean.name != null && bean.code != null) {
KeyValue(bean.name, bean.code)
} else null
} ?: emptyList()
waybillTypeList.value = keyValueList
}
}
}
/**
* 加载运单详情数据
*/
private fun loadDetails() {
if (maWbId == 0L) {
showToast("运单ID不存在")
getTopActivity().finish()
return
}
launchLoadingCollect({ NetApply.api.getGjcQueryDetails(maWbId) }) {
onSuccess = { result ->
val data = result.data ?: emptyMap()
// 1. 提取 maWb 对象(主要数据)
val maWb = data["maWb"] as? Map<String, Any> ?: emptyMap()
// 2. 提取 maWbM 对象(海关扩展数据)
val maWbM = data["maWbM"] as? Map<String, Any> ?: emptyMap()
// 3. 提取 warehouseList仓库列表用于计算入库件数和入库重量
val warehouseList = data["warehouseList"] as? List<Map<String, Any>> ?: emptyList()
// 4. 合并两个对象
val mergedData = mutableMapOf<String, Any>()
mergedData.putAll(maWb)
mergedData.putAll(maWbM)
// 5. 特殊字段处理
// 5.1 运单号: 组合 prefix + no
val prefix = maWb["prefix"] as? String ?: ""
val no = maWb["no"] as? String ?: ""
if (prefix.isNotEmpty() && no.isNotEmpty()) {
mergedData["wbNo"] = "$prefix$no"
}
// 5.2 代理人: 如果 agentName 为空,使用 agentCode
if (!mergedData.containsKey("agentName") || (mergedData["agentName"] as? String).isNullOrEmpty()) {
maWb["agentCode"]?.let { mergedData["agentName"] = it }
}
// 5.3 入库件数和入库重量: 从 warehouseList 计算总和
if (warehouseList.isNotEmpty()) {
var totalPc = 0L
var totalWeight = 0.0
warehouseList.forEach { warehouse ->
// 提取 pc件数并累加
val pc = warehouse["pc"]
when (pc) {
is Number -> totalPc += pc.toLong()
is String -> totalPc += pc.toLongOrNull() ?: 0L
}
// 提取 weight重量并累加
val weight = warehouse["weight"]
when (weight) {
is Number -> totalWeight += weight.toDouble()
is String -> totalWeight += weight.toDoubleOrNull() ?: 0.0
}
}
// 覆盖原有的 arrivePc 和 arriveWeight
mergedData["arrivePc"] = totalPc
mergedData["arriveWeight"] = totalWeight
}
// 6. 转换为 GjcMaWb 对象
val bean = Gson().fromJson(Gson().toJson(mergedData), GjcMaWb::class.java)
// 7. 匹配包装类型(支持 contains
matchPackageType(bean)
// 8. 匹配运单类型(支持 contains
matchWaybillType(bean)
dataBean.value = bean
}
}
}
/**
* 匹配包装类型
* 使用 contains 匹配,支持简写值和完整值
*/
private fun matchPackageType(bean: GjcMaWb) {
val currentPackageType = bean.packageType
if (currentPackageType.isNullOrEmpty()) return
val packageList = packageTypeList.value ?: emptyList()
if (packageList.isEmpty()) return
// 使用 contains 匹配(完整值和简写值都支持)
val match = packageList.find { keyValue ->
keyValue.value?.contains(currentPackageType) == true
}
if (match != null) {
// 使用匹配到的完整值
bean.packageType = match.value
}
}
/**
* 匹配运单类型
* 使用 code 进行匹配bean.awbType 存储的是 code
* 显示时使用 name但实际存储和提交的是 code
*/
private fun matchWaybillType(bean: GjcMaWb) {
val currentAwbTypeCode = bean.awbType
if (currentAwbTypeCode.isNullOrEmpty()) return
val waybillList = waybillTypeList.value ?: emptyList()
if (waybillList.isEmpty()) return
// 使用 code 进行精确匹配value 字段存储的是 code
val match = waybillList.find { keyValue ->
keyValue.value == currentAwbTypeCode
}
if (match != null) {
// 使用匹配到的 code 值(确保存储的是 code而不是 name
bean.awbType = match.value
}
}
/**
* 保存修改
*/
@@ -53,7 +233,7 @@ class GjcQueryEditViewModel : BaseViewModel() {
// 调用更新接口
launchLoadingCollect({
NetApply.api.updateGjcMaWb(Gson().toJson(bean).toRequestBody())
NetApply.api.updateGjcMaWb(bean.toRequestBody())
}) {
onSuccess = {
showToast("修改成功")

View File

@@ -16,7 +16,7 @@ import com.lukouguoji.module_base.ktx.toRequestBody
import com.lukouguoji.module_base.model.ScanModel
import dev.utils.app.info.KeyValue
import dev.utils.common.DateUtils
import com.lukouguoji.module_base.ktx.formatDate
import com.lukouguoji.module_base.ktx.formatDate
/**
* 国际出港查询ViewModel
@@ -103,8 +103,8 @@ class GjcQueryViewModel : BasePageViewModel() {
val listParams = mapOf(
"pageNum" to pageModel.page,
"pageSize" to pageModel.limit,
"fdateStart" to flightDateStart.value!!.ifEmpty { null },
"fdateEnd" to flightDateEnd.value!!.ifEmpty { null },
"beginDate" to flightDateStart.value!!.ifEmpty { null },
"endDate" to flightDateEnd.value!!.ifEmpty { null },
"agentCode" to agentId.value!!.ifEmpty { null },
"outState" to outStatus.value!!.ifEmpty { null },
"wbNo" to waybillNo.value!!.ifEmpty { null },

View File

@@ -19,7 +19,7 @@ import com.lukouguoji.module_base.ktx.showToast
import com.lukouguoji.module_base.ktx.toRequestBody
import com.lukouguoji.module_base.model.ScanModel
import dev.utils.common.DateUtils
import com.lukouguoji.module_base.ktx.formatDate
import com.lukouguoji.module_base.ktx.formatDate
import kotlinx.coroutines.launch
/**
@@ -41,6 +41,14 @@ class IntExpArriveViewModel : BasePageViewModel() {
// ========== 全选状态 ==========
val isAllChecked = MutableLiveData(false)
// ========== 全局展开状态 ==========
/**
* 全局展开状态
* - true: 全部展开
* - false: 全部收起
*/
val isAllExpanded = MutableLiveData(false)
init {
// 监听全选状态,自动更新所有列表项
isAllChecked.observeForever { checked ->
@@ -75,6 +83,28 @@ class IntExpArriveViewModel : BasePageViewModel() {
pageModel.rv?.commonAdapter()?.notifyDataSetChanged()
}
/**
* 切换全局展开/收起状态
*/
fun toggleAllExpand() {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjcMaWb> ?: return
// 切换全局状态
val shouldExpand = !isAllExpanded.value!!
isAllExpanded.value = shouldExpand
// 更新所有列表项的 showMore 状态
list.forEach { bean ->
// 只有当有子列表时才设置展开状态
if (!bean.haWbList.isNullOrEmpty()) {
bean.showMore.set(shouldExpand)
}
}
// 刷新列表UI
pageModel.rv?.commonAdapter()?.notifyDataSetChanged()
}
/**
* 扫码运单号
*/
@@ -208,7 +238,11 @@ class IntExpArriveViewModel : BasePageViewModel() {
// 获取列表 (带Loading)
launchLoadingCollect({ NetApply.api.getIntExpArriveList(listParams) }) {
onSuccess = { pageModel.handleListBean(it) }
onSuccess = {
pageModel.handleListBean(it)
// 数据加载完成后,重置全局展开状态为收起
isAllExpanded.value = false
}
}
// 获取统计信息 (后台请求)

View File

@@ -90,7 +90,7 @@
title='@{"运单件数"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@{String.valueOf(viewModel.dataBean.pc)}' />
value='@{viewModel.dataBean.pc != null ? String.valueOf(viewModel.dataBean.pc) : ``}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
@@ -100,7 +100,7 @@
title='@{"运单重量"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@{String.valueOf(viewModel.dataBean.weight)}' />
value='@{viewModel.dataBean.weight != null ? String.valueOf(viewModel.dataBean.weight) : ``}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
@@ -128,7 +128,7 @@
title='@{"入库件数"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@{String.valueOf(viewModel.dataBean.arrivePc)}' />
value='@{viewModel.dataBean.arrivePc != null ? String.valueOf(viewModel.dataBean.arrivePc) : ``}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
@@ -138,7 +138,7 @@
title='@{"入库重量"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@{String.valueOf(viewModel.dataBean.arriveWeight)}' />
value='@{viewModel.dataBean.arriveWeight != null ? String.valueOf(viewModel.dataBean.arriveWeight) : ``}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
@@ -148,7 +148,7 @@
title='@{"计费重量"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@{String.valueOf(viewModel.dataBean.weight)}' />
value='@{viewModel.dataBean.weight != null ? String.valueOf(viewModel.dataBean.weight) : ``}' />
</LinearLayout>
@@ -183,10 +183,11 @@
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{true}"
hint='@{"请输入包装类型"}'
hint='@{"请选择包装类型"}'
list="@{viewModel.packageTypeList}"
title='@{"包装类型"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
type="@{DataLayoutType.SPINNER}"
value='@={viewModel.dataBean.packageType}' />
</LinearLayout>
@@ -241,27 +242,17 @@
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{true}"
hint='@{"请输入运单类型"}'
hint='@{"请选择运单类型"}'
list="@{viewModel.waybillTypeList}"
title='@{"运单类型"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
type="@{DataLayoutType.SPINNER}"
value='@={viewModel.dataBean.awbType}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{true}"
hint='@{"请输入库位"}'
title='@{"库位"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.dataBean.customsLib}' />
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
android:layout_weight="2" />
</LinearLayout>

View File

@@ -7,6 +7,8 @@
<import type="com.lukouguoji.module_base.ui.weight.search.layout.SearchLayoutType" />
<import type="com.lukouguoji.module_base.R" />
<variable
name="viewModel"
type="com.lukouguoji.gjc.viewModel.IntExpArriveViewModel" />
@@ -86,6 +88,17 @@
android:padding="2dp"
android:src="@drawable/img_search" />
<!-- 全局展开/收起按钮 -->
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginStart="8dp"
android:onClick="@{()-> viewModel.toggleAllExpand()}"
android:padding="2dp"
android:scaleType="fitCenter"
loadImage="@{viewModel.isAllExpanded ? R.mipmap.img_up : R.mipmap.img_down}"
android:contentDescription="展开/收起全部子列表" />
</LinearLayout>
</LinearLayout>

View File

@@ -93,13 +93,13 @@
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:layout_weight="0.7"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
completeSpace="@{4}"
completeSpace="@{3}"
android:text="重量:" />
<TextView
@@ -120,7 +120,7 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
completeSpace="@{4}"
completeSpace="@{5}"
android:text="代理人:" />
<TextView
@@ -206,13 +206,13 @@
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:layout_weight="0.7"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
completeSpace="@{4}"
completeSpace="@{3}"
android:text="特码:" />
<TextView

View File

@@ -339,7 +339,8 @@
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:padding="5dp"
android:src="@mipmap/img_down" />
android:src="@mipmap/img_down"
visible="@{bean.haWbList != null &amp;&amp; !bean.haWbList.empty}" />
</LinearLayout>