feat: 国际出港 出港仓库 finish

This commit is contained in:
2026-01-17 16:30:29 +08:00
parent dfddf646f5
commit e2f6cdde04
8 changed files with 312 additions and 26 deletions

View File

@@ -832,6 +832,13 @@ interface Api {
@POST("IntExpStorageUse/outStorage") @POST("IntExpStorageUse/outStorage")
suspend fun outIntExpStorage(@Body data: RequestBody): BaseResultBean<Boolean> suspend fun outIntExpStorage(@Body data: RequestBody): BaseResultBean<Boolean>
/**
* 国际出港库位操作-入库
* 接口路径: /IntExpStorageUse/inStorage
*/
@POST("IntExpStorageUse/inStorage")
suspend fun inIntExpStorage(@Body data: RequestBody): BaseResultBean<Boolean>
/** /**
* 国际出港仓库-分页查询 * 国际出港仓库-分页查询
* 接口路径: /IntExpStorageUse/pageQuery * 接口路径: /IntExpStorageUse/pageQuery
@@ -853,6 +860,14 @@ interface Api {
@POST("IntExpStorageUse/queryWbNoList") @POST("IntExpStorageUse/queryWbNoList")
suspend fun getIntExpStorageWbNoList(@Body data: RequestBody): BaseResultBean<List<String>> suspend fun getIntExpStorageWbNoList(@Body data: RequestBody): BaseResultBean<List<String>>
/**
* 获取库位列表
* 接口路径: /typeCode/locationByFlag
* @param flag 库位标志2表示国际出港库位
*/
@GET("typeCode/locationByFlag")
suspend fun getLocationList(@Query("flag") flag: Int): BaseResultBean<List<DictLocationBean>>
/** /**
* 国际出港待计重-分页搜索 * 国际出港待计重-分页搜索
* 接口路径: /IntExpCheckIn/pageQuery * 接口路径: /IntExpCheckIn/pageQuery

View File

@@ -9,6 +9,7 @@ import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.databinding.ActivityIntExpStorageUseBinding import com.lukouguoji.gjc.databinding.ActivityIntExpStorageUseBinding
import com.lukouguoji.gjc.dialog.IntExpMoveClearDialogModel import com.lukouguoji.gjc.dialog.IntExpMoveClearDialogModel
import com.lukouguoji.gjc.dialog.IntExpModifyStorageDialogModel import com.lukouguoji.gjc.dialog.IntExpModifyStorageDialogModel
import com.lukouguoji.gjc.dialog.IntExpInStorageDialogModel
import com.lukouguoji.gjc.viewModel.IntExpStorageUseViewModel import com.lukouguoji.gjc.viewModel.IntExpStorageUseViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.common.Constant import com.lukouguoji.module_base.common.Constant
@@ -115,8 +116,9 @@ class IntExpStorageUseActivity :
// 显示修改库位对话框 // 显示修改库位对话框
IntExpModifyStorageDialogModel { dialog -> IntExpModifyStorageDialogModel { dialog ->
// 用户点击保存后,执行修改库位操作 // 用户点击保存后,执行修改库位操作
val newLocation = dialog.location.value ?: "" val locationName = dialog.locationName
viewModel.performModifyStorage(newLocation, selectedStorage) val locationId = dialog.locationId
viewModel.performModifyStorage(locationName, locationId, selectedStorage)
}.show(this) }.show(this)
} }
@@ -151,6 +153,41 @@ class IntExpStorageUseActivity :
.show() .show()
} }
/**
* 显示入库操作对话框
*/
fun showInStorageDialog() {
val list = viewModel.pageModel.rv?.commonAdapter()?.items as? List<*> ?: return
val allItems = list.filterIsInstance<com.lukouguoji.module_base.bean.GjcMaWb>()
// 构建入库数据:保留主列表结构,但只包含选中的子列表项
val maWbListForInStorage = allItems.mapNotNull { maWb ->
// 过滤出选中的子列表项
val selectedStorageList = maWb.storageUseList?.filter { it.isSelected } ?: emptyList()
// 只添加有选中子列表项的主列表项
if (selectedStorageList.isNotEmpty() || maWb.isSelected) {
// 创建主列表项的副本,只包含选中的子列表
maWb.copy(storageUseList = selectedStorageList)
} else {
null
}
}
if (maWbListForInStorage.isEmpty()) {
showToast("请至少选择一个单据")
return
}
// 显示入库对话框
IntExpInStorageDialogModel { dialog ->
// 用户点击保存后,执行入库操作
val locationName = dialog.locationName
val locationId = dialog.locationId
viewModel.performInStorage(locationName, locationId, maWbListForInStorage)
}.show(this)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
if (requestCode == Constant.RequestCode.WAYBILL && resultCode == Activity.RESULT_OK) { if (requestCode == Constant.RequestCode.WAYBILL && resultCode == Activity.RESULT_OK) {

View File

@@ -0,0 +1,74 @@
package com.lukouguoji.gjc.dialog
import android.content.Context
import androidx.lifecycle.MutableLiveData
import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.databinding.DialogIntExpInStorageBinding
import com.lukouguoji.module_base.base.BaseDialogModel
import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.ktx.launchCollect
import com.lukouguoji.module_base.ktx.showToast
import com.lukouguoji.module_base.ktx.verifyNullOrEmpty
import dev.utils.app.info.KeyValue
/**
* 国际出港仓库 - 入库操作对话框
*/
class IntExpInStorageDialogModel(
private val callback: (IntExpInStorageDialogModel) -> Unit
) : BaseDialogModel<DialogIntExpInStorageBinding>(DIALOG_TYPE_CENTER) {
// 库位列表
val locationList = MutableLiveData<List<KeyValue>>()
// 选中的库位存储的是code
val selectedLocationCode = MutableLiveData("")
// 库位ID (后端需要的code)
var locationId: String = ""
// 库位名称 (后端需要的name)
var locationName: String = ""
override fun layoutId(): Int {
return R.layout.dialog_int_exp_in_storage
}
override fun onDialogCreated(context: Context) {
binding.model = this
loadLocationList()
// 监听选择变化更新locationId和locationName
selectedLocationCode.observeForever { code ->
val selectedItem = locationList.value?.find { it.value == code }
locationId = selectedItem?.value ?: ""
locationName = selectedItem?.key ?: ""
}
}
/**
* 加载库位列表
*/
private fun loadLocationList() {
launchCollect({ NetApply.api.getLocationList(flag = 2) }) {
onSuccess = { result ->
val list = result.data?.map { it.toKeyValue() } ?: emptyList()
locationList.value = list
}
onFailed = { _, msg ->
showToast(msg ?: "加载库位列表失败")
}
}
}
/**
* 保存按钮点击
*/
fun onSaveClick() {
if (selectedLocationCode.value.verifyNullOrEmpty("请选择库位")) {
return
}
dismiss()
callback(this)
}
}

View File

@@ -5,7 +5,11 @@ import androidx.lifecycle.MutableLiveData
import com.lukouguoji.gjc.R import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.databinding.DialogIntExpModifyStorageBinding import com.lukouguoji.gjc.databinding.DialogIntExpModifyStorageBinding
import com.lukouguoji.module_base.base.BaseDialogModel import com.lukouguoji.module_base.base.BaseDialogModel
import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.ktx.launchCollect
import com.lukouguoji.module_base.ktx.showToast
import com.lukouguoji.module_base.ktx.verifyNullOrEmpty import com.lukouguoji.module_base.ktx.verifyNullOrEmpty
import dev.utils.app.info.KeyValue
/** /**
* 国际出港 - 修改库位对话框 * 国际出港 - 修改库位对话框
@@ -14,8 +18,17 @@ class IntExpModifyStorageDialogModel(
private val callback: (IntExpModifyStorageDialogModel) -> Unit private val callback: (IntExpModifyStorageDialogModel) -> Unit
) : BaseDialogModel<DialogIntExpModifyStorageBinding>(DIALOG_TYPE_CENTER) { ) : BaseDialogModel<DialogIntExpModifyStorageBinding>(DIALOG_TYPE_CENTER) {
// 库位 // 库位列表
val location = MutableLiveData("") val locationList = MutableLiveData<List<KeyValue>>()
// 选中的库位存储的是code
val selectedLocationCode = MutableLiveData("")
// 库位ID (后端需要的code)
var locationId: String = ""
// 库位名称 (后端需要的name)
var locationName: String = ""
override fun layoutId(): Int { override fun layoutId(): Int {
return R.layout.dialog_int_exp_modify_storage return R.layout.dialog_int_exp_modify_storage
@@ -23,13 +36,36 @@ class IntExpModifyStorageDialogModel(
override fun onDialogCreated(context: Context) { override fun onDialogCreated(context: Context) {
binding.model = this binding.model = this
loadLocationList()
// 监听选择变化更新locationId和locationName
selectedLocationCode.observeForever { code ->
val selectedItem = locationList.value?.find { it.value == code }
locationId = selectedItem?.value ?: ""
locationName = selectedItem?.key ?: ""
}
}
/**
* 加载库位列表
*/
private fun loadLocationList() {
launchCollect({ NetApply.api.getLocationList(flag = 2) }) {
onSuccess = { result ->
val list = result.data?.map { it.toKeyValue() } ?: emptyList()
locationList.value = list
}
onFailed = { _, msg ->
showToast(msg ?: "加载库位列表失败")
}
}
} }
/** /**
* 保存按钮点击 * 保存按钮点击
*/ */
fun onSaveClick() { fun onSaveClick() {
if (location.value.verifyNullOrEmpty("输入库位")) { if (selectedLocationCode.value.verifyNullOrEmpty("选择库位")) {
return return
} }
dismiss() dismiss()

View File

@@ -177,17 +177,25 @@ class IntExpStorageUseViewModel : BasePageViewModel() {
/** /**
* 执行修改库位操作 * 执行修改库位操作
* @param newLocation 新的库位 * @param locationName 新的库位名称 (后端的location字段)
* @param locationId 新的库位ID (后端的locationId字段)
* @param storageUse 选中的单个库位使用对象 * @param storageUse 选中的单个库位使用对象
*/ */
fun performModifyStorage(newLocation: String, storageUse: com.lukouguoji.module_base.bean.GjcStorageUse) { fun performModifyStorage(
if (newLocation.isEmpty()) { locationName: String,
showToast("请输入新的库位号") locationId: String,
storageUse: com.lukouguoji.module_base.bean.GjcStorageUse
) {
if (locationName.isEmpty() || locationId.isEmpty()) {
showToast("请选择库位")
return return
} }
// 创建更新后的库位对象(覆盖 location 字段) // 创建更新后的库位对象(覆盖 location 和 locationId 字段)
val updatedStorage = storageUse.copy(location = newLocation) val updatedStorage = storageUse.copy(
location = locationName,
locationId = locationId.toLongOrNull() ?: 0
)
// 直接使用更新后的对象构建请求参数 // 直接使用更新后的对象构建请求参数
val params = updatedStorage.toRequestBody() val params = updatedStorage.toRequestBody()
@@ -244,21 +252,49 @@ class IntExpStorageUseViewModel : BasePageViewModel() {
* 入库操作 * 入库操作
*/ */
fun inStorage() { fun inStorage() {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjcMaWb> ?: return // 由Activity显示对话框
}
// 收集所有选中的子列表项(库位) /**
val selectedStorageUseList = mutableListOf<com.lukouguoji.module_base.bean.GjcStorageUse>() * 执行入库操作
list.forEach { maWb -> * @param locationName 库位名称 (后端的location字段)
maWb.storageUseList?.filter { it.isSelected }?.let { selectedStorageUseList.addAll(it) } * @param locationId 库位ID (后端的locationId字段)
} * @param maWbListForInStorage 包含选中子列表项的主列表数据
*/
if (selectedStorageUseList.isEmpty()) { fun performInStorage(
showToast("请选择要入库的库位") locationName: String,
locationId: String,
maWbListForInStorage: List<GjcMaWb>
) {
if (maWbListForInStorage.isEmpty()) {
showToast("请至少选择一个单据")
return return
} }
// TODO: 实现入库接口调用 if (locationName.isEmpty() || locationId.isEmpty()) {
showToast("入库功能待实现") showToast("请选择库位")
return
}
// 构建请求参数:库位名称 + 库位ID + 完整的主子列表结构
val params = mapOf(
"location" to locationName,
"locationId" to locationId.toLongOrNull(),
"maWbList" to maWbListForInStorage
).toRequestBody()
launchLoadingCollect({ NetApply.api.inIntExpStorage(params) }) {
onSuccess = {
showToast("入库成功")
viewModelScope.launch {
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
}
refresh() // 刷新列表
}
onFailed = { _, msg ->
showToast(msg.noNull("入库失败"))
}
}
} }
/** /**

View File

@@ -240,7 +240,7 @@
<!-- 入库按钮 --> <!-- 入库按钮 -->
<TextView <TextView
style="@style/tv_bottom_btn" style="@style/tv_bottom_btn"
android:onClick="@{()-> viewModel.inStorage()}" android:onClick="@{()-> activity.showInStorageDialog()}"
android:text="入 库" /> android:text="入 库" />
</LinearLayout> </LinearLayout>

View File

@@ -0,0 +1,87 @@
<?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.IntExpInStorageDialogModel" />
</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.SPINNER}"
hint='@{"请选择库位"}'
list="@{model.locationList}"
value="@={model.selectedLocationCode}" />
</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>

View File

@@ -55,9 +55,10 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
type="@{SearchLayoutType.INPUT}" type="@{SearchLayoutType.SPINNER}"
hint='@{"请输入库位"}' hint='@{"请选择库位"}'
value="@={model.location}" /> list="@{model.locationList}"
value="@={model.selectedLocationCode}" />
</LinearLayout> </LinearLayout>