From bad565085a49a8f894f591fd26ea913fdf5a995d Mon Sep 17 00:00:00 2001 From: YANGJIANKUAN Date: Wed, 28 Jan 2026 17:12:40 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20opt=20=E5=BC=80=E5=A7=8B=E7=BB=84?= =?UTF-8?q?=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_base/bean/GjcWarehouse.kt | 4 + .../GjcAssembleWeightEditViewModel.kt | 6 +- .../viewModel/IntExpAssembleStartViewModel.kt | 272 ++++++++++++------ 3 files changed, 198 insertions(+), 84 deletions(-) diff --git a/module_base/src/main/java/com/lukouguoji/module_base/bean/GjcWarehouse.kt b/module_base/src/main/java/com/lukouguoji/module_base/bean/GjcWarehouse.kt index 7c09144..eeaec6b 100644 --- a/module_base/src/main/java/com/lukouguoji/module_base/bean/GjcWarehouse.kt +++ b/module_base/src/main/java/com/lukouguoji/module_base/bean/GjcWarehouse.kt @@ -39,6 +39,10 @@ class GjcWarehouse : Serializable { var location: String = "" // uld var checkInPc: Long = 0 // 入库件数 var checkInWeight: Double = 0.0 // 入库重量 + set(value) { + field = value + onDataChanged?.invoke() + } var assembleCount: Int = 0 // 已经组装的数量 // ========== UI扩展字段 ========== diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/GjcAssembleWeightEditViewModel.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/GjcAssembleWeightEditViewModel.kt index 5351cb0..1f4e290 100644 --- a/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/GjcAssembleWeightEditViewModel.kt +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/GjcAssembleWeightEditViewModel.kt @@ -126,12 +126,14 @@ class GjcAssembleWeightEditViewModel : BaseViewModel() { /** * 计算统计数据:总货重、重量误差 + * - 总货重:运单列表中所有 checkInWeight(入库重量/组装重量)之和 + * - 重量误差:(总货重 - ULD货重) / ULD货重 * 100% */ private fun calculateStatistics() { val records = waybillList.value ?: emptyList() - // 计算总货重(所有运单weight之和) - val sumWeight = records.sumOf { it.weight } + // 计算总货重(所有运单 checkInWeight 之和,即列表中显示的重量) + val sumWeight = records.sumOf { it.checkInWeight } sumCargoWeight.value = String.format("%.2f", sumWeight) // 计算重量误差百分比(相对于ULD的货重) diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpAssembleStartViewModel.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpAssembleStartViewModel.kt index 4e30319..1ec06df 100644 --- a/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpAssembleStartViewModel.kt +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpAssembleStartViewModel.kt @@ -83,6 +83,14 @@ class IntExpAssembleStartViewModel : BaseViewModel() { */ val isUldNoLocked = MutableLiveData(false) + /** + * 卸货时选中的组装信息子运单数据 + * 用于: + * 1. 卸货校验时对比组装件数/重量 + * 2. 卸货提交时构建 wbInfo + */ + private var selectedAssembleWaybill: AssembleInfoBean? = null + /** * 是否从列表页"修改"模式进入 * 与 isUldNoLocked 的区别: @@ -173,6 +181,7 @@ class IntExpAssembleStartViewModel : BaseViewModel() { /** * 运单点击(单选切换) + * 装货模式:从运单列表选择运单 */ fun onWaybillItemClick(position: Int) { val list = waybillList.value ?: return @@ -190,9 +199,10 @@ class IntExpAssembleStartViewModel : BaseViewModel() { if (selectedWaybill != null) { selectedWaybill.isSelected.set(true) - // 自动提取航班号和航班日期 - assembleFlightNo.value = selectedWaybill.fno - assembleFlightDate.value = selectedWaybill.fdate + // 【删除】不再从运单提取航班信息(航班信息改为从ULD查询接口获取) + + // 【新增】清空卸货选中的子运单(切换到装货模式) + selectedAssembleWaybill = null // 保存当前的组装人(始终保留,从operator LiveData读取) val previousOperator = operator.value ?: "" @@ -380,6 +390,7 @@ class IntExpAssembleStartViewModel : BaseViewModel() { /** * 查询ULD信息(状态和耗材重量) + * 同时从ULD信息提取航班信息,并触发组装信息列表查询 */ private fun queryUldInfo(uldNo: String) { launchCollect({ NetApply.api.getUldWithConsumeWeight(uldNo) }) { @@ -401,6 +412,20 @@ class IntExpAssembleStartViewModel : BaseViewModel() { // 保存useId(用于装货/卸货接口) useId = uldBean.useId } + + // 【新增】从ULD信息提取航班信息 + if (uldBean.fno.isNotEmpty() && uldBean.fdate.isNotEmpty()) { + assembleFlightNo.value = uldBean.fno + assembleFlightDate.value = uldBean.fdateFormatted // 使用格式化后的日期(只保留年月日) + // 清除防抖标记,触发组装信息列表查询 + lastQueriedAssembledParams = "" + loadAssembledList() + } else { + // 航班信息为空,清空组装信息列表,但允许继续装货 + assembleFlightNo.value = "" + assembleFlightDate.value = "" + assembleInfoList.value = mutableListOf() + } } } onFailed = { code, message -> @@ -426,6 +451,14 @@ class IntExpAssembleStartViewModel : BaseViewModel() { /** * 执行组装操作(卸货或装货) * @param isLoad true-装货,false-卸货 + * + * 装货与卸货的区别: + * 1. 校验逻辑不同: + * - 装货:与运单列表中的件数/重量对比 + * - 卸货:与组装信息中的组装件数/重量对比 + * 2. wbInfo 来源不同: + * - 装货:从运单列表选中项获取 + * - 卸货:从组装信息选中的子运单获取 */ private fun performAssembleOperation(isLoad: Boolean) { // 1. 验证必填字段 @@ -454,36 +487,51 @@ class IntExpAssembleStartViewModel : BaseViewModel() { return } - // 校验件数范围 - val waybillPieces = waybillInfo.value?.waybillPieces?.trim() ?: "" - val assembleCountInt = assembleCount.toLongOrNull() ?: 0L - val waybillPiecesInt = waybillPieces.toLongOrNull() ?: 0L - - if (waybillPiecesInt > 0 && assembleCountInt > waybillPiecesInt) { - val errorMessage = if (isLoad) { - "装货件数不能大于运单件数" - } else { - "卸货件数不能大于已装货件数" - } - showToast(errorMessage) - return - } - val assembleWeight = waybillInfo.value?.assembleWeight?.trim() ?: "" - // 校验重量范围(如果填写了组装重量) - if (assembleWeight.isNotEmpty()) { - val waybillWeight = waybillInfo.value?.waybillWeight?.trim() ?: "" - val assembleWeightDouble = assembleWeight.toDoubleOrNull() ?: 0.0 - val waybillWeightDouble = waybillWeight.toDoubleOrNull() ?: 0.0 + // 【修改】区分校验逻辑 + val assembleCountInt = assembleCount.toLongOrNull() ?: 0L + val assembleWeightDouble = assembleWeight.toDoubleOrNull() ?: 0.0 - if (waybillWeightDouble > 0 && assembleWeightDouble > waybillWeightDouble) { - val errorMessage = if (isLoad) { - "装货重量不能大于运单重量" - } else { - "卸货重量不能大于已装货重量" + if (isLoad) { + // 装货校验:与运单列表中的件数/重量对比 + val waybillPieces = waybillInfo.value?.waybillPieces?.trim() ?: "" + val waybillPiecesInt = waybillPieces.toLongOrNull() ?: 0L + + if (waybillPiecesInt > 0 && assembleCountInt > waybillPiecesInt) { + showToast("装货件数不能大于运单件数") + return + } + + if (assembleWeight.isNotEmpty()) { + val waybillWeight = waybillInfo.value?.waybillWeight?.trim() ?: "" + val waybillWeightDouble = waybillWeight.toDoubleOrNull() ?: 0.0 + + if (waybillWeightDouble > 0 && assembleWeightDouble > waybillWeightDouble) { + showToast("装货重量不能大于运单重量") + return } - showToast(errorMessage) + } + } else { + // 卸货校验:与组装信息中的组装件数/重量对比 + val assembleInfo = selectedAssembleWaybill?.waybillData + if (assembleInfo == null) { + showToast("请从组装信息列表选择要卸货的运单") + return + } + + // originalPieces 对应 checkInPc(已组装件数) + val maxPieces = assembleInfo.originalPieces.toLongOrNull() ?: 0L + // originalWeight 对应 checkInWeight(已组装重量) + val maxWeight = assembleInfo.originalWeight.toDoubleOrNull() ?: 0.0 + + if (maxPieces > 0 && assembleCountInt > maxPieces) { + showToast("卸货件数不能大于已组装件数") + return + } + + if (assembleWeight.isNotEmpty() && maxWeight > 0 && assembleWeightDouble > maxWeight) { + showToast("卸货重量不能大于已组装重量") return } } @@ -500,21 +548,7 @@ class IntExpAssembleStartViewModel : BaseViewModel() { return } - // 2. 获取或构建运单Bean - // 从运单列表中获取选中的运单 - val currentWaybillList = waybillList.value - if (currentWaybillList == null) { - showToast("运单列表为空") - return - } - - val selectedWaybill = currentWaybillList.firstOrNull { it.isSelected.get() } - if (selectedWaybill == null) { - showToast("请选择运单") - return - } - - // 3. 构建useInfo(ULD信息) + // 2. 构建useInfo(ULD信息) val useInfo = mapOf( "uld" to uldNo, "consumeWeight" to materialWeight.toDoubleOrNull(), @@ -527,29 +561,62 @@ class IntExpAssembleStartViewModel : BaseViewModel() { "useId" to if (uldInfo.value?.useId == 0L) null else uldInfo.value?.useId // 添加useId(来自getUld接口) ) - // 4. 构建wbInfo(运单信息) - // 使用原始运单件数/重量(如果有),否则使用当前件数/重量 - val waybillPc = if (selectedWaybill.originalPieces.isNotEmpty()) { - selectedWaybill.originalPieces.toLongOrNull() + // 3. 【修改】区分 wbInfo 构建 + val wbInfo: Map + + if (isLoad) { + // 装货:从运单列表获取 + val currentWaybillList = waybillList.value + if (currentWaybillList == null) { + showToast("运单列表为空") + return + } + + val selectedWaybill = currentWaybillList.firstOrNull { it.isSelected.get() } + if (selectedWaybill == null) { + showToast("请选择运单") + return + } + + // 使用原始运单件数/重量(如果有),否则使用当前件数/重量 + val waybillPc = if (selectedWaybill.originalPieces.isNotEmpty()) { + selectedWaybill.originalPieces.toLongOrNull() + } else { + selectedWaybill.pieces.toLongOrNull() + } + val waybillWeight = if (selectedWaybill.originalWeight.isNotEmpty()) { + selectedWaybill.originalWeight.toDoubleOrNull() + } else { + selectedWaybill.weight.toDoubleOrNull() + } + + wbInfo = mapOf( + "wbNo" to selectedWaybill.waybillNo, + "pc" to waybillPc, + "weight" to waybillWeight, + "fdate" to selectedWaybill.fdate, + "fno" to selectedWaybill.fno, + "whId" to selectedWaybill.whId + ) } else { - selectedWaybill.pieces.toLongOrNull() - } - val waybillWeight = if (selectedWaybill.originalWeight.isNotEmpty()) { - selectedWaybill.originalWeight.toDoubleOrNull() - } else { - selectedWaybill.weight.toDoubleOrNull() + // 卸货:从组装信息子运单获取 + val assembleWaybill = selectedAssembleWaybill?.waybillData + if (assembleWaybill == null) { + showToast("请从组装信息列表选择要卸货的运单") + return + } + + wbInfo = mapOf( + "wbNo" to assembleWaybill.waybillNo, + "pc" to assembleWaybill.pieces.toLongOrNull(), // 运单件数 + "weight" to assembleWaybill.weight.toDoubleOrNull(), // 运单重量 + "fdate" to assembleWaybill.fdate, + "fno" to assembleWaybill.fno, + "whId" to assembleWaybill.whId + ) } - val wbInfo = mapOf( - "wbNo" to selectedWaybill.waybillNo, - "pc" to waybillPc, - "weight" to waybillWeight, - "fdate" to selectedWaybill.fdate, - "fno" to selectedWaybill.fno, - "whId" to selectedWaybill.whId - ) - - // 5. 构建完整请求参数 + // 4. 构建完整请求参数 val params = mapOf( "abPc" to assembleCount.toLongOrNull(), "abWeight" to assembleWeight.toDoubleOrNull(), @@ -561,7 +628,7 @@ class IntExpAssembleStartViewModel : BaseViewModel() { "userId" to SharedPreferenceUtil.getString(Constant.Share.account) ).toRequestBody() - // 6. 调用接口(带Loading,等待接口返回) + // 5. 调用接口(带Loading,等待接口返回) val operationName = if (isLoad) "装货" else "卸货" launchLoadingCollect({ if (isLoad) { @@ -572,7 +639,7 @@ class IntExpAssembleStartViewModel : BaseViewModel() { }) { onSuccess = { result -> // 接口成功后才显示成功提示并刷新列表 - handleOperationSuccess(operationName, isLoad, uldNo, selectedWaybill, assembleCount, assembleWeight) + handleOperationSuccess(operationName, isLoad, uldNo, assembleCount, assembleWeight) } onFailed = { code, message -> showToast("${operationName}失败: $message") @@ -587,7 +654,6 @@ class IntExpAssembleStartViewModel : BaseViewModel() { operationName: String, isLoad: Boolean, uldNo: String, - selectedWaybill: AssembleWaybillBean, assembleCount: String, assembleWeight: String ) { @@ -598,14 +664,45 @@ class IntExpAssembleStartViewModel : BaseViewModel() { FlowBus.with(ConstantEvent.EVENT_REFRESH).emit("refresh") } - // 重新查询组装信息列表(刷新数据) + // 清空表单(在刷新数据前清空,避免刷新时的状态冲突) + clearForm() + + // 清除防抖标记,强制刷新组装信息列表 + lastQueriedAssembledParams = "" loadAssembledList() - // 刷新运单列表 - loadInitialWaitingAssemble() + // 刷新运单列表(使用当前搜索条件) + refreshWaybillList() + } - // 清空表单 - clearForm() + /** + * 刷新运单列表(保留当前搜索条件) + */ + private fun refreshWaybillList() { + val wbNo = searchText.value?.trim() ?: "" + + launchLoadingCollect({ NetApply.api.queryWaitingAssemble(wbNo) }) { + onSuccess = { result -> + val warehouseList = result.data ?: mutableListOf() + val waybillBeanList = warehouseList.map { warehouse -> + AssembleWaybillBean().apply { + waybillNo = warehouse.wbNo + pieces = warehouse.pc.toString() + weight = String.format("%.1f", warehouse.weight) + flight = warehouse.flight + fno = warehouse.fno + fdate = warehouse.fdate + whId = warehouse.whId + isMarked = false + } + }.toMutableList() + + waybillList.value = waybillBeanList + } + onFailed = { code, message -> + showToast("刷新运单列表失败: $message") + } + } } /** @@ -737,14 +834,23 @@ class IntExpAssembleStartViewModel : BaseViewModel() { } /** - * 从二级运单行填充表单(编辑模式) - * 1. 填充ULD信息(并锁定ULD编号) - * 2. 填充运单信息(使用原始运单件数/重量,只读) - * 3. 保留组装件数、组装重量、组装人为可编辑 + * 从二级运单行填充表单(卸货模式) + * 1. 存储选中的组装信息子运单(用于卸货校验和提交) + * 2. 填充ULD信息(并锁定ULD编号) + * 3. 填充运单信息(字段对调:运单件数/组装件数对调,运单重量/组装重量对调) + * + * 卸货时字段映射: + * - 运单件数 ← pieces (pc,原始运单件数) + * - 运单重量 ← weight (weight,原始运单重量) + * - 组装件数 ← originalPieces (checkInPc,已组装件数,可编辑卸货数量) + * - 组装重量 ← originalWeight (checkInWeight,已组装重量,可编辑卸货数量) */ private fun fillFormFromWaybillDetail(item: AssembleInfoBean) { val waybill = item.waybillData ?: return + // 【新增】存储选中的组装信息子运单(用于卸货校验和提交) + selectedAssembleWaybill = item + // 1. 填充ULD信息 uldInfo.value = uldInfo.value?.apply { uldNo = item.parentUldNo @@ -754,14 +860,13 @@ class IntExpAssembleStartViewModel : BaseViewModel() { // 保存当前的组装人(在创建新对象前,从operator LiveData读取) val previousOperator = operator.value ?: "" - // 2. 填充运单信息 + // 2. 填充运单信息(【修改】对调字段填充) waybillInfo.value = WaybillInfoBean().apply { waybillNo = waybill.waybillNo - waybillPieces = waybill.originalPieces // 使用原始运单件数 - waybillWeight = waybill.originalWeight // 使用原始运单重量 - // 填充已累积的组装件数和组装重量(可编辑) - assembleCount = waybill.pieces - assembleWeight = waybill.weight + waybillPieces = waybill.pieces // 【对调】显示运单件数(pc) + waybillWeight = waybill.weight // 【对调】显示运单重量(weight) + assembleCount = waybill.originalPieces // 【对调】显示组装件数(checkInPc),可编辑卸货数量 + assembleWeight = waybill.originalWeight // 【对调】显示组装重量(checkInWeight),可编辑卸货数量 operator = previousOperator // 保留之前选择的组装人 } @@ -893,6 +998,9 @@ class IntExpAssembleStartViewModel : BaseViewModel() { operator = previousOperator // 恢复组装人 } isUldNoLocked.value = false + + // 【新增】清空卸货选中的子运单 + selectedAssembleWaybill = null } /**