feat: opt 开始组装

This commit is contained in:
2026-01-28 17:12:40 +08:00
parent 6ea6833396
commit bad565085a
3 changed files with 198 additions and 84 deletions

View File

@@ -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的货重

View File

@@ -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. 构建useInfoULD信息
// 2. 构建useInfoULD信息
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<String, Any?>
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<String>(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
}
/**