feat: 国际出港 出港仓库 仓位修改
This commit is contained in:
@@ -274,6 +274,7 @@ data class GjcStorageUse(
|
||||
var prefix: String? = null, // 运单前缀
|
||||
var no: String? = null, // 运单号
|
||||
var location: String? = null, // 库位号
|
||||
var locationId: Long? = null, // 库位id
|
||||
var storageCode: String? = null, // 库位号(兼容字段)
|
||||
var uld: String? = null, // 板箱号
|
||||
var inDate: String? = null, // 入库时间
|
||||
@@ -281,7 +282,8 @@ data class GjcStorageUse(
|
||||
var inId: String? = null, // 入库人(兼容字段)
|
||||
var outDate: String? = null, // 出库时间
|
||||
var outOpId: String? = null, // 出库人
|
||||
var outId: String? = null // 出库人(兼容字段)
|
||||
var outId: String? = null, // 出库人(兼容字段)
|
||||
var cargoStatus: String? = null // 货物状态
|
||||
) {
|
||||
// ==================== UI扩展字段 ====================
|
||||
@Transient
|
||||
|
||||
@@ -818,6 +818,13 @@ interface Api {
|
||||
@POST("IntExpStorageUse/updateClear")
|
||||
suspend fun clearIntExpStorage(@Body data: RequestBody): BaseResultBean<Boolean>
|
||||
|
||||
/**
|
||||
* 国际出港库位操作-修改库位
|
||||
* 接口路径: /IntExpStorageUse/modifyStorage
|
||||
*/
|
||||
@POST("IntExpStorageUse/modifyStorage")
|
||||
suspend fun modifyIntExpStorage(@Body data: RequestBody): BaseResultBean<Boolean>
|
||||
|
||||
/**
|
||||
* 国际出港仓库-分页查询
|
||||
* 接口路径: /IntExpStorageUse/pageQuery
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -228,7 +228,7 @@
|
||||
<!-- 修改库位按钮 -->
|
||||
<TextView
|
||||
style="@style/tv_bottom_btn"
|
||||
android:onClick="@{()-> viewModel.modifyStorage()}"
|
||||
android:onClick="@{()-> activity.showModifyStorageDialog()}"
|
||||
android:text="修改库位" />
|
||||
|
||||
<!-- 出库按钮 -->
|
||||
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user