From 29b1875fa5edd505abe2efef573ce6bc53ba3a05 Mon Sep 17 00:00:00 2001 From: YANGJIANKUAN Date: Thu, 27 Nov 2025 13:11:33 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=87=BA=E6=B8=AF=E7=BB=84=E8=A3=85=20?= =?UTF-8?q?list?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/deploymentTargetSelector.xml | 8 + app/src/main/AndroidManifest.xml | 6 + .../aerologic/ui/fragment/HomeFragment.kt | 12 + .../module_base/bean/GjcUldUseBean.kt | 4 + .../module_base/bean/GjcWarehouse.kt | 37 ++ .../lukouguoji/module_base/common/Constant.kt | 1 + .../lukouguoji/module_base/http/net/Api.kt | 25 ++ .../module_base/router/ARouterConstants.kt | 1 + .../main/res/drawable/bg_green_radius_4.xml | 5 + .../holder/AssembleWaybillDetailViewHolder.kt | 20 + .../gjc/holder/IntExpAssembleViewHolder.kt | 137 +++++++ .../page/assemble/IntExpAssembleActivity.kt | 40 ++ .../gjc/viewModel/IntExpAssembleViewModel.kt | 132 +++++++ .../res/layout/activity_int_exp_assemble.xml | 181 +++++++++ .../layout/item_assemble_waybill_detail.xml | 106 ++++++ .../res/layout/item_int_exp_assemble_uld.xml | 343 ++++++++++++++++++ 16 files changed, 1058 insertions(+) create mode 100644 module_base/src/main/java/com/lukouguoji/module_base/bean/GjcWarehouse.kt create mode 100644 module_base/src/main/res/drawable/bg_green_radius_4.xml create mode 100644 module_gjc/src/main/java/com/lukouguoji/gjc/holder/AssembleWaybillDetailViewHolder.kt create mode 100644 module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpAssembleViewHolder.kt create mode 100644 module_gjc/src/main/java/com/lukouguoji/gjc/page/assemble/IntExpAssembleActivity.kt create mode 100644 module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpAssembleViewModel.kt create mode 100644 module_gjc/src/main/res/layout/activity_int_exp_assemble.xml create mode 100644 module_gjc/src/main/res/layout/item_assemble_waybill_detail.xml create mode 100644 module_gjc/src/main/res/layout/item_int_exp_assemble_uld.xml diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml index b268ef3..6884b13 100644 --- a/.idea/deploymentTargetSelector.xml +++ b/.idea/deploymentTargetSelector.xml @@ -4,6 +4,14 @@ diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 22474f8..994eef7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -145,6 +145,12 @@ android:configChanges="orientation|keyboardHidden" android:exported="false" android:screenOrientation="userLandscape" /> + + { + ARouter.getInstance().build(ARouterConstants.ACTIVITY_URL_INT_EXP_ASSEMBLE) + .navigation() + } /** * 国际进港 */ @@ -645,6 +650,13 @@ class HomeFragment : Fragment() { "板箱组装" ) ) + list.add( + RightMenu( + Constant.AuthName.GjcIntExpAssembleActivity, + com.lukouguoji.module_base.R.drawable.img_gjc_banxiangzuzhuang, + "出港组装" + ) + ) list.add( RightMenu( Constant.AuthName.GjcGoodsListActivity, diff --git a/module_base/src/main/java/com/lukouguoji/module_base/bean/GjcUldUseBean.kt b/module_base/src/main/java/com/lukouguoji/module_base/bean/GjcUldUseBean.kt index 102e640..27a92b2 100644 --- a/module_base/src/main/java/com/lukouguoji/module_base/bean/GjcUldUseBean.kt +++ b/module_base/src/main/java/com/lukouguoji/module_base/bean/GjcUldUseBean.kt @@ -51,4 +51,8 @@ class GjcUldUseBean { var remark: String = "" // 备注 var checkFlag: String = "" // 检查标记 var emptyUld: String = "" // 空ULD + + // ========== 出港组装页面扩展字段 ========== + var isExpanded: Boolean = false // 展开状态 + var waybillDetails: MutableList? = null // 运单明细缓存 } 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 new file mode 100644 index 0000000..059ea66 --- /dev/null +++ b/module_base/src/main/java/com/lukouguoji/module_base/bean/GjcWarehouse.kt @@ -0,0 +1,37 @@ +package com.lukouguoji.module_base.bean + +/** + * 国际出港-运单明细Bean + * 对应API: IntExpAssemble/queryAssembled + */ +class GjcWarehouse { + var whId: Long = 0 // ID + var no: String = "" // 运单号(11位) + var prefix: String = "" // 运单前缀 + var wbNo: String = "" // 主运单编号 + var pc: Long = 0 // 件数 + var weight: Double = 0.0 // 重量 + var volume: Double = 0.0 // 体积 + var agentCode: String = "" // 代理code + var agentName: String = "" // 代理名称 + var dest: String = "" // 目的港 + var dest1: String = "" // 卸货站 + var dest2: String = "" // 第二目的地 + var dep: String = "" // 始发站 + var spCode: String = "" // 特码 + var goods: String = "" // 品名(英) + var goodsCn: String = "" // 品名(中) + var fdate: String = "" // 航班日期 + var fno: String = "" // 航班号 + var fclose: String = "" // 航班关闭时间 + var flight: String = "" // 航班:航班日期/航班号 + var range: String = "" // 航程 + var businessType: String = "" // 业务类型 + var opId: String = "" // 收运人ID + var userName: String = "" // 收运人 + var opDate: String = "" // 收运时间 + var location: String = "" // uld + var checkInPc: Long = 0 // 入库件数 + var checkInWeight: Double = 0.0 // 入库重量 + var assembleCount: Int = 0 // 已经组装的数量 +} diff --git a/module_base/src/main/java/com/lukouguoji/module_base/common/Constant.kt b/module_base/src/main/java/com/lukouguoji/module_base/common/Constant.kt index 973e2ba..0d4a039 100644 --- a/module_base/src/main/java/com/lukouguoji/module_base/common/Constant.kt +++ b/module_base/src/main/java/com/lukouguoji/module_base/common/Constant.kt @@ -244,6 +244,7 @@ interface Constant { const val GjcBanXListActivity = "AppIntExpBox" //板箱 const val GjcGoodsListActivity = "AppIntExpGoods" //货物交接 const val GjcInspectionActivity = "AppIntExpInspection" //收运检查 + const val GjcIntExpAssembleActivity = "AppIntExpAssemble" //出港组装 /** * 国际进港 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 c07e5bc..a0e3af5 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 @@ -28,6 +28,7 @@ import com.lukouguoji.module_base.bean.GjcGoodsAddBean import com.lukouguoji.module_base.bean.GjcGoodsBean import com.lukouguoji.module_base.bean.GjcGoodsDetailsBean import com.lukouguoji.module_base.bean.GjcUldUseBean +import com.lukouguoji.module_base.bean.GjcWarehouse import com.lukouguoji.module_base.bean.GjcWaybillBean import com.lukouguoji.module_base.bean.GjcWaybillDataBean import com.lukouguoji.module_base.bean.GjcWeighingBean @@ -443,6 +444,30 @@ interface Api { @POST("IntExpWeighting/weight") suspend fun submitGjcBoxWeighing(@Body data: RequestBody): BaseResultBean + // ==================== 国际出港-出港组装 ==================== + + /** + * 国际出港组装-分页查询已组装的ULD列表 + * 接口路径: /IntExpAssemble/pageQuery + */ + @POST("IntExpAssemble/pageQuery") + suspend fun getIntExpAssembleList(@Body data: RequestBody): BaseListBean + + /** + * 国际出港组装-分页合计统计数据 + * 接口路径: /IntExpAssemble/pageQueryTotal + */ + @POST("IntExpAssemble/pageQueryTotal") + suspend fun getIntExpAssembleTotal(@Body data: RequestBody): BaseResultBean + + /** + * 国际出港组装-根据板箱组装记录查询运单明细 + * 接口路径: /IntExpAssemble/queryAssembled + * @param data 请求参数:useId(ULD使用ID) + */ + @POST("IntExpAssemble/queryAssembled") + suspend fun getIntExpAssembleWaybillDetails(@Body data: RequestBody): BaseResultBean> + /** * 国际出港待计重-分页搜索 * 接口路径: /IntExpCheckIn/pageQuery diff --git a/module_base/src/main/java/com/lukouguoji/module_base/router/ARouterConstants.kt b/module_base/src/main/java/com/lukouguoji/module_base/router/ARouterConstants.kt index 80d08fa..1d28a0f 100644 --- a/module_base/src/main/java/com/lukouguoji/module_base/router/ARouterConstants.kt +++ b/module_base/src/main/java/com/lukouguoji/module_base/router/ARouterConstants.kt @@ -136,6 +136,7 @@ object ARouterConstants { const val ACTIVITY_URL_GJC_INSPECTION = "/gjc/GjcInspectionActivity" //国际出港 收运检查 const val ACTIVITY_URL_GJC_INSPECTION_DETAILS = "/gjc/GjcInspectionDetailsActivity" //国际出港 收运检查详情 const val ACTIVITY_URL_GJC_HANDOVER = "/gjc/GjcHandoverActivity" //国际出港 货物交接单 + const val ACTIVITY_URL_INT_EXP_ASSEMBLE = "/gjc/IntExpAssembleActivity" //国际出港 出港组装 ///////////////// 国际进港模块 /** diff --git a/module_base/src/main/res/drawable/bg_green_radius_4.xml b/module_base/src/main/res/drawable/bg_green_radius_4.xml new file mode 100644 index 0000000..91cfa01 --- /dev/null +++ b/module_base/src/main/res/drawable/bg_green_radius_4.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/holder/AssembleWaybillDetailViewHolder.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/AssembleWaybillDetailViewHolder.kt new file mode 100644 index 0000000..9bc0077 --- /dev/null +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/AssembleWaybillDetailViewHolder.kt @@ -0,0 +1,20 @@ +package com.lukouguoji.gjc.holder + +import android.view.View +import com.lukouguoji.gjc.databinding.ItemAssembleWaybillDetailBinding +import com.lukouguoji.module_base.base.BaseViewHolder +import com.lukouguoji.module_base.bean.GjcWarehouse + +/** + * 国际出港组装-运单明细ViewHolder + */ +class AssembleWaybillDetailViewHolder(view: View) : + BaseViewHolder(view) { + + override fun onBind(item: Any?, position: Int) { + val bean = getItemBean(item) ?: return + binding.bean = bean + binding.position = position // 用于显示序号 + binding.executePendingBindings() + } +} diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpAssembleViewHolder.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpAssembleViewHolder.kt new file mode 100644 index 0000000..fd68314 --- /dev/null +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpAssembleViewHolder.kt @@ -0,0 +1,137 @@ +package com.lukouguoji.gjc.holder + +import android.view.View +import android.view.ViewGroup +import android.view.animation.Animation +import android.view.animation.Transformation +import androidx.recyclerview.widget.LinearLayoutManager +import com.lukouguoji.gjc.R +import com.lukouguoji.gjc.databinding.ItemIntExpAssembleUldBinding +import com.lukouguoji.module_base.base.BaseViewHolder +import com.lukouguoji.module_base.base.CommonAdapter +import com.lukouguoji.module_base.bean.GjcUldUseBean +import com.lukouguoji.module_base.bean.GjcWarehouse + +/** + * 国际出港组装-ULD列表ViewHolder + * 支持展开/收起运单明细 + */ +class IntExpAssembleViewHolder(view: View) : + BaseViewHolder(view) { + + private var waybillAdapter: CommonAdapter? = null + + override fun onBind(item: Any?, position: Int) { + val bean = getItemBean(item) ?: return + binding.bean = bean + binding.position = position + + // 初始化运单明细子列表 + setupWaybillRecyclerView(bean) + + // 更新展开状态(初次绑定不需要动画) + updateExpandState(bean, animate = false) + + // 展开按钮点击事件 + binding.btnExpand.setOnClickListener { + clickListener?.onItemClick(position, 1000) // type=1000表示展开操作 + } + + binding.executePendingBindings() + } + + /** + * 初始化运单明细RecyclerView + */ + private fun setupWaybillRecyclerView(bean: GjcUldUseBean) { + if (binding.rvWaybillDetails.adapter == null) { + binding.rvWaybillDetails.layoutManager = LinearLayoutManager(itemView.context) + waybillAdapter = CommonAdapter( + itemView.context, + R.layout.item_assemble_waybill_detail, + AssembleWaybillDetailViewHolder::class.java + ) + binding.rvWaybillDetails.adapter = waybillAdapter + } + + // 刷新运单明细数据 + waybillAdapter?.refresh(bean.waybillDetails ?: mutableListOf()) + } + + /** + * 更新展开状态 + * @param bean ULD数据 + * @param animate 是否显示动画 + */ + private fun updateExpandState(bean: GjcUldUseBean, animate: Boolean = true) { + if (bean.isExpanded) { + // 展开 + if (animate) { + expand(binding.llWaybillDetails) + } else { + binding.llWaybillDetails.visibility = View.VISIBLE + } + binding.btnExpand.text = "收起" + } else { + // 收起 + if (animate) { + collapse(binding.llWaybillDetails) + } else { + binding.llWaybillDetails.visibility = View.GONE + } + binding.btnExpand.text = "展开" + } + } + + /** + * 展开动画(高度从0到wrap_content) + */ + private fun expand(view: View) { + // 测量目标高度 + view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED) + val targetHeight = view.measuredHeight + + // 初始高度设为0 + view.layoutParams.height = 0 + view.visibility = View.VISIBLE + + val animation = object : Animation() { + override fun applyTransformation(interpolatedTime: Float, t: Transformation?) { + view.layoutParams.height = if (interpolatedTime == 1f) { + ViewGroup.LayoutParams.WRAP_CONTENT + } else { + (targetHeight * interpolatedTime).toInt() + } + view.requestLayout() + } + + override fun willChangeBounds() = true + } + + animation.duration = 300 // 动画时长300ms + view.startAnimation(animation) + } + + /** + * 收起动画(高度从当前到0) + */ + private fun collapse(view: View) { + val initialHeight = view.measuredHeight + + val animation = object : Animation() { + override fun applyTransformation(interpolatedTime: Float, t: Transformation?) { + if (interpolatedTime == 1f) { + view.visibility = View.GONE + } else { + view.layoutParams.height = initialHeight - (initialHeight * interpolatedTime).toInt() + view.requestLayout() + } + } + + override fun willChangeBounds() = true + } + + animation.duration = 300 // 动画时长300ms + view.startAnimation(animation) + } +} diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/page/assemble/IntExpAssembleActivity.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/page/assemble/IntExpAssembleActivity.kt new file mode 100644 index 0000000..9d90df0 --- /dev/null +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/page/assemble/IntExpAssembleActivity.kt @@ -0,0 +1,40 @@ +package com.lukouguoji.gjc.page.assemble + +import android.os.Bundle +import com.alibaba.android.arouter.facade.annotation.Route +import com.lukouguoji.gjc.R +import com.lukouguoji.gjc.databinding.ActivityIntExpAssembleBinding +import com.lukouguoji.gjc.viewModel.IntExpAssembleViewModel +import com.lukouguoji.module_base.base.BaseBindingActivity +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.addOnItemClickListener +import com.lukouguoji.module_base.router.ARouterConstants + +/** + * 国际出港-出港组装Activity + */ +@Route(path = ARouterConstants.ACTIVITY_URL_INT_EXP_ASSEMBLE) +class IntExpAssembleActivity : + BaseBindingActivity() { + + override fun layoutId() = R.layout.activity_int_exp_assemble + override fun viewModelClass() = IntExpAssembleViewModel::class.java + + override fun initOnCreate(savedInstanceState: Bundle?) { + setBackArrow("出港组装") + binding.viewModel = viewModel + + // 绑定分页 + viewModel.pageModel.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, this) + + // 设置item点击监听 + binding.rv.addOnItemClickListener(viewModel) + + // 监听刷新事件 + FlowBus.with(ConstantEvent.EVENT_REFRESH).observe(this) { + viewModel.refresh() + } + } +} diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpAssembleViewModel.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpAssembleViewModel.kt new file mode 100644 index 0000000..1b91d65 --- /dev/null +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpAssembleViewModel.kt @@ -0,0 +1,132 @@ +package com.lukouguoji.gjc.viewModel + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.viewModelScope +import com.lukouguoji.gjc.R +import com.lukouguoji.gjc.holder.IntExpAssembleViewHolder +import com.lukouguoji.module_base.base.BasePageViewModel +import com.lukouguoji.module_base.bean.GjcUldUseBean +import com.lukouguoji.module_base.http.net.NetApply +import com.lukouguoji.module_base.ktx.commonAdapter +import com.lukouguoji.module_base.ktx.launchCollect +import com.lukouguoji.module_base.ktx.launchLoadingCollect +import com.lukouguoji.module_base.ktx.showToast +import com.lukouguoji.module_base.ktx.toRequestBody +import dev.utils.app.info.KeyValue +import kotlinx.coroutines.launch + +/** + * 国际出港-出港组装ViewModel + */ +class IntExpAssembleViewModel : BasePageViewModel() { + + // ========== 搜索条件 ========== + val flightDate = MutableLiveData("") // 航班日期 + val flightNo = MutableLiveData("") // 航班号 + val uldNo = MutableLiveData("") // ULD编号 + val reweighStatus = MutableLiveData("全部") // 复磅状态 + val reweighStatusList = MutableLiveData( // 复磅状态选项 + listOf( + KeyValue("全部", "全部"), + KeyValue("未复磅", "未复磅"), + KeyValue("已复磅", "已复磅") + ) + ) + val assembler = MutableLiveData("") // 组装人 + + // ========== 适配器配置 ========== + val itemViewHolder = IntExpAssembleViewHolder::class.java + val itemLayoutId = R.layout.item_int_exp_assemble_uld + + // ========== 底部统计 ========== + val totalCount = MutableLiveData("0") // 合计票数 + val totalPieces = MutableLiveData("0") // 总件数 + val totalWeight = MutableLiveData("0") // 总重量 + + /** + * 搜索按钮点击 + */ + fun searchClick() { + refresh() + } + + /** + * 切换展开/收起状态 + */ + fun toggleExpand(position: Int) { + val bean = pageModel.rv?.commonAdapter()?.getItem(position) as? GjcUldUseBean ?: return + bean.isExpanded = !bean.isExpanded + + if (bean.isExpanded && bean.waybillDetails == null) { + // 首次展开,加载运单明细 + loadWaybillDetails(position, bean) + } else { + // 已有数据,直接刷新item显示/隐藏 + pageModel.rv?.commonAdapter()?.notifyItemChanged(position) + } + } + + /** + * 加载运单明细 + */ + private fun loadWaybillDetails(position: Int, bean: GjcUldUseBean) { + val params = mapOf("useId" to bean.useId).toRequestBody() + + launchCollect({ NetApply.api.getIntExpAssembleWaybillDetails(params) }) { + onSuccess = { result -> + bean.waybillDetails = result.data ?: mutableListOf() + pageModel.rv?.commonAdapter()?.notifyItemChanged(position) + } + onFailed = { _, msg -> + bean.isExpanded = false // 加载失败,恢复展开状态 + showToast(msg) + } + } + } + + /** + * 获取数据(列表 + 统计) + */ + override fun getData() { + // 构建筛选参数 + val filterParams = mapOf( + "fdate" to flightDate.value!!.ifEmpty { null }, + "fno" to flightNo.value!!.ifEmpty { null }, + "uld" to uldNo.value!!.ifEmpty { null }, + "ldUserName" to assembler.value!!.ifEmpty { null } + ) + + // 列表参数(含分页) + val listParams = (filterParams + mapOf( + "pageNum" to pageModel.page, + "pageSize" to pageModel.limit + )).toRequestBody() + + // 统计参数(无分页) + val totalParams = filterParams.toRequestBody() + + // 获取列表(显示loading) + launchLoadingCollect({ NetApply.api.getIntExpAssembleList(listParams) }) { + onSuccess = { pageModel.handleListBean(it) } + } + + // 获取统计(后台调用) + launchCollect({ NetApply.api.getIntExpAssembleTotal(totalParams) }) { + onSuccess = { result -> + val data = result.data + totalCount.value = (data?.wbNumber ?: 0).toString() + totalPieces.value = (data?.totalPc ?: 0).toString() + totalWeight.value = (data?.totalWeight ?: 0.0).toString() + } + } + } + + /** + * Item点击事件处理 + */ + override fun onItemClick(position: Int, type: Int) { + if (type == 1000) { // 展开/收起操作 + toggleExpand(position) + } + } +} diff --git a/module_gjc/src/main/res/layout/activity_int_exp_assemble.xml b/module_gjc/src/main/res/layout/activity_int_exp_assemble.xml new file mode 100644 index 0000000..dee7384 --- /dev/null +++ b/module_gjc/src/main/res/layout/activity_int_exp_assemble.xml @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjc/src/main/res/layout/item_assemble_waybill_detail.xml b/module_gjc/src/main/res/layout/item_assemble_waybill_detail.xml new file mode 100644 index 0000000..11d4d56 --- /dev/null +++ b/module_gjc/src/main/res/layout/item_assemble_waybill_detail.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjc/src/main/res/layout/item_int_exp_assemble_uld.xml b/module_gjc/src/main/res/layout/item_int_exp_assemble_uld.xml new file mode 100644 index 0000000..0569d3e --- /dev/null +++ b/module_gjc/src/main/res/layout/item_int_exp_assemble_uld.xml @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +