diff --git a/app/src/main/java/com/lukouguoji/aerologic/ui/fragment/HomeFragment.kt b/app/src/main/java/com/lukouguoji/aerologic/ui/fragment/HomeFragment.kt index 90ca0fb..7cf65b9 100644 --- a/app/src/main/java/com/lukouguoji/aerologic/ui/fragment/HomeFragment.kt +++ b/app/src/main/java/com/lukouguoji/aerologic/ui/fragment/HomeFragment.kt @@ -753,7 +753,7 @@ class HomeFragment : Fragment() { RightMenu( Constant.AuthName.GjcIntExpStorageUse, R.mipmap.gjc_cang_ku_icon, - "仓库" + "出港仓库" ) ) diff --git a/module_base/src/main/java/com/lukouguoji/module_base/bean/GjcMaWb.kt b/module_base/src/main/java/com/lukouguoji/module_base/bean/GjcMaWb.kt index a9d05e1..a5b605d 100644 --- a/module_base/src/main/java/com/lukouguoji/module_base/bean/GjcMaWb.kt +++ b/module_base/src/main/java/com/lukouguoji/module_base/bean/GjcMaWb.kt @@ -1,7 +1,9 @@ package com.lukouguoji.module_base.bean import androidx.databinding.ObservableBoolean +import java.text.SimpleDateFormat import java.util.Date +import java.util.Locale /** * 国际出港主单数据模型 @@ -78,6 +80,7 @@ data class GjcMaWb( var declareStatus: String? = null, // 申报状态 var reviewStatus: String? = null, // 审核状态(0:未审核;1:通过;2:退回) var tranFlag: String? = null, // 转运标志 + var clearNormal: String? = null, // 清仓正常(0:否,1:是) // ==================== 操作信息 ==================== var opDate: String? = null, // 操作时间(入库时间) @@ -106,7 +109,6 @@ data class GjcMaWb( // ==================== 关联列表(非数据库字段,用于展示) ==================== var haWbList: List? = null, // 分单列表 - @Transient var storageUseList: List? = null, // 库位使用列表 @Transient var attachList: List? = null // 附件列表 @@ -145,6 +147,34 @@ data class GjcMaWb( "1" -> "提前运抵" else -> arriveFlag ?: "" } + + /** + * 航班信息(格式化后) + * 格式: yyyyMMdd/航班号 + * 示例: 20260108/MU2025 + */ + val flightInfo: String + get() { + val dateFormat = SimpleDateFormat("yyyyMMdd", Locale.getDefault()) + val formattedDate = fdate?.let { dateFormat.format(it) } ?: "" + val flightNo = fno ?: "" + return if (formattedDate.isNotEmpty() && flightNo.isNotEmpty()) { + "$formattedDate/$flightNo" + } else { + flight ?: "" // 如果无法格式化,回退到原始flight字段 + } + } + + /** + * 清仓正常状态中文 + * 0-否,1-是 + */ + val clearNormalText: String + get() = when (clearNormal) { + "0" -> "否" + "1" -> "是" + else -> clearNormal ?: "" + } } /** @@ -244,14 +274,16 @@ 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: Date? = null, // 入库时间 + var inDate: String? = null, // 入库时间 var inOpId: String? = null, // 入库人 var inId: String? = null, // 入库人(兼容字段) - var outDate: Date? = null, // 出库时间 + var outDate: String? = null, // 出库时间 var outOpId: String? = null, // 出库人 - var outId: String? = null // 出库人(兼容字段) + var outId: String? = null, // 出库人(兼容字段) + var cargoStatus: String? = null // 货物状态 ) { // ==================== UI扩展字段 ==================== @Transient diff --git a/module_base/src/main/java/com/lukouguoji/module_base/http/net/Api.kt b/module_base/src/main/java/com/lukouguoji/module_base/http/net/Api.kt index 27bbef5..80f8b5d 100644 --- a/module_base/src/main/java/com/lukouguoji/module_base/http/net/Api.kt +++ b/module_base/src/main/java/com/lukouguoji/module_base/http/net/Api.kt @@ -811,6 +811,27 @@ interface Api { @POST("IntExpMove/move") suspend fun submitIntExpMove(@Body data: RequestBody): BaseResultBean + /** + * 国际出港库位操作-清仓 + * 接口路径: /IntExpStorageUse/updateClear + */ + @POST("IntExpStorageUse/updateClear") + suspend fun clearIntExpStorage(@Body data: RequestBody): BaseResultBean + + /** + * 国际出港库位操作-修改库位 + * 接口路径: /IntExpStorageUse/modifyStorage + */ + @POST("IntExpStorageUse/modifyStorage") + suspend fun modifyIntExpStorage(@Body data: RequestBody): BaseResultBean + + /** + * 国际出港库位操作-出库 + * 接口路径: /IntExpStorageUse/outStorage + */ + @POST("IntExpStorageUse/outStorage") + suspend fun outIntExpStorage(@Body data: RequestBody): BaseResultBean + /** * 国际出港仓库-分页查询 * 接口路径: /IntExpStorageUse/pageQuery diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpStorageUseActivity.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpStorageUseActivity.kt index f876f58..01dc11f 100644 --- a/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpStorageUseActivity.kt +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpStorageUseActivity.kt @@ -3,15 +3,20 @@ package com.lukouguoji.gjc.activity import android.app.Activity import android.content.Intent import android.os.Bundle +import androidx.appcompat.app.AlertDialog 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 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.ktx.commonAdapter +import com.lukouguoji.module_base.ktx.showToast import com.lukouguoji.module_base.router.ARouterConstants /** @@ -27,6 +32,7 @@ class IntExpStorageUseActivity : override fun initOnCreate(savedInstanceState: Bundle?) { setBackArrow("国际出港仓库") binding.viewModel = viewModel + binding.activity = this // 观察全选状态,更新图标透明度 viewModel.isAllChecked.observe(this) { isAllChecked -> @@ -45,6 +51,106 @@ class IntExpStorageUseActivity : viewModel.refresh() } + /** + * 显示清仓操作对话框 + */ + fun showClearDialog() { + val list = viewModel.pageModel.rv?.commonAdapter()?.items as? List<*> ?: return + val allItems = list.filterIsInstance() + + // 构建清仓数据:保留主列表结构,但只包含选中的子列表项 + val maWbListForClear = allItems.mapNotNull { maWb -> + // 过滤出选中的子列表项 + val selectedStorageList = maWb.storageUseList?.filter { it.isSelected } ?: emptyList() + + // 只添加有选中子列表项的主列表项 + if (selectedStorageList.isNotEmpty() || maWb.isSelected) { + // 创建主列表项的副本,只包含选中的子列表 + maWb.copy(storageUseList = selectedStorageList) + } else { + null + } + } + + if (maWbListForClear.isEmpty()) { + showToast("请至少选择一个库位") + return + } + + // 显示清仓对话框 + IntExpMoveClearDialogModel { dialog -> + // 用户点击保存后,执行清仓操作 + val clearNormal = dialog.clearNormal.value ?: "" + viewModel.performClear(clearNormal, maWbListForClear) + }.show(this) + } + + /** + * 显示修改库位对话框 + */ + fun showModifyStorageDialog() { + val list = viewModel.pageModel.rv?.commonAdapter()?.items as? List<*> ?: return + val allItems = list.filterIsInstance() + + // 收集所有选中的子列表项(库位) + val selectedStorageUseList = mutableListOf() + 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) + } + + /** + * 显示出库二次确认对话框 + */ + fun showOutStorageDialog() { + val list = viewModel.pageModel.rv?.commonAdapter()?.items as? List<*> ?: return + val allItems = list.filterIsInstance() + + // 收集所有选中的子列表项(库位) + val selectedStorageUseList = mutableListOf() + allItems.forEach { maWb -> + maWb.storageUseList?.filter { it.isSelected }?.let { selectedStorageUseList.addAll(it) } + } + + // 校验:必须至少选中一个库位 + if (selectedStorageUseList.isEmpty()) { + showToast("请选择要出库的库位") + return + } + + // 显示二次确认对话框 + AlertDialog.Builder(this) + .setTitle("出库确认") + .setMessage("确定要将选中的 ${selectedStorageUseList.size} 个库位执行出库操作吗?") + .setPositiveButton("确定") { _, _ -> + // 用户确认后,执行出库操作 + viewModel.performOutStorage(selectedStorageUseList) + } + .setNegativeButton("取消", null) + .show() + } + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == Constant.RequestCode.WAYBILL && resultCode == Activity.RESULT_OK) { diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/dialog/IntExpModifyStorageDialogModel.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/dialog/IntExpModifyStorageDialogModel.kt new file mode 100644 index 0000000..1520172 --- /dev/null +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/dialog/IntExpModifyStorageDialogModel.kt @@ -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(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) + } +} diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/dialog/IntExpMoveClearDialogModel.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/dialog/IntExpMoveClearDialogModel.kt new file mode 100644 index 0000000..8af9afa --- /dev/null +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/dialog/IntExpMoveClearDialogModel.kt @@ -0,0 +1,47 @@ +package com.lukouguoji.gjc.dialog + +import android.content.Context +import androidx.lifecycle.MutableLiveData +import com.lukouguoji.gjc.R +import com.lukouguoji.gjc.databinding.DialogIntExpMoveClearBinding +import com.lukouguoji.module_base.base.BaseDialogModel +import com.lukouguoji.module_base.ktx.verifyNullOrEmpty +import dev.utils.app.info.KeyValue + +/** + * 国际出港移库 - 清仓操作对话框 + */ +class IntExpMoveClearDialogModel( + private val callback: (IntExpMoveClearDialogModel) -> Unit +) : BaseDialogModel(DIALOG_TYPE_CENTER) { + + // 清仓正常(存储的是 code:"0" 或 "1") + val clearNormal = MutableLiveData("") + + // 清仓正常选项列表 + val clearNormalList = MutableLiveData>().apply { + value = listOf( + KeyValue("是", "1"), + KeyValue("否", "0") + ) + } + + override fun layoutId(): Int { + return R.layout.dialog_int_exp_move_clear + } + + override fun onDialogCreated(context: Context) { + binding.model = this + } + + /** + * 保存按钮点击 + */ + fun onSaveClick() { + if (clearNormal.value.verifyNullOrEmpty("请选择清仓正常")) { + return + } + dismiss() + callback(this) + } +} diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpStorageUseSubViewHolder.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpStorageUseSubViewHolder.kt index 491e1a0..97ceef6 100644 --- a/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpStorageUseSubViewHolder.kt +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpStorageUseSubViewHolder.kt @@ -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(newCheckedState) } } + + /** + * 更新父列表项的选择状态 + * 规则: + * - 如果子项被勾选(newCheckedState = true),则自动勾选父项 + * - 如果子项被取消勾选(newCheckedState = false),则不改变父项状态 + */ + private fun updateParentCheckState(newCheckedState: Boolean) { + // 从RecyclerView的tag获取父Bean引用 + val recyclerView = itemView.parent as? RecyclerView ?: return + val parentBean = recyclerView.tag as? GjcMaWb ?: return + + // 只有当子项被勾选时,才联动勾选父项 + if (newCheckedState) { + parentBean.checked.set(true) + } + // 当子项被取消勾选时,不影响父项状态 + } } diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpStorageUseViewHolder.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpStorageUseViewHolder.kt index df097a0..afa0696 100644 --- a/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpStorageUseViewHolder.kt +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpStorageUseViewHolder.kt @@ -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) } } diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpTallyViewHolder.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpTallyViewHolder.kt index 60f7324..661c87f 100644 --- a/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpTallyViewHolder.kt +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpTallyViewHolder.kt @@ -20,10 +20,20 @@ class IntExpTallyViewHolder(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.haWbList?.forEach { haWb -> + haWb.checked.set(newCheckedState) + } + + // 刷新UI binding.executePendingBindings() + binding.rvSub.adapter?.notifyDataSetChanged() } // ========== 新增:展开按钮点击事件 ========== diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpMoveViewModel.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpMoveViewModel.kt index ccdf2bf..441616e 100644 --- a/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpMoveViewModel.kt +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpMoveViewModel.kt @@ -31,18 +31,17 @@ class IntExpMoveViewModel : BasePageViewModel(), IOnItemClickListener { // ========== 运单类型下拉数据 ========== val awbTypeList = MutableLiveData>().apply { value = listOf( - KeyValue("", "全部"), - KeyValue("IOCO", "国际出港(经国内航班出境)"), - KeyValue("IOSO", "国际出港(国际航班出境)") + KeyValue("全部", ""), + KeyValue("转国内出港", "IOCO") ) } // ========== 移库状态下拉数据 ========== val moveStateList = MutableLiveData>().apply { value = listOf( - KeyValue("", "全部"), - KeyValue("0", "未移交"), - KeyValue("1", "已移交") + KeyValue("全部", ""), + KeyValue("未移库", "0"), + KeyValue("已移库", "1") ) } @@ -146,14 +145,14 @@ class IntExpMoveViewModel : BasePageViewModel(), IOnItemClickListener { * 获取列表数据 */ override fun getData() { - // 构建筛选参数 - val filterParams = mapOf( - "awbType" to awbType.value.noNull(), - "by1" to by1.value.noNull(), - "dest1" to dest1.value.noNull(), - "moveState" to moveState.value.noNull(), - "wbNo" to waybillNo.value.noNull() - ) + // 构建筛选参数(只传递非空值) + val filterParams = mutableMapOf() + + awbType.value?.takeIf { it.isNotEmpty() }?.let { filterParams["awbType"] = it } + by1.value?.takeIf { it.isNotEmpty() }?.let { filterParams["by1"] = it } + dest1.value?.takeIf { it.isNotEmpty() }?.let { filterParams["dest1"] = it } + moveState.value?.takeIf { it.isNotEmpty() }?.let { filterParams["moveState"] = it } + waybillNo.value?.takeIf { it.isNotEmpty() }?.let { filterParams["wbNo"] = it } // 列表参数(含分页) val listParams = (filterParams + mapOf( diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpStorageUseViewModel.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpStorageUseViewModel.kt index f1d77fb..9341b4a 100644 --- a/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpStorageUseViewModel.kt +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpStorageUseViewModel.kt @@ -11,13 +11,16 @@ 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.commonAdapter +import com.lukouguoji.module_base.ktx.formatDate 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.model.ScanModel import dev.utils.app.info.KeyValue import kotlinx.coroutines.launch +import java.util.Date /** * 国际出港-仓库 ViewModel @@ -25,12 +28,12 @@ import kotlinx.coroutines.launch class IntExpStorageUseViewModel : BasePageViewModel() { // ========== 筛选条件 ========== - val flightDate = MutableLiveData("") // 航班日期 + val flightDate = MutableLiveData(Date().formatDate()) // 航班日期,默认今天 val flightNo = MutableLiveData("") // 航班号 val clearResult = MutableLiveData("") // 清仓综合结果 val clearResultList = MutableLiveData>() // 清仓综合结果列表 val wbNo = MutableLiveData("") // 运单号 - val storageCode = MutableLiveData("") // 库位号 + val location = MutableLiveData("") // 库位号 // ========== 统计信息 ========== val totalWbNumber = MutableLiveData("0") // 总票数 @@ -40,6 +43,14 @@ class IntExpStorageUseViewModel : BasePageViewModel() { // ========== 全选状态 ========== val isAllChecked = MutableLiveData(false) + // ========== 全局展开状态 ========== + /** + * 全局展开状态 + * - true: 全部展开 + * - false: 全部收起 + */ + val isAllExpanded = MutableLiveData(false) + init { // 初始化清仓综合结果列表(根据实际需求配置) clearResultList.value = listOf( @@ -50,7 +61,8 @@ class IntExpStorageUseViewModel : BasePageViewModel() { // 监听全选状态,自动更新所有列表项 isAllChecked.observeForever { checked -> - val list = pageModel.rv?.commonAdapter()?.items as? List ?: return@observeForever + val list = + pageModel.rv?.commonAdapter()?.items as? List ?: return@observeForever list.forEach { it.checked.set(checked) } pageModel.rv?.commonAdapter()?.notifyDataSetChanged() } @@ -68,18 +80,49 @@ class IntExpStorageUseViewModel : BasePageViewModel() { } /** - * 全选按钮点击 + * 全选按钮点击(联动勾选所有子列表项) */ fun checkAllClick() { val list = pageModel.rv?.commonAdapter()?.items as? List ?: 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() } + /** + * 切换全局展开/收起状态 + */ + fun toggleAllExpand() { + val list = pageModel.rv?.commonAdapter()?.items as? List ?: return + + // 切换全局状态 + val shouldExpand = !isAllExpanded.value!! + isAllExpanded.value = shouldExpand + + // 更新所有列表项的 showMore 状态 + list.forEach { bean -> + // 只有当有子列表时才设置展开状态 + if (!bean.storageUseList.isNullOrEmpty()) { + bean.showMore.set(shouldExpand) + } + } + + // 刷新列表UI + pageModel.rv?.commonAdapter()?.notifyDataSetChanged() + } + /** * 扫码运单号 */ @@ -88,51 +131,113 @@ class IntExpStorageUseViewModel : BasePageViewModel() { } /** - * 清仓操作 + * 清仓操作(在Activity中调用,会显示对话框) */ fun clearStorage() { - val list = pageModel.rv?.commonAdapter()?.items as? List ?: return - val selectedItems = list.filter { it.isSelected } + // 由Activity显示对话框 + } - if (selectedItems.isEmpty()) { - showToast("请选择要清仓的运单") + /** + * 执行清仓操作 + * @param clearNormal 清仓正常("0"或"1") + * @param maWbListForClear 包含选中子列表项的主列表数据 + */ + fun performClear(clearNormal: String, maWbListForClear: List) { + if (maWbListForClear.isEmpty()) { + showToast("请至少选择一个库位") return } - // TODO: 实现清仓接口调用 - showToast("清仓功能待实现") + // 构建请求参数:完整的主子列表结构 + val params = mapOf( + "clearNormal" to clearNormal, + "maWbList" to maWbListForClear + ).toRequestBody() + + launchLoadingCollect({ NetApply.api.clearIntExpStorage(params) }) { + onSuccess = { + showToast("清仓成功") + viewModelScope.launch { + FlowBus.with(ConstantEvent.EVENT_REFRESH).emit("refresh") + } + refresh() // 刷新列表 + } + onFailed = { _, msg -> + showToast(msg.noNull("清仓失败")) + } + } } /** * 修改库位 */ fun modifyStorage() { - val list = pageModel.rv?.commonAdapter()?.items as? List ?: return - val selectedItems = list.filter { it.isSelected } - - if (selectedItems.isEmpty()) { - showToast("请选择要修改库位的运单") - return - } - - // TODO: 实现修改库位接口调用或弹出对话框 - showToast("修改库位功能待实现") + // 由Activity显示对话框 } /** - * 出库操作 + * 执行修改库位操作 + * @param newLocation 新的库位号 + * @param storageUse 选中的单个库位使用对象 */ - fun outStorage() { - val list = pageModel.rv?.commonAdapter()?.items as? List ?: return - val selectedItems = list.filter { it.isSelected } - - if (selectedItems.isEmpty()) { - showToast("请选择要出库的运单") + 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(ConstantEvent.EVENT_REFRESH).emit("refresh") + } + refresh() // 刷新列表 + } + onFailed = { _, msg -> + showToast(msg.noNull("修改库位失败")) + } + } + } + + /** + * 出库操作(在Activity中调用,会显示二次确认对话框) + */ + fun outStorage() { + // 由Activity显示二次确认对话框 + } + + /** + * 执行出库操作 + * @param selectedStorageList 选中的子列表项(库位) + */ + fun performOutStorage(selectedStorageList: List) { + if (selectedStorageList.isEmpty()) { + showToast("请选择要出库的库位") + return + } + + // 将选中的子列表项转换为RequestBody + val params = selectedStorageList.toRequestBody() + + launchLoadingCollect({ NetApply.api.outIntExpStorage(params) }) { + onSuccess = { + showToast("出库成功") + viewModelScope.launch { + FlowBus.with(ConstantEvent.EVENT_REFRESH).emit("refresh") + } + refresh() // 刷新列表 + } + onFailed = { _, msg -> + showToast(msg.noNull("出库失败")) + } + } } /** @@ -140,10 +245,15 @@ class IntExpStorageUseViewModel : BasePageViewModel() { */ fun inStorage() { val list = pageModel.rv?.commonAdapter()?.items as? List ?: return - val selectedItems = list.filter { it.isSelected } - if (selectedItems.isEmpty()) { - showToast("请选择要入库的运单") + // 收集所有选中的子列表项(库位) + val selectedStorageUseList = mutableListOf() + list.forEach { maWb -> + maWb.storageUseList?.filter { it.isSelected }?.let { selectedStorageUseList.addAll(it) } + } + + if (selectedStorageUseList.isEmpty()) { + showToast("请选择要入库的库位") return } @@ -160,7 +270,7 @@ class IntExpStorageUseViewModel : BasePageViewModel() { "fdate" to flightDate.value?.ifEmpty { null }, "fno" to flightNo.value?.ifEmpty { null }, "wbNo" to wbNo.value?.ifEmpty { null }, - "storageCode" to storageCode.value?.ifEmpty { null } + "location" to location.value?.ifEmpty { null } ) // 列表参数 (含分页) @@ -178,6 +288,8 @@ class IntExpStorageUseViewModel : BasePageViewModel() { // 手动处理 PageInfo 数据 pageModel.handleDataList(result.list) pageModel.haveMore.postValue((result.pages) > pageModel.page) + // 数据加载完成后,重置全局展开状态为收起 + isAllExpanded.value = false } } diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpTallyViewModel.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpTallyViewModel.kt index 1d4af55..278852b 100644 --- a/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpTallyViewModel.kt +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpTallyViewModel.kt @@ -71,14 +71,23 @@ class IntExpTallyViewModel : BasePageViewModel() { } /** - * 全选按钮点击 (切换全选状态) + * 全选按钮点击 (切换全选状态,单向同步到子列表) */ fun checkAllClick() { val list = pageModel.rv?.commonAdapter()?.items as? List ?: return // 切换全选状态 val shouldCheckAll = !isAllChecked.value!! - list.forEach { it.checked.set(shouldCheckAll) } + + // 单向同步:主列表和子列表都设置为相同的选择状态 + list.forEach { maWb -> + maWb.checked.set(shouldCheckAll) + // 同步到所有子列表项 + maWb.haWbList?.forEach { haWb -> + haWb.checked.set(shouldCheckAll) + } + } + isAllChecked.value = shouldCheckAll pageModel.rv?.commonAdapter()?.notifyDataSetChanged() diff --git a/module_gjc/src/main/res/layout/activity_int_exp_storage_use.xml b/module_gjc/src/main/res/layout/activity_int_exp_storage_use.xml index b17b796..553ffbf 100644 --- a/module_gjc/src/main/res/layout/activity_int_exp_storage_use.xml +++ b/module_gjc/src/main/res/layout/activity_int_exp_storage_use.xml @@ -7,9 +7,15 @@ + + + + + + + @@ -199,22 +222,19 @@ diff --git a/module_gjc/src/main/res/layout/dialog_int_exp_modify_storage.xml b/module_gjc/src/main/res/layout/dialog_int_exp_modify_storage.xml new file mode 100644 index 0000000..51537c3 --- /dev/null +++ b/module_gjc/src/main/res/layout/dialog_int_exp_modify_storage.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjc/src/main/res/layout/dialog_int_exp_move_clear.xml b/module_gjc/src/main/res/layout/dialog_int_exp_move_clear.xml new file mode 100644 index 0000000..213c10a --- /dev/null +++ b/module_gjc/src/main/res/layout/dialog_int_exp_move_clear.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjc/src/main/res/layout/item_int_exp_storage_use.xml b/module_gjc/src/main/res/layout/item_int_exp_storage_use.xml index 5df4666..3a221c7 100644 --- a/module_gjc/src/main/res/layout/item_int_exp_storage_use.xml +++ b/module_gjc/src/main/res/layout/item_int_exp_storage_use.xml @@ -65,7 +65,7 @@ + android:textSize="16sp" /> @@ -90,7 +88,7 @@ @@ -120,16 +116,14 @@ @@ -138,7 +132,7 @@ @@ -164,22 +156,20 @@ @@ -197,7 +187,7 @@ @@ -221,7 +209,7 @@ @@ -251,16 +237,14 @@ @@ -269,7 +253,7 @@ @@ -293,22 +275,20 @@ diff --git a/module_gjc/src/main/res/layout/item_int_exp_storage_use_sub.xml b/module_gjc/src/main/res/layout/item_int_exp_storage_use_sub.xml index a5dcc3d..21e5f28 100644 --- a/module_gjc/src/main/res/layout/item_int_exp_storage_use_sub.xml +++ b/module_gjc/src/main/res/layout/item_int_exp_storage_use_sub.xml @@ -59,7 +59,7 @@ android:layout_gravity="center_vertical" android:layout_weight="1.5" android:gravity="center" - android:text="@{bean.inDate != null ? bean.inDate.toString() : ``}" + android:text="@{bean.inDate ?? ``}" android:textColor="@color/text_normal" android:textSize="14sp" /> @@ -81,7 +81,7 @@ android:layout_gravity="center_vertical" android:layout_weight="1.5" android:gravity="center" - android:text="@{bean.outDate != null ? bean.outDate.toString() : ``}" + android:text="@{bean.outDate ?? ``}" android:textColor="@color/text_normal" android:textSize="14sp" />