feat: 国际出港 出港仓库 仓位修改

This commit is contained in:
2026-01-14 18:39:15 +08:00
parent 76183823b0
commit 0a506617c7
9 changed files with 295 additions and 35 deletions

View File

@@ -7,6 +7,7 @@ import com.alibaba.android.arouter.facade.annotation.Route
import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.databinding.ActivityIntExpStorageUseBinding
import com.lukouguoji.gjc.dialog.IntExpMoveClearDialogModel
import com.lukouguoji.gjc.dialog.IntExpModifyStorageDialogModel
import com.lukouguoji.gjc.viewModel.IntExpStorageUseViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.common.Constant
@@ -54,11 +55,25 @@ class IntExpStorageUseActivity :
*/
fun showClearDialog() {
val list = viewModel.pageModel.rv?.commonAdapter()?.items as? List<*> ?: return
val selectedItems = list.filterIsInstance<com.lukouguoji.module_base.bean.GjcMaWb>()
.filter { it.isSelected }
val allItems = list.filterIsInstance<com.lukouguoji.module_base.bean.GjcMaWb>()
if (selectedItems.isEmpty()) {
showToast("请至少选择一条运单")
// 构建清仓数据:保留主列表结构,但只包含选中的子列表项
val maWbListForClear = allItems.mapNotNull { maWb ->
// 过滤出选中的子列表项
val selectedStorageList = maWb.storageUseList?.filter { it.isSelected } ?: emptyList()
// 只添加有选中子列表项的主列表项
if (selectedStorageList.isNotEmpty()) {
// 创建主列表项的副本,只包含选中的子列表
maWb.copy(storageUseList = selectedStorageList)
} else {
// null
maWb
}
}
if (maWbListForClear.isEmpty()) {
showToast("请至少选择一个库位")
return
}
@@ -66,7 +81,42 @@ class IntExpStorageUseActivity :
IntExpMoveClearDialogModel { dialog ->
// 用户点击保存后,执行清仓操作
val clearNormal = dialog.clearNormal.value ?: ""
viewModel.performClear(clearNormal)
viewModel.performClear(clearNormal, maWbListForClear)
}.show(this)
}
/**
* 显示修改库位对话框
*/
fun showModifyStorageDialog() {
val list = viewModel.pageModel.rv?.commonAdapter()?.items as? List<*> ?: return
val allItems = list.filterIsInstance<com.lukouguoji.module_base.bean.GjcMaWb>()
// 收集所有选中的子列表项(库位)
val selectedStorageUseList = mutableListOf<com.lukouguoji.module_base.bean.GjcStorageUse>()
allItems.forEach { maWb ->
maWb.storageUseList?.filter { it.isSelected }?.let { selectedStorageUseList.addAll(it) }
}
// 校验:必须且只能选中一个库位
when {
selectedStorageUseList.isEmpty() -> {
showToast("请选择要修改的库位")
return
}
selectedStorageUseList.size > 1 -> {
showToast("只能选择一个库位进行修改")
return
}
}
val selectedStorage = selectedStorageUseList[0]
// 显示修改库位对话框
IntExpModifyStorageDialogModel { dialog ->
// 用户点击保存后,执行修改库位操作
val newLocation = dialog.location.value ?: ""
viewModel.performModifyStorage(newLocation, selectedStorage)
}.show(this)
}

View File

@@ -0,0 +1,38 @@
package com.lukouguoji.gjc.dialog
import android.content.Context
import androidx.lifecycle.MutableLiveData
import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.databinding.DialogIntExpModifyStorageBinding
import com.lukouguoji.module_base.base.BaseDialogModel
import com.lukouguoji.module_base.ktx.verifyNullOrEmpty
/**
* 国际出港 - 修改库位对话框
*/
class IntExpModifyStorageDialogModel(
private val callback: (IntExpModifyStorageDialogModel) -> Unit
) : BaseDialogModel<DialogIntExpModifyStorageBinding>(DIALOG_TYPE_CENTER) {
// 库位号
val location = MutableLiveData("")
override fun layoutId(): Int {
return R.layout.dialog_int_exp_modify_storage
}
override fun onDialogCreated(context: Context) {
binding.model = this
}
/**
* 保存按钮点击
*/
fun onSaveClick() {
if (location.value.verifyNullOrEmpty("请输入库位号")) {
return
}
dismiss()
callback(this)
}
}

View File

@@ -1,8 +1,10 @@
package com.lukouguoji.gjc.holder
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import com.lukouguoji.gjc.databinding.ItemIntExpStorageUseSubBinding
import com.lukouguoji.module_base.base.BaseViewHolder
import com.lukouguoji.module_base.bean.GjcMaWb
import com.lukouguoji.module_base.bean.GjcStorageUse
/**
@@ -17,10 +19,33 @@ class IntExpStorageUseSubViewHolder(view: View) :
binding.position = position
binding.executePendingBindings()
// 单选框点击切换选择状态
// 单选框点击切换选择状态(反向联动主列表)
binding.ivCheckbox.setOnClickListener {
bean.checked.set(!bean.checked.get())
// 切换子列表项的选择状态
val newCheckedState = !bean.checked.get()
bean.checked.set(newCheckedState)
binding.executePendingBindings()
// 反向联动主列表项
updateParentCheckState()
}
}
/**
* 更新父列表项的选择状态
* 规则:
* - 如果有任何一个子列表项被勾选,则主列表项也应该被勾选
* - 如果所有子列表项都未勾选,则主列表项也应该取消勾选
*/
private fun updateParentCheckState() {
// 从RecyclerView的tag获取父Bean引用
val recyclerView = itemView.parent as? RecyclerView ?: return
val parentBean = recyclerView.tag as? GjcMaWb ?: return
// 检查是否有任何一个子列表项被勾选
val hasAnyChecked = parentBean.storageUseList?.any { it.checked.get() } ?: false
// 更新父列表项的选择状态
parentBean.checked.set(hasAnyChecked)
}
}

View File

@@ -20,10 +20,20 @@ class IntExpStorageUseViewHolder(view: View) :
binding.position = position
binding.executePendingBindings()
// 图标点击切换选择状态
// 图标点击切换选择状态(联动子列表)
binding.ivIcon.setOnClickListener {
bean.checked.set(!bean.checked.get())
// 切换主列表项的选择状态
val newCheckedState = !bean.checked.get()
bean.checked.set(newCheckedState)
// 联动勾选/取消所有子列表项
bean.storageUseList?.forEach { storageUse ->
storageUse.checked.set(newCheckedState)
}
// 刷新UI
binding.executePendingBindings()
binding.rvSub.adapter?.notifyDataSetChanged()
}
// 展开按钮点击事件
@@ -38,7 +48,10 @@ class IntExpStorageUseViewHolder(view: View) :
R.layout.item_int_exp_storage_use_sub
)
// 刷新库位明细数据
binding.rvSub.refresh(bean.storageUseList ?: emptyList())
// 刷新库位明细数据传递父Bean引用
val storageUseList = bean.storageUseList ?: emptyList()
// 为每个子列表项设置父Bean引用通过tag传递
binding.rvSub.tag = bean
binding.rvSub.refresh(storageUseList)
}
}

View File

@@ -80,13 +80,22 @@ class IntExpStorageUseViewModel : BasePageViewModel() {
}
/**
* 全选按钮点击
* 全选按钮点击(联动勾选所有子列表项)
*/
fun checkAllClick() {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjcMaWb> ?: return
val shouldCheckAll = !isAllChecked.value!!
list.forEach { it.checked.set(shouldCheckAll) }
// 联动勾选/取消主列表和子列表
list.forEach { maWb ->
maWb.checked.set(shouldCheckAll)
// 同时联动勾选/取消所有子列表项
maWb.storageUseList?.forEach { storageUse ->
storageUse.checked.set(shouldCheckAll)
}
}
isAllChecked.value = shouldCheckAll
pageModel.rv?.commonAdapter()?.notifyDataSetChanged()
@@ -131,20 +140,18 @@ class IntExpStorageUseViewModel : BasePageViewModel() {
/**
* 执行清仓操作
* @param clearNormal 清仓正常("0"或"1"
* @param maWbListForClear 包含选中子列表项的主列表数据
*/
fun performClear(clearNormal: String) {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjcMaWb> ?: return
val selectedItems = list.filter { it.isSelected }
if (selectedItems.isEmpty()) {
showToast("请至少选择一条运单")
fun performClear(clearNormal: String, maWbListForClear: List<GjcMaWb>) {
if (maWbListForClear.isEmpty()) {
showToast("请至少选择一个库位")
return
}
// 构建请求参数
// 构建请求参数:完整的主子列表结构
val params = mapOf(
"clearNormal" to clearNormal,
"maWbList" to selectedItems
"maWbList" to maWbListForClear
).toRequestBody()
launchLoadingCollect({ NetApply.api.clearIntExpStorage(params) }) {
@@ -165,16 +172,38 @@ class IntExpStorageUseViewModel : BasePageViewModel() {
* 修改库位
*/
fun modifyStorage() {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjcMaWb> ?: return
val selectedItems = list.filter { it.isSelected }
// 由Activity显示对话框
}
if (selectedItems.isEmpty()) {
showToast("请选择要修改库位的运单")
/**
* 执行修改库位操作
* @param newLocation 新的库位号
* @param storageUse 选中的单个库位使用对象
*/
fun performModifyStorage(newLocation: String, storageUse: com.lukouguoji.module_base.bean.GjcStorageUse) {
if (newLocation.isEmpty()) {
showToast("请输入新的库位号")
return
}
// TODO: 实现修改库位接口调用或弹出对话框
showToast("修改库位功能待实现")
// 创建更新后的库位对象(覆盖 location 字段)
val updatedStorage = storageUse.copy(location = newLocation)
// 直接使用更新后的对象构建请求参数
val params = updatedStorage.toRequestBody()
launchLoadingCollect({ NetApply.api.modifyIntExpStorage(params) }) {
onSuccess = {
showToast("修改库位成功")
viewModelScope.launch {
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
}
refresh() // 刷新列表
}
onFailed = { _, msg ->
showToast(msg.noNull("修改库位失败"))
}
}
}
/**
@@ -182,10 +211,15 @@ class IntExpStorageUseViewModel : BasePageViewModel() {
*/
fun outStorage() {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjcMaWb> ?: return
val selectedItems = list.filter { it.isSelected }
if (selectedItems.isEmpty()) {
showToast("请选择要出库的运单")
// 收集所有选中的子列表项(库位)
val selectedStorageUseList = mutableListOf<com.lukouguoji.module_base.bean.GjcStorageUse>()
list.forEach { maWb ->
maWb.storageUseList?.filter { it.isSelected }?.let { selectedStorageUseList.addAll(it) }
}
if (selectedStorageUseList.isEmpty()) {
showToast("请选择要出库的库位")
return
}
@@ -198,10 +232,15 @@ class IntExpStorageUseViewModel : BasePageViewModel() {
*/
fun inStorage() {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjcMaWb> ?: return
val selectedItems = list.filter { it.isSelected }
if (selectedItems.isEmpty()) {
showToast("请选择要入库的运单")
// 收集所有选中的子列表项(库位)
val selectedStorageUseList = mutableListOf<com.lukouguoji.module_base.bean.GjcStorageUse>()
list.forEach { maWb ->
maWb.storageUseList?.filter { it.isSelected }?.let { selectedStorageUseList.addAll(it) }
}
if (selectedStorageUseList.isEmpty()) {
showToast("请选择要入库的库位")
return
}

View File

@@ -228,7 +228,7 @@
<!-- 修改库位按钮 -->
<TextView
style="@style/tv_bottom_btn"
android:onClick="@{()-> viewModel.modifyStorage()}"
android:onClick="@{()-> activity.showModifyStorageDialog()}"
android:text="修改库位" />
<!-- 出库按钮 -->

View File

@@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="com.lukouguoji.module_base.ui.weight.search.layout.SearchLayoutType"/>
<variable
name="model"
type="com.lukouguoji.gjc.dialog.IntExpModifyStorageDialogModel" />
</data>
<LinearLayout
android:layout_width="600dp"
android:layout_height="wrap_content"
android:background="@drawable/bg_dialog_f2_radius_10"
android:gravity="center_horizontal"
android:orientation="vertical">
<!-- 标题栏 -->
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/bg_primary_radius_top_10"
android:gravity="center"
android:text="库位信息"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold" />
<!-- 表单内容 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="30dp"
android:layout_marginTop="30dp"
android:orientation="vertical">
<!-- 库位号 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
completeSpace="@{5}"
android:text="库位号:"
android:textColor="@color/text_normal"
android:textSize="16sp" />
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
type="@{SearchLayoutType.INPUT}"
hint='@{"请输入库位号"}'
value="@={model.location}" />
</LinearLayout>
</LinearLayout>
<!-- 底部按钮 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:layout_marginBottom="20dp">
<TextView
style="@style/tv_bottom_btn"
android:onClick="@{()->model.dismiss()}"
android:text="取消" />
<TextView
style="@style/tv_bottom_btn"
android:onClick="@{()->model.onSaveClick()}"
android:text="保存" />
</LinearLayout>
</LinearLayout>
</layout>