From 222ae8a0f5d45933678c91610e50f7c7fef9cda1 Mon Sep 17 00:00:00 2001 From: YANG JIANKUAN Date: Thu, 18 Dec 2025 11:34:06 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20opt=20=E5=BC=80=E5=A7=8B=E7=BB=84?= =?UTF-8?q?=E8=A3=85=20tree?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_base/bean/AssembleInfoBean.kt | 48 ++- .../gjc/holder/AssembleInfoViewHolder.kt | 9 + .../assemble/IntExpAssembleStartActivity.kt | 7 +- .../viewModel/IntExpAssembleStartViewModel.kt | 351 +++++++++++++++++- .../activity_int_exp_assemble_start.xml | 1 + .../main/res/layout/item_assemble_info.xml | 118 ++++-- 6 files changed, 476 insertions(+), 58 deletions(-) diff --git a/module_base/src/main/java/com/lukouguoji/module_base/bean/AssembleInfoBean.kt b/module_base/src/main/java/com/lukouguoji/module_base/bean/AssembleInfoBean.kt index 30fbd1f..6b418cd 100644 --- a/module_base/src/main/java/com/lukouguoji/module_base/bean/AssembleInfoBean.kt +++ b/module_base/src/main/java/com/lukouguoji/module_base/bean/AssembleInfoBean.kt @@ -1,12 +1,50 @@ package com.lukouguoji.module_base.bean +import androidx.databinding.ObservableBoolean + /** - * 组装信息Bean(左侧列表) + * 组装信息Bean(左侧折叠列表) + * 支持两种行类型: + * 1. 一级ULD行: 显示ULD编号、总件数、总重量 + * 2. 二级运单行: 显示运单号、件数、重量 */ class AssembleInfoBean { + + // ========== 层级类型 ========== + enum class ItemType { + ULD_HEADER, // 一级ULD行 + WAYBILL_DETAIL // 二级运单行 + } + + var itemType: ItemType = ItemType.ULD_HEADER // 行类型 + + // ========== 一级ULD行字段 ========== var uldNo: String = "" // ULD编号 - var weightInfo: String = "" // 重量信息(如100/290kg) - var hasArrow: Boolean = false // 是否显示箭头(可点击) - var isOrange: Boolean = false // 是否橙色文字 - var showIndex: Boolean = true // 是否显示序号圆圈 + var uldIndex: Int = 0 // ULD序号(用于显示1、2、3...) + var totalPieces: Int = 0 // 总件数(二级运单件数求和) + var totalWeight: Double = 0.0 // 总重量(二级运单重量求和) + + // 展开/折叠状态(使用ObservableBoolean支持DataBinding) + val isExpanded: ObservableBoolean = ObservableBoolean(false) + + // 子运单列表(用于数据管理,不直接显示) + var waybillChildren: MutableList = mutableListOf() + + // ========== 二级运单行字段 ========== + var parentUldNo: String = "" // 父级ULD编号(用于关联) + var wbNo: String = "" // 运单号(直接使用后端字段名) + var waybillPieces: Int = 0 // 运单件数 + var waybillWeight: Double = 0.0 // 运单重量 + + // 原始运单数据(用于同步更新和填充表单) + var waybillData: AssembleWaybillBean? = null + + // ========== 视觉样式字段 ========== + var hasArrow: Boolean = false // 是否显示箭头(一级ULD行为true) + var isOrange: Boolean = false // 是否橙色文字(暂保留) + var showIndex: Boolean = false // 是否显示序号圆圈(改为false,不再显示序号) + var showIndent: Boolean = false // 是否显示缩进(二级运单行为true) + + // 保留原有的weightInfo字段(兼容性,但不再使用) + var weightInfo: String = "" } diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/holder/AssembleInfoViewHolder.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/AssembleInfoViewHolder.kt index 291d95f..32b36f5 100644 --- a/module_gjc/src/main/java/com/lukouguoji/gjc/holder/AssembleInfoViewHolder.kt +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/AssembleInfoViewHolder.kt @@ -7,6 +7,9 @@ import com.lukouguoji.module_base.bean.AssembleInfoBean /** * 组装信息ViewHolder + * 支持两种行类型: + * 1. 一级ULD行: 显示ULD编号、总件数、总重量、展开/折叠箭头 + * 2. 二级运单行: 显示缩进、运单号、件数、重量 */ class AssembleInfoViewHolder(view: View) : BaseViewHolder(view) { @@ -15,6 +18,12 @@ class AssembleInfoViewHolder(view: View) : val bean = getItemBean(item) ?: return binding.bean = bean binding.position = position + + // 设置点击事件(type=2表示组装信息列表点击) + itemView.setOnClickListener { + clickListener?.onItemClick(position, 2) + } + binding.executePendingBindings() } } diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/page/assemble/IntExpAssembleStartActivity.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/page/assemble/IntExpAssembleStartActivity.kt index 9abbe9e..0a29828 100644 --- a/module_gjc/src/main/java/com/lukouguoji/gjc/page/assemble/IntExpAssembleStartActivity.kt +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/page/assemble/IntExpAssembleStartActivity.kt @@ -76,6 +76,8 @@ class IntExpAssembleStartActivity : ) binding.rvAssembleInfo.layoutManager = LinearLayoutManager(this) binding.rvAssembleInfo.adapter = assembleInfoAdapter + // 添加点击监听器 + binding.rvAssembleInfo.addOnItemClickListener(this) // 左侧组装位置列表 assemblePositionAdapter = CommonAdapter( @@ -122,8 +124,9 @@ class IntExpAssembleStartActivity : */ override fun onItemClick(position: Int, type: Int) { when (type) { - 0 -> viewModel.onPositionItemClick(position) // 组装位置点击 - 1 -> viewModel.onWaybillItemClick(position) // 运单列表点击 + 0 -> viewModel.onPositionItemClick(position) // 组装位置点击 + 1 -> viewModel.onWaybillItemClick(position) // 运单列表点击 + 2 -> viewModel.onAssembleInfoItemClick(position) // 组装信息列表点击 else -> {} } } 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 a55bffa..80c8628 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 @@ -55,12 +55,32 @@ class IntExpAssembleStartViewModel : BaseViewModel() { // ========== 标记位,避免重复查询 ========== private var lastQueriedUldNo = "" + // ========== 本地存储(页面生命周期内)========== /** - * 初始化模拟数据(已废弃) + * 已组装货物的本地存储 + * Key: ULD编号 + * Value: 该ULD下的运单列表 */ - fun initMockData() { - // 不再加载mock数据 - } + private val assembledCargoMap = mutableMapOf>() + + /** + * 扁平化的组装信息列表(包含一级和二级行) + * 用于RecyclerView显示 + */ + private val flatAssembleInfoList = mutableListOf() + + /** + * 编辑模式标记 + * null: 新增模式 + * 非null: 编辑模式,存储原始ULD编号和运单号 + */ + private var editMode: Pair? = null // Pair + + /** + * ULD编号锁定状态 + */ + val isUldNoLocked = MutableLiveData(false) + /** * 加载组装位置列表 @@ -118,15 +138,20 @@ class IntExpAssembleStartViewModel : BaseViewModel() { val selectedWaybill = list[position] selectedWaybill.isSelected.set(true) + // 保存当前的组装件数、组装重量、组装人(在创建新对象前) + val previousAssembleCount = waybillInfo.value?.assembleCount ?: "" + val previousAssembleWeight = waybillInfo.value?.assembleWeight ?: "" + val previousOperator = waybillInfo.value?.operator ?: "" + // 同步运单信息到表单 waybillInfo.value = WaybillInfoBean().apply { waybillNo = selectedWaybill.waybillNo waybillPieces = selectedWaybill.pieces waybillWeight = selectedWaybill.weight // 保留当前的组装件数、组装重量、组装人 - assembleCount = waybillInfo.value?.assembleCount ?: "" - assembleWeight = waybillInfo.value?.assembleWeight ?: "" - operator = waybillInfo.value?.operator ?: "" + assembleCount = previousAssembleCount + assembleWeight = previousAssembleWeight + operator = previousOperator } } @@ -391,9 +416,12 @@ class IntExpAssembleStartViewModel : BaseViewModel() { "userId" to SharedPreferenceUtil.getString(Constant.Share.account) ).toRequestBody() - // 6. 调用接口 + // 6. 立即同步到组装信息列表(不等接口成功) val operationName = if (isLoad) "装货" else "卸货" - launchLoadingCollect({ + handleOperationSuccess(operationName, isLoad, uldNo, selectedWaybill, assembleCount, assembleWeight) + + // 7. 调用接口(后台执行,不阻塞UI) + launchCollect({ if (isLoad) { NetApply.api.assembleLoadCargo(params) } else { @@ -401,15 +429,308 @@ class IntExpAssembleStartViewModel : BaseViewModel() { } }) { onSuccess = { result -> - showToast("${operationName}成功") - // 刷新运单列表 - loadInitialWaitingAssemble() - // 清空运单信息 - waybillInfo.value = WaybillInfoBean() + // 接口成功,无需额外操作(已经同步到本地) } onFailed = { code, message -> - showToast("${operationName}失败: $message") + showToast("${operationName}接口调用失败: $message(数据已保存到本地)") } } } + + /** + * 处理装货/卸货操作成功 + */ + private fun handleOperationSuccess( + operationName: String, + isLoad: Boolean, + uldNo: String, + selectedWaybill: AssembleWaybillBean, + assembleCount: String, + assembleWeight: String + ) { + showToast("${operationName}成功") + + // 创建一个包含组装件数和重量的运单Bean + val assembleWaybill = AssembleWaybillBean() + assembleWaybill.waybillNo = selectedWaybill.waybillNo + assembleWaybill.pieces = assembleCount + assembleWaybill.weight = assembleWeight + assembleWaybill.flight = selectedWaybill.flight + assembleWaybill.fno = selectedWaybill.fno + assembleWaybill.fdate = selectedWaybill.fdate + assembleWaybill.whId = selectedWaybill.whId + assembleWaybill.isMarked = selectedWaybill.isMarked + + // 判断是新增还是编辑模式 + if (editMode != null) { + // 编辑模式:更新本地存储中的对应运单 + updateAssembledCargoInLocal( + uldNo = editMode!!.first, + oldWaybillNo = editMode!!.second, + newWaybillBean = assembleWaybill, + isLoad = isLoad + ) + } else { + // 新增模式:添加到本地存储 + addAssembledCargoToLocal(uldNo, assembleWaybill, isLoad) + } + + // 同步刷新组装信息列表 + syncAssembleInfoListFromLocal() + + // 刷新运单列表 + loadInitialWaitingAssemble() + + // 清空表单 + clearForm() + } + + /** + * 从本地存储同步组装信息列表 + * 1. 遍历 assembledCargoMap,为每个 ULD 生成一级行 + * 2. 计算总件数/总重量(求和子运单) + * 3. 根据展开状态决定是否添加二级运单行 + * 4. 更新 LiveData 触发 UI 刷新 + */ + private fun syncAssembleInfoListFromLocal() { + // 记录当前展开状态(避免刷新后展开状态丢失) + val expandedUlds = flatAssembleInfoList + .filter { it.itemType == AssembleInfoBean.ItemType.ULD_HEADER && it.isExpanded.get() } + .map { it.uldNo } + .toSet() + + flatAssembleInfoList.clear() + + // 遍历每个 ULD(带序号) + var uldIndex = 1 + assembledCargoMap.forEach { (uldNo, waybillList) -> + // 计算总件数和总重量 + var totalPieces = 0 + var totalWeight = 0.0 + waybillList.forEach { waybill -> + totalPieces += waybill.pieces.toIntOrNull() ?: 0 + totalWeight += waybill.weight.toDoubleOrNull() ?: 0.0 + } + + // 创建一级 ULD 行 + val uldHeader = AssembleInfoBean().apply { + itemType = AssembleInfoBean.ItemType.ULD_HEADER + this.uldNo = uldNo + this.uldIndex = uldIndex + this.totalPieces = totalPieces + this.totalWeight = totalWeight + hasArrow = true + showIndex = true // 显示序号 + + // 恢复展开状态 + isExpanded.set(expandedUlds.contains(uldNo)) + + // 保存子运单(用于展开/折叠) + waybillChildren = waybillList.map { waybill -> + AssembleInfoBean().apply { + itemType = AssembleInfoBean.ItemType.WAYBILL_DETAIL + parentUldNo = uldNo + wbNo = waybill.waybillNo + waybillPieces = waybill.pieces.toIntOrNull() ?: 0 + waybillWeight = waybill.weight.toDoubleOrNull() ?: 0.0 + waybillData = waybill + showIndent = true + showIndex = false + } + }.toMutableList() + } + + // 添加一级行 + flatAssembleInfoList.add(uldHeader) + + // 如果展开,添加二级运单行 + if (uldHeader.isExpanded.get()) { + flatAssembleInfoList.addAll(uldHeader.waybillChildren) + } + + // 递增序号 + uldIndex++ + } + + // 更新 LiveData + assembleInfoList.value = flatAssembleInfoList.toMutableList() + } + + /** + * 组装信息列表点击事件 + * 1. 点击一级 ULD 行:切换展开/折叠状态 + * 2. 点击二级运单行:进入编辑模式,填充表单 + */ + fun onAssembleInfoItemClick(position: Int) { + val list = flatAssembleInfoList + if (position !in list.indices) return + + val clickedItem = list[position] + + when (clickedItem.itemType) { + AssembleInfoBean.ItemType.ULD_HEADER -> { + // 一级 ULD 行:切换展开/折叠 + val newExpandState = !clickedItem.isExpanded.get() + clickedItem.isExpanded.set(newExpandState) + + // 重新生成扁平化列表 + syncAssembleInfoListFromLocal() + } + + AssembleInfoBean.ItemType.WAYBILL_DETAIL -> { + // 二级运单行:填充表单(编辑模式) + fillFormFromWaybillDetail(clickedItem) + } + } + } + + /** + * 从二级运单行填充表单(编辑模式) + * 1. 填充 ULD 信息(并锁定 ULD 编号) + * 2. 填充运单信息(只读) + * 3. 保留组装件数、组装重量、组装人为可编辑 + * 4. 标记编辑模式 + */ + private fun fillFormFromWaybillDetail(item: AssembleInfoBean) { + val waybill = item.waybillData ?: return + + // 1. 填充 ULD 信息 + uldInfo.value = uldInfo.value?.apply { + uldNo = item.parentUldNo + // 耗材重量、ULD 状态保持不变 + } + + // 保存当前的组装人(在创建新对象前) + val previousOperator = waybillInfo.value?.operator ?: "" + + // 2. 填充运单信息 + waybillInfo.value = WaybillInfoBean().apply { + waybillNo = waybill.waybillNo + waybillPieces = waybill.pieces + waybillWeight = waybill.weight + // 保留可编辑字段为空(需要用户重新输入) + assembleCount = "" + assembleWeight = "" + operator = previousOperator // 保留之前选择的组装人 + } + + // 3. 锁定 ULD 编号 + isUldNoLocked.value = true + + // 4. 标记编辑模式(存储原始 ULD 编号和运单号) + editMode = Pair(item.parentUldNo, waybill.waybillNo) + + // 5. 查询 ULD 信息(如果需要) + if (item.parentUldNo != lastQueriedUldNo) { + lastQueriedUldNo = item.parentUldNo + queryUldInfo(item.parentUldNo) + } + + showToast("已进入编辑模式,请修改组装信息") + } + + /** + * 新增模式:添加已组装货物到本地存储 + * @param isLoad true-装货(加),false-卸货(减) + */ + private fun addAssembledCargoToLocal(uldNo: String, waybill: AssembleWaybillBean, isLoad: Boolean) { + val list = assembledCargoMap.getOrPut(uldNo) { mutableListOf() } + + // 检查是否已存在 + val existingIndex = list.indexOfFirst { it.waybillNo == waybill.waybillNo } + if (existingIndex >= 0) { + // 已存在:累加或减去件数和重量 + val existing = list[existingIndex] + val existingPieces = existing.pieces.toIntOrNull() ?: 0 + val existingWeight = existing.weight.toDoubleOrNull() ?: 0.0 + val newPieces = waybill.pieces.toIntOrNull() ?: 0 + val newWeight = waybill.weight.toDoubleOrNull() ?: 0.0 + + if (isLoad) { + // 装货:累加 + existing.pieces = (existingPieces + newPieces).toString() + existing.weight = String.format("%.1f", existingWeight + newWeight) + } else { + // 卸货:减去 + val resultPieces = existingPieces - newPieces + val resultWeight = existingWeight - newWeight + + if (resultPieces <= 0 || resultWeight <= 0) { + // 减到0或负数,从列表中移除 + list.removeAt(existingIndex) + // 如果该ULD下没有运单了,删除整个ULD + if (list.isEmpty()) { + assembledCargoMap.remove(uldNo) + } + } else { + existing.pieces = resultPieces.toString() + existing.weight = String.format("%.1f", resultWeight) + } + } + } else { + // 不存在:直接新增(只有装货时才会走到这里) + if (isLoad) { + list.add(waybill) + } + } + } + + /** + * 编辑模式:更新本地存储中的运单数据 + * @param isLoad true-装货(加),false-卸货(减) + */ + private fun updateAssembledCargoInLocal( + uldNo: String, + oldWaybillNo: String, + newWaybillBean: AssembleWaybillBean, + isLoad: Boolean + ) { + val list = assembledCargoMap[uldNo] ?: return + + // 查找并更新 + val index = list.indexOfFirst { it.waybillNo == oldWaybillNo } + if (index >= 0) { + val existing = list[index] + val existingPieces = existing.pieces.toIntOrNull() ?: 0 + val existingWeight = existing.weight.toDoubleOrNull() ?: 0.0 + val newPieces = newWaybillBean.pieces.toIntOrNull() ?: 0 + val newWeight = newWaybillBean.weight.toDoubleOrNull() ?: 0.0 + + if (isLoad) { + // 装货:累加 + existing.pieces = (existingPieces + newPieces).toString() + existing.weight = String.format("%.1f", existingWeight + newWeight) + } else { + // 卸货:减去 + val resultPieces = existingPieces - newPieces + val resultWeight = existingWeight - newWeight + + if (resultPieces <= 0 || resultWeight <= 0) { + // 减到0或负数,从列表中移除 + list.removeAt(index) + // 如果该ULD下没有运单了,删除整个ULD + if (list.isEmpty()) { + assembledCargoMap.remove(uldNo) + } + } else { + existing.pieces = resultPieces.toString() + existing.weight = String.format("%.1f", resultWeight) + } + } + } + } + + /** + * 清空表单并退出编辑模式 + */ + private fun clearForm() { + // 保留组装人的值(用户期望保留上一次的选择) + val previousOperator = waybillInfo.value?.operator ?: "" + + waybillInfo.value = WaybillInfoBean().apply { + operator = previousOperator // 恢复组装人 + } + isUldNoLocked.value = false + editMode = null + } } diff --git a/module_gjc/src/main/res/layout/activity_int_exp_assemble_start.xml b/module_gjc/src/main/res/layout/activity_int_exp_assemble_start.xml index 4d1f8ea..8ae876b 100644 --- a/module_gjc/src/main/res/layout/activity_int_exp_assemble_start.xml +++ b/module_gjc/src/main/res/layout/activity_int_exp_assemble_start.xml @@ -249,6 +249,7 @@ + + @@ -23,45 +25,89 @@ android:paddingHorizontal="8dp" android:paddingVertical="6dp"> - - - - - + + android:gravity="center_vertical" + android:orientation="horizontal" + android:visibility="@{bean.itemType == AssembleInfoBean.ItemType.ULD_HEADER ? View.VISIBLE : View.GONE}"> - - + + + + + + + + + + + + + + + android:gravity="center_vertical" + android:orientation="horizontal" + android:visibility="@{bean.itemType == AssembleInfoBean.ItemType.WAYBILL_DETAIL ? View.VISIBLE : View.GONE}"> + + + + + + + + + + - -