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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+