feat: 完成出港运抵页面5.5寸手机端适配

- 主列表新增待运抵/已运抵 Tab(客户端按申报状态拆分)+ 卡片长按浮层(补充/重置/回执)
- 新增分单明细页:复用主列表已加载数据,零新增请求
- 新增回执内容只读页
- 新增补充信息页:参照 Pad 端收发货人信息批量应用模式(后端接口暂缺,已登记问题清单)
- 手机首页「国际」Tab 增加「出港运抵」入口
- 修复两个平台坑:RecyclerView 内 GONE 不塌陷高度;Serializable Intent 传递
  遇 @Transient 字段反序列化为 null 导致的崩溃
- 登记后端接口缺口 2 项(#19~#20)至问题清单

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-07-30 11:44:51 +08:00
parent 1eb288a703
commit ef8e7cfacb
37 changed files with 2825 additions and 775 deletions

View File

@@ -3,6 +3,7 @@ package com.lukouguoji.gjc.activity
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import androidx.databinding.ObservableBoolean
import com.alibaba.android.arouter.facade.annotation.Autowired
import com.alibaba.android.arouter.facade.annotation.Route
import com.alibaba.android.arouter.launcher.ARouter
@@ -10,15 +11,24 @@ import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.databinding.ActivityIntExpArriveBinding
import com.lukouguoji.gjc.viewModel.IntExpArriveViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.bean.GjcHaWb
import com.lukouguoji.module_base.bean.GjcMaWb
import com.lukouguoji.module_base.common.Constant
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.ktx.commonAdapter
import com.lukouguoji.module_base.router.ARouterConstants
import com.lukouguoji.module_base.util.DeviceUtil
import java.util.ArrayList
/**
* 国际出港-出港运抵页面
*
* 布局 id 不区分设备,平板/手机由资源限定符自动选择:
* layout-sw600dp/activity_int_exp_arrive.xml平板
* layout/activity_int_exp_arrive.xml手机
*/
@Route(path = ARouterConstants.ACTIVITY_URL_INT_EXP_ARRIVE)
class IntExpArriveActivity :
@@ -31,12 +41,25 @@ class IntExpArriveActivity :
override fun layoutId() = R.layout.activity_int_exp_arrive
override fun viewModelClass() = IntExpArriveViewModel::class.java
/** 手机版筛选弹层显隐(仅 UI 状态,不涉及业务逻辑) */
val filterPanelVisible = ObservableBoolean(false)
/** 供 [com.lukouguoji.gjc.holder.IntExpArriveViewHolder] 绑定 item 布局的 viewModel 变量(父类 viewModel 为 protected */
val itemViewModel: IntExpArriveViewModel get() = viewModel
override fun initOnCreate(savedInstanceState: Bundle?) {
// 注入 ARouter 参数
ARouter.getInstance().inject(this)
setBackArrow("国际出港运抵")
binding.viewModel = viewModel
binding.activity = this
// 手机版专属数据:加载「代理」筛选下拉
// 平板端不调用,查询链路与请求次数与改造前完全一致
if (DeviceUtil.isPhone()) {
viewModel.initPhoneExtras()
}
// 如果有传入运单号,自动填充并触发搜索
if (!wbNoParam.isNullOrEmpty()) {
@@ -63,6 +86,77 @@ class IntExpArriveActivity :
}
}
// ==================== 手机版专用交互(纯 UI复用既有 ViewModel 字段与数据) ====================
/**
* 手机版 Tab 切换回调PhoneStatusTab 已通过双向绑定写入 viewModel.currentTab
* 这里触发 ViewModel 把适配器数据集替换为过滤后的子集(不发起新请求)。
*/
fun onArriveTabChanged() {
viewModel.onTabChangedPhone()
}
/** 卡片长按展开操作浮层View.OnLongClickListener 要求返回 Boolean */
fun showCardActionPhone(bean: GjcMaWb): Boolean {
bean.actionMenuVisible.set(true)
return true
}
/** 点击浮层遮罩/空白处:收起操作浮层 */
fun hideCardActionPhone(bean: GjcMaWb) {
bean.actionMenuVisible.set(false)
}
/** 选择圈勾选状态变化后回调(由 ViewHolder 调用) */
fun onItemCheckChanged() {
viewModel.onItemCheckChanged()
}
/** 手机版筛选弹层显隐切换 */
fun toggleFilterPanel() {
filterPanelVisible.set(!filterPanelVisible.get())
}
/** 手机版筛选:重置 */
fun resetFilter() {
viewModel.flightDate.value = ""
viewModel.flightNo.value = ""
viewModel.agentCodePhone.value = ""
}
/** 手机版筛选:确认 */
fun confirmFilter() {
filterPanelVisible.set(false)
viewModel.searchClick()
}
/**
* 进入「分单明细」页:直接传递该运单已加载的 haWbList零新增请求。
*/
fun openSubOrder(bean: GjcMaWb) {
val list = ArrayList<GjcHaWb>(bean.haWbList.orEmpty())
IntExpArriveSubOrderActivity.start(this, bean.wbNo.orEmpty(), list)
}
/**
* 进入「回执」页(手机专属只读页):复用 haWbList[].response + arrivalOpDate零新增请求。
*/
fun openReceipt(bean: GjcMaWb) {
bean.actionMenuVisible.set(false)
val list = ArrayList<GjcHaWb>(bean.haWbList.orEmpty())
IntExpArriveReceiptActivity.start(this, bean.wbNo.orEmpty(), list)
}
/**
* 进入「补充信息」页(手机专属新页):对该运单整个 haWbList 批量应用(参照 Pad 端国际进港
* IntArrSupplementInfoViewModel 的批量复制模式)。后端暂无保存接口,见接口问题清单。
*/
fun openSupplement(bean: GjcMaWb) {
bean.actionMenuVisible.set(false)
val list = ArrayList<GjcHaWb>(bean.haWbList.orEmpty())
IntExpArriveSupplementActivity.start(this, bean.wbNo.orEmpty(), list)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {

View File

@@ -0,0 +1,43 @@
package com.lukouguoji.gjc.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.databinding.ActivityIntExpArriveReceiptBinding
import com.lukouguoji.gjc.viewModel.IntExpArriveReceiptViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.bean.GjcHaWb
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.ktx.refresh
/**
* 国际出港运抵-回执内容页5.5寸手机版专属只读新页,平板端无对应页面)
*
* 数据来自主列表页已加载的 haWbList零新增请求。
* 对应设计稿 documents/5.5寸手持端设计文件/04_出港运抵/receipt.html。
*/
class IntExpArriveReceiptActivity :
BaseBindingActivity<ActivityIntExpArriveReceiptBinding, IntExpArriveReceiptViewModel>() {
override fun layoutId() = R.layout.activity_int_exp_arrive_receipt
override fun viewModelClass() = IntExpArriveReceiptViewModel::class.java
override fun initOnCreate(savedInstanceState: Bundle?) {
setBackArrow("回执内容")
binding.viewModel = viewModel
viewModel.initOnCreated(intent)
viewModel.receiptList.observe(this) { binding.rv.refresh(it) }
}
companion object {
@JvmStatic
fun start(context: Context, wbNo: String, haWbList: ArrayList<GjcHaWb>) {
val starter = Intent(context, IntExpArriveReceiptActivity::class.java)
.putExtra(Constant.Key.CODE, wbNo)
.putExtra(Constant.Key.DATA, haWbList)
context.startActivity(starter)
}
}
}

View File

@@ -0,0 +1,92 @@
package com.lukouguoji.gjc.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.databinding.ObservableBoolean
import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.databinding.ActivityIntExpArriveSubOrderBinding
import com.lukouguoji.gjc.viewModel.IntExpArriveSubOrderViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.bean.GjcHaWb
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.ktx.commonAdapter
import com.lukouguoji.module_base.ktx.refresh
/**
* 国际出港运抵-分单明细页5.5寸手机版专属新页,平板端无对应页面)
*
* 数据来自主列表页已加载的 haWbListIntent 传入),零新增请求。
* 对应设计稿 documents/5.5寸手持端设计文件/04_出港运抵/suborder.html。
*/
class IntExpArriveSubOrderActivity :
BaseBindingActivity<ActivityIntExpArriveSubOrderBinding, IntExpArriveSubOrderViewModel>() {
override fun layoutId() = R.layout.activity_int_exp_arrive_sub_order
override fun viewModelClass() = IntExpArriveSubOrderViewModel::class.java
/** 筛选弹层显隐(仅 UI 状态) */
val filterPanelVisible = ObservableBoolean(false)
override fun initOnCreate(savedInstanceState: Bundle?) {
setBackArrow("分单明细")
binding.viewModel = viewModel
binding.activity = this
viewModel.initOnCreated(intent)
// 监听数据变化刷新列表
viewModel.displayList.observe(this) { binding.rv.refresh(it) }
}
/** 子项选中状态变化后回调(由 ViewHolder 调用) */
fun onItemCheckChanged() {
viewModel.onItemCheckChanged()
}
/** 全选按钮点击切换全部选中状态后强制刷新列表checked 为原地修改,不触发 LiveData */
fun checkAllClick() {
viewModel.checkAllClick()
binding.rv.commonAdapter()?.notifyDataSetChanged()
}
/** 卡片长按展开操作浮层View.OnLongClickListener 要求返回 Boolean */
fun showActionMenu(bean: GjcHaWb): Boolean {
bean.actionMenuVisible.set(true)
return true
}
/** 点击浮层遮罩:收起操作浮层 */
fun hideActionMenu(bean: GjcHaWb) {
bean.actionMenuVisible.set(false)
}
/** 长按菜单「重置」(单条) */
fun resetSingleClick(bean: GjcHaWb) {
bean.actionMenuVisible.set(false)
viewModel.resetSingleClick(bean)
}
fun toggleFilterPanel() {
filterPanelVisible.set(!filterPanelVisible.get())
}
fun resetFilter() {
viewModel.hnoFilter.value = ""
}
fun confirmFilter() {
filterPanelVisible.set(false)
viewModel.searchClick()
}
companion object {
@JvmStatic
fun start(context: Context, wbNo: String, haWbList: ArrayList<GjcHaWb>) {
val starter = Intent(context, IntExpArriveSubOrderActivity::class.java)
.putExtra(IntExpArriveSubOrderViewModel.KEY_WB_NO, wbNo)
.putExtra(Constant.Key.DATA, haWbList)
context.startActivity(starter)
}
}
}

View File

@@ -0,0 +1,41 @@
package com.lukouguoji.gjc.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.databinding.ActivityIntExpArriveSupplementBinding
import com.lukouguoji.gjc.viewModel.IntExpArriveSupplementViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.bean.GjcHaWb
import com.lukouguoji.module_base.common.Constant
/**
* 国际出港运抵-补充信息页5.5寸手机版专属新页,平板端无对应页面)
*
* 参照 Pad 端国际进港「收发货人信息」补充页的批量应用模式:对该运单整个 haWbList 批量应用
* 同一份收发货人表单。后端暂无保存接口,见 IntExpArriveSupplementViewModel 顶部注释。
* 对应设计稿 documents/5.5寸手持端设计文件/04_出港运抵/supplement.html。
*/
class IntExpArriveSupplementActivity :
BaseBindingActivity<ActivityIntExpArriveSupplementBinding, IntExpArriveSupplementViewModel>() {
override fun layoutId() = R.layout.activity_int_exp_arrive_supplement
override fun viewModelClass() = IntExpArriveSupplementViewModel::class.java
override fun initOnCreate(savedInstanceState: Bundle?) {
setBackArrow("补充信息")
binding.viewModel = viewModel
viewModel.initOnCreated(intent)
}
companion object {
@JvmStatic
fun start(context: Context, wbNo: String, haWbList: ArrayList<GjcHaWb>) {
val starter = Intent(context, IntExpArriveSupplementActivity::class.java)
.putExtra(Constant.Key.CODE, wbNo)
.putExtra(Constant.Key.DATA, haWbList)
context.startActivity(starter)
}
}
}

View File

@@ -0,0 +1,19 @@
package com.lukouguoji.gjc.holder
import android.view.View
import com.lukouguoji.gjc.databinding.ItemIntExpArriveReceiptBinding
import com.lukouguoji.module_base.base.BaseViewHolder
import com.lukouguoji.module_base.bean.GjcHaWb
/**
* 国际出港运抵-回执内容列表 ViewHolder5.5寸手机版专属只读页)
*/
class IntExpArriveReceiptViewHolder(view: View) :
BaseViewHolder<GjcHaWb, ItemIntExpArriveReceiptBinding>(view) {
override fun onBind(item: Any?, position: Int) {
val bean = getItemBean(item) ?: return
binding.bean = bean
binding.executePendingBindings()
}
}

View File

@@ -0,0 +1,32 @@
package com.lukouguoji.gjc.holder
import android.view.View
import com.lukouguoji.gjc.activity.IntExpArriveSubOrderActivity
import com.lukouguoji.gjc.databinding.ItemIntExpArriveSubOrderBinding
import com.lukouguoji.module_base.base.BaseViewHolder
import com.lukouguoji.module_base.bean.GjcHaWb
/**
* 国际出港运抵-分单明细列表 ViewHolder5.5寸手机版专属页面)
*
* 选中状态变化只影响本页自身的 ViewModel不复用全局 FlowBus.EVENT_CHECK_CHANGED
* 避免与主列表页共享同一事件、产生跨页面的无意义联动)。
*/
class IntExpArriveSubOrderViewHolder(view: View) :
BaseViewHolder<GjcHaWb, ItemIntExpArriveSubOrderBinding>(view) {
override fun onBind(item: Any?, position: Int) {
val bean = getItemBean(item) ?: return
val activity = itemView.context as? IntExpArriveSubOrderActivity
binding.bean = bean
binding.activity = activity
binding.executePendingBindings()
// 整卡点击切换选择状态
binding.ll.setOnClickListener {
bean.checked.set(!bean.checked.get())
activity?.onItemCheckChanged()
binding.executePendingBindings()
}
}
}

View File

@@ -2,6 +2,7 @@ package com.lukouguoji.gjc.holder
import android.view.View
import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.activity.IntExpArriveActivity
import com.lukouguoji.gjc.databinding.ItemIntExpArriveBinding
import com.lukouguoji.module_base.adapter.setCommonAdapter
import com.lukouguoji.module_base.base.BaseViewHolder
@@ -12,52 +13,73 @@ import com.lukouguoji.module_base.ktx.refresh
/**
* 国际出港-出港运抵 列表项ViewHolder
*
* item 布局分平板layout-sw600dp/item_int_exp_arrive.xml内嵌分单子列表 rv_sub 展开/收起)
* 与手机layout/item_int_exp_arrive.xml分单改为独立「分单明细」页无 rv_sub/iv_show 等 id
* 两个变体,单侧独有的 id 在 Binding 基类中为 `@Nullable`,需判空调用。
*/
class IntExpArriveViewHolder(view: View) :
BaseViewHolder<GjcMaWb, ItemIntExpArriveBinding>(view) {
override fun onBind(item: Any?, position: Int) {
val bean = getItemBean(item) ?: return
val activity = itemView.context as? IntExpArriveActivity
binding.bean = bean
binding.position = position
binding.activity = activity
binding.viewModel = activity?.itemViewModel
binding.executePendingBindings()
// 添加图标点击事件 - 切换选择状态
binding.ivIcon.setOnClickListener {
// 添加图标点击事件 - 切换选择状态(平板独有)
binding.ivIcon?.setOnClickListener {
bean.checked.set(!bean.checked.get())
FlowBus.with<String>(ConstantEvent.EVENT_CHECK_CHANGED).tryEmit("check_changed")
binding.executePendingBindings()
}
// 展开按钮点击事件
binding.ivShow.setOnClickListener {
// 展开按钮点击事件(平板独有)
binding.ivShow?.setOnClickListener {
bean.showMore.set(!bean.showMore.get())
}
// 选择圈点击事件(手机独有,仅待运抵 Tab 可见)
binding.ivSelect?.setOnClickListener {
bean.checked.set(!bean.checked.get())
activity?.onItemCheckChanged()
binding.executePendingBindings()
}
// 子列表 RecyclerView 仅平板存在,手机版分单改走独立页面
val rvSub = binding.rvSub ?: return
// 初始化子列表 RecyclerView
setCommonAdapter(
binding.rvSub,
rvSub,
IntExpArriveSubViewHolder::class.java,
R.layout.item_int_exp_arrive_sub
)
// 刷新子列表数据
val subList = bean.haWbList ?: emptyList()
binding.rvSub.refresh(subList)
rvSub.refresh(subList)
updateSubListVisibility(subList.isNotEmpty())
}
private fun updateSubListVisibility(hasData: Boolean) {
val llHeader = binding.llHeader ?: return
val dividerHeader = binding.dividerHeader ?: return
val rvSub = binding.rvSub ?: return
val tvEmpty = binding.tvEmpty ?: return
if (hasData) {
binding.llHeader.visibility = View.VISIBLE
binding.dividerHeader.visibility = View.VISIBLE
binding.rvSub.visibility = View.VISIBLE
binding.tvEmpty.visibility = View.GONE
llHeader.visibility = View.VISIBLE
dividerHeader.visibility = View.VISIBLE
rvSub.visibility = View.VISIBLE
tvEmpty.visibility = View.GONE
} else {
binding.llHeader.visibility = View.GONE
binding.dividerHeader.visibility = View.GONE
binding.rvSub.visibility = View.GONE
binding.tvEmpty.visibility = View.VISIBLE
llHeader.visibility = View.GONE
dividerHeader.visibility = View.GONE
rvSub.visibility = View.GONE
tvEmpty.visibility = View.VISIBLE
}
}
}

View File

@@ -0,0 +1,34 @@
package com.lukouguoji.gjc.viewModel
import android.content.Intent
import androidx.lifecycle.MutableLiveData
import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.holder.IntExpArriveReceiptViewHolder
import com.lukouguoji.module_base.base.BaseViewModel
import com.lukouguoji.module_base.bean.GjcHaWb
import com.lukouguoji.module_base.common.Constant
/**
* 国际出港运抵-回执内容 ViewModel5.5寸手机版专属只读页)
*
* 数据直接复用主列表页已加载的 haWbList.response / arrivalOpDate 字段,无需任何新增请求。
* 对应设计稿 documents/5.5寸手持端设计文件/04_出港运抵/receipt.html。
*/
class IntExpArriveReceiptViewModel : BaseViewModel() {
val receiptList = MutableLiveData<List<GjcHaWb>>(emptyList())
// 适配器配置
val itemViewHolder = IntExpArriveReceiptViewHolder::class.java
val itemLayoutId = R.layout.item_int_exp_arrive_receipt
@Suppress("UNCHECKED_CAST")
fun initOnCreated(intent: Intent) {
val list = intent.getSerializableExtra(Constant.Key.DATA) as? ArrayList<GjcHaWb>
// .copy() 补上被 Java 序列化跳过的 @Transient 字段checked 等),见分单明细页同款注释
receiptList.value = (list ?: emptyList())
.map { it.copy() }
.filter { !it.response.isNullOrEmpty() }
.sortedByDescending { it.arrivalOpDate }
}
}

View File

@@ -0,0 +1,137 @@
package com.lukouguoji.gjc.viewModel
import android.content.Intent
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.dialog.IntExpArriveResetDialogModel
import com.lukouguoji.gjc.holder.IntExpArriveSubOrderViewHolder
import com.lukouguoji.module_base.base.BaseViewModel
import com.lukouguoji.module_base.bean.GjcHaWb
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.common.ConstantEvent
import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.impl.FlowBus
import com.lukouguoji.module_base.ktx.launchLoadingCollect
import com.lukouguoji.module_base.ktx.showToast
import com.lukouguoji.module_base.ktx.toRequestBody
import kotlinx.coroutines.launch
/**
* 国际出港运抵-分单明细 ViewModel5.5寸手机版专属页面)
*
* 数据直接复用主列表页已加载的 haWbListIntent 传入),无需任何新增请求。
* 筛选仅「分单号」在客户端生效——航班日期/航班号/代理等字段在单个运单的分单集合内
* 恒为同一值,筛选它们没有实际意义(设计稿疑似沿用主列表筛选组件模板,未按此页场景定制)。
*/
class IntExpArriveSubOrderViewModel : BaseViewModel() {
// 运单号(页面标题辅助展示,非必需)
var wbNo: String = ""
private set
// 完整分单列表Intent 传入,不随筛选变化)
private var fullList: List<GjcHaWb> = emptyList()
// 当前展示列表(按分单号筛选后的结果)
val displayList = MutableLiveData<List<GjcHaWb>>(emptyList())
// 筛选:分单号(客户端 contains 匹配)
val hnoFilter = MutableLiveData("")
// 全选状态与已选计数
val isAllChecked = MutableLiveData(false)
val selectedCount = MutableLiveData("0")
// 适配器配置
val itemViewHolder = IntExpArriveSubOrderViewHolder::class.java
val itemLayoutId = R.layout.item_int_exp_arrive_sub_order
@Suppress("UNCHECKED_CAST")
fun initOnCreated(intent: Intent) {
wbNo = intent.getStringExtra(KEY_WB_NO).orEmpty()
val list = intent.getSerializableExtra(Constant.Key.DATA) as? ArrayList<GjcHaWb>
// Java 序列化会跳过 checked/actionMenuVisible标了 @Transient即 JVM transient 修饰符),
// 反序列化后这两个 ObservableBoolean 字段为 null。.copy() 会重新走一遍类体初始化逻辑,
// 用全新的 ObservableBoolean(false) 补上,避免全选/长按时 NPE已实机崩溃验证过
fullList = (list ?: emptyList()).map { it.copy() }
displayList.value = fullList
}
/**
* 分单号筛选(客户端 contains 匹配,非后端查询)。
*/
fun searchClick() {
val key = hnoFilter.value?.trim().orEmpty()
displayList.value = if (key.isEmpty()) {
fullList
} else {
fullList.filter { it.hno?.contains(key, ignoreCase = true) == true }
}
updateCheckAllStatus()
}
fun onItemCheckChanged() {
updateCheckAllStatus()
}
fun updateCheckAllStatus() {
val list = displayList.value ?: return
isAllChecked.value = list.isNotEmpty() && list.all { it.checked.get() }
selectedCount.value = list.count { it.checked.get() }.toString()
}
fun checkAllClick() {
val list = displayList.value ?: return
val shouldCheckAll = !isAllChecked.value!!
list.forEach { it.checked.set(shouldCheckAll) }
isAllChecked.value = shouldCheckAll
selectedCount.value = if (shouldCheckAll) list.size.toString() else "0"
}
/**
* 长按菜单「重置」(单条分单)。
*/
fun resetSingleClick(bean: GjcHaWb) {
val dialog = IntExpArriveResetDialogModel { dialogModel ->
val params = mutableMapOf<String, Any?>("haWbList" to listOf(bean))
if (dialogModel.resetStatusCode != null) {
params["restStatus"] = dialogModel.resetStatusCode
}
launchLoadingCollect({ NetApply.api.resetArriveDeclare(params.toRequestBody()) }) {
onSuccess = {
showToast("状态重置成功,请返回列表页下拉刷新查看最新状态")
viewModelScope.launch {
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
}
}
}
}
dialog.show()
}
/**
* 底部「申报」:批量申报当前选中的分单。
*/
fun declareClick() {
val selected = displayList.value?.filter { it.isSelected } ?: emptyList()
if (selected.isEmpty()) {
showToast("请选择要申报的分单")
return
}
val params = mapOf("haWbList" to selected).toRequestBody()
launchLoadingCollect({ NetApply.api.arriveDeclare(params) }) {
onSuccess = {
showToast("运抵申报成功")
viewModelScope.launch {
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
}
getTopActivity().finish()
}
}
}
companion object {
const val KEY_WB_NO = "wbNo"
}
}

View File

@@ -0,0 +1,119 @@
package com.lukouguoji.gjc.viewModel
import android.content.Intent
import androidx.lifecycle.MutableLiveData
import com.lukouguoji.module_base.base.BaseViewModel
import com.lukouguoji.module_base.bean.GjcHaWb
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.http.net.NetApply
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 com.lukouguoji.module_base.ktx.verifyNullOrEmpty
import dev.utils.app.info.KeyValue
/**
* 国际出港运抵-补充信息 ViewModel5.5寸手机版专属新页)
*
* 参照 Pad 端国际进港 [com.lukouguoji.gjj.viewModel.IntArrSupplementInfoViewModel] 的
* 「单一表单批量复制到选中列表」模式:对该运单的整个 haWbList 批量应用同一份收发货人信息。
*
* ⚠️ 后端暂无保存接口,见 [com.lukouguoji.module_base.http.net.Api.supplementArriveHaWb] 注释
* 与 documents/后端接口对接问题清单.xlsx。
*/
class IntExpArriveSupplementViewModel : BaseViewModel() {
// 表单编辑用数据对象(取首个分单填充,让用户看到已有数据)
val dataBean = MutableLiveData(GjcHaWb())
// 批量应用的目标分单列表
private var haWbList: List<GjcHaWb> = emptyList()
// 国家代码下拉列表
val countryCodeList = MutableLiveData<List<KeyValue>>(emptyList())
// 通讯方式下拉列表
val comTypeList = MutableLiveData<List<KeyValue>>(emptyList())
@Suppress("UNCHECKED_CAST")
fun initOnCreated(intent: Intent) {
val list = intent.getSerializableExtra(Constant.Key.DATA) as? ArrayList<GjcHaWb>
// .copy() 补上被 Java 序列化跳过的 @Transient 字段checked 等),见分单明细页同款注释
haWbList = (list ?: emptyList()).map { it.copy() }
dataBean.value = haWbList.firstOrNull()?.copy() ?: GjcHaWb()
loadCountryCodeList()
loadComTypeList()
}
private fun loadCountryCodeList() {
launchCollect({ NetApply.api.getCountryCodeList() }) {
onSuccess = { result ->
countryCodeList.value = result.data?.mapNotNull { bean ->
if (bean.code != null && bean.name != null) KeyValue(bean.name, bean.code) else null
} ?: emptyList()
}
}
}
private fun loadComTypeList() {
launchCollect({ NetApply.api.getCommunicateTypeList() }) {
onSuccess = { result ->
comTypeList.value = result.data?.mapNotNull { bean ->
if (bean.code != null && bean.name != null) KeyValue(bean.name, bean.code) else null
} ?: emptyList()
}
}
}
fun cancel() {
getTopActivity().finish()
}
/**
* 保存按钮点击 - 将表单信息复制到该运单的所有分单,批量提交。
*/
fun save() {
val formBean = dataBean.value ?: return
if (formBean.consigneeName.verifyNullOrEmpty("收货人名称不能为空")) return
if (formBean.consigneeCountryCode.verifyNullOrEmpty("收货人国家代码不能为空")) return
if (formBean.consigneeComType.verifyNullOrEmpty("收货人通讯方式不能为空")) return
if (formBean.consigneePnum.verifyNullOrEmpty("收货人联系号码不能为空")) return
if (formBean.consignorName.verifyNullOrEmpty("发货人名称不能为空")) return
if (formBean.consignorCountryCode.verifyNullOrEmpty("发货人国家代码不能为空")) return
if (formBean.consignorComType.verifyNullOrEmpty("发货人通讯方式不能为空")) return
if (formBean.consignorPnum.verifyNullOrEmpty("发货人联系号码不能为空")) return
if (haWbList.isEmpty()) {
showToast("无可保存的分单数据")
return
}
val updatedList = haWbList.map { haWb ->
haWb.copy(
consigneeName = formBean.consigneeName,
consigneeCountryCode = formBean.consigneeCountryCode,
consigneeComType = formBean.consigneeComType,
consigneePnum = formBean.consigneePnum,
consigneeAddress = formBean.consigneeAddress,
consignorName = formBean.consignorName,
consignorCountryCode = formBean.consignorCountryCode,
consignorComType = formBean.consignorComType,
consignorPnum = formBean.consignorPnum,
consignorAddress = formBean.consignorAddress
)
}
launchLoadingCollect({ NetApply.api.supplementArriveHaWb(updatedList.toRequestBody()) }) {
onSuccess = {
showToast("保存成功")
getTopActivity().finish()
}
onFailed = { code, msg ->
showToast("保存失败:$msg(后端接口暂未支持,见接口问题清单)")
}
}
}
}

View File

@@ -20,6 +20,7 @@ import com.lukouguoji.module_base.ktx.launchLoadingCollect
import com.lukouguoji.module_base.ktx.showToast
import com.lukouguoji.module_base.ktx.toRequestBody
import com.lukouguoji.module_base.model.ScanModel
import dev.utils.app.info.KeyValue
import dev.utils.common.DateUtils
import com.lukouguoji.module_base.ktx.formatDate
import kotlinx.coroutines.launch
@@ -45,6 +46,7 @@ class IntExpArriveViewModel : BasePageViewModel() {
fun onItemCheckChanged() {
updateCheckAllStatus()
updateCheckAllStatusPhone()
}
fun updateCheckAllStatus() {
@@ -52,6 +54,101 @@ class IntExpArriveViewModel : BasePageViewModel() {
isAllChecked.value = list.isNotEmpty() && list.all { it.checked.get() }
}
// ========== 5.5寸手机版专属(平板布局不引用,零影响) ==========
/** 当前 Tab"pending"(待运抵) / "shipped"(已运抵)。接口无申报状态查询参数Tab 由客户端对已加载数据拆分 */
val currentTab = MutableLiveData("pending")
/** Tab 配置 */
val arriveTabs = MutableLiveData(
listOf(KeyValue("待运抵", "pending"), KeyValue("已运抵", "shipped"))
)
/** 两个 Tab 的角标计数(当前已加载数据的客户端统计,非全量,见接口问题清单) */
val arriveTabCounts = MutableLiveData(listOf("", ""))
/** 手机版全选状态(仅统计待运抵 Tab 内的项,与 Pad 端 [isAllChecked] 统计口径不同) */
val isAllCheckedPhone = MutableLiveData(false)
/** 手机版已选数量(底部操作条「已选 N 项」) */
val selectedCountPhone = MutableLiveData("0")
/** 手机版筛选弹层「代理」(后端 pageQuery 支持 agentCode 入参,复用既有 agentCode 语义查询) */
val agentCodePhone = MutableLiveData("")
val agentListPhone = MutableLiveData<List<KeyValue>>(emptyList())
private var phoneExtrasEnabled = false
/**
* 完整已加载列表(跨分页累计,未按 Tab 过滤)。
*
* ⚠️ RecyclerView/LinearLayoutManager 不会像普通 ViewGroup 那样让 `View.GONE` 的子项
* 自动塌陷为 0 高度——它仍按子项的测量高度参与滚动区域计算,导致"隐藏"的卡片在列表里
* 留下一段空白(已实机截图验证)。因此 Tab 切换不能靠给 item 加 visibility 绑定,
* 必须真正地把适配器的数据集替换成过滤后的子集([applyTabFilterPhone])。
*/
private var allLoadedList: List<GjcMaWb> = emptyList()
/**
* 开启手机版专属数据:加载「代理」筛选下拉。仅由手机形态的 Activity 调用。
*/
fun initPhoneExtras() {
phoneExtrasEnabled = true
launchCollect({ NetApply.api.getIntExpAgentList() }) {
onSuccess = { result ->
agentListPhone.postValue(
listOf(KeyValue("全部", "")) + (result.data ?: emptyList()).map { KeyValue(it.name ?: "", it.code ?: "") }
)
}
}
}
/**
* 手机版 Tab 切换:将适配器数据集替换为过滤后的子集(不重新请求)。
* 由 Activity 在 [com.lukouguoji.module_base.ui.weight.phone.PhoneStatusTab] 的
* 双向绑定写入 currentTab 后调用。
*/
fun onTabChangedPhone() {
applyTabFilterPhone()
}
private fun applyTabFilterPhone() {
val isPendingTab = currentTab.value == "pending"
val filtered = allLoadedList.filter { it.isPending == isPendingTab }
pageModel.rv?.commonAdapter()?.refresh(filtered)
updateCheckAllStatusPhone()
}
/**
* 根据完整已加载列表重新计算 Tab 角标计数(每次数据变化后调用)。
*/
private fun updatePhoneTabCounts() {
val pending = allLoadedList.count { it.isPending }.toString()
val shipped = allLoadedList.count { !it.isPending }.toString()
arriveTabCounts.value = listOf(pending, shipped)
}
/**
* 手机版全选(适配器此时已只包含当前 Tab 的子集,待运抵 Tab 下即为全部可选项)。
*/
fun checkAllClickPhone() {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjcMaWb> ?: return
val shouldCheckAll = !isAllCheckedPhone.value!!
list.forEach { it.checked.set(shouldCheckAll) }
isAllCheckedPhone.value = shouldCheckAll
updateCheckAllStatusPhone()
pageModel.rv?.commonAdapter()?.notifyDataSetChanged()
}
/**
* 更新手机版全选状态与已选计数(基于适配器当前子集,即当前 Tab 的数据)。
*/
fun updateCheckAllStatusPhone() {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjcMaWb> ?: return
isAllCheckedPhone.value = list.isNotEmpty() && list.all { it.checked.get() }
selectedCountPhone.value = list.count { it.checked.get() }.toString()
}
// ========== 全局展开状态 ==========
/**
* 全局展开状态
@@ -292,18 +389,53 @@ class IntExpArriveViewModel : BasePageViewModel() {
}
}
/**
* 手机版:卡片长按菜单「重置」(单条,已运抵 Tab 专用,对应设计稿长按浮层)。
*/
fun resetSingleDeclareClick(bean: GjcMaWb) {
bean.actionMenuVisible.set(false)
val dialog = IntExpArriveResetDialogModel { dialogModel ->
val params = mutableMapOf<String, Any?>("maWbList" to listOf(bean))
if (dialogModel.resetStatusCode != null) {
params["restStatus"] = dialogModel.resetStatusCode
}
launchLoadingCollect({ NetApply.api.resetArriveDeclare(params.toRequestBody()) }) {
onSuccess = {
showToast("状态重置成功")
viewModelScope.launch {
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
}
refresh()
}
}
}
dialog.show()
}
/**
* 获取数据 (重写BasePageViewModel)
*/
override fun getData() {
// 构建搜索条件
val filterParams = mapOf(
val filterParams = mutableMapOf<String, Any?>(
"fdate" to flightDate.value?.ifEmpty { null },
"fno" to flightNo.value?.ifEmpty { null },
"wbNo" to waybillNo.value?.ifEmpty { null },
"hno" to hno.value?.ifEmpty { null }
)
// 手机版专属条件(平板 phoneExtrasEnabled 恒为 false请求体与改造前完全一致
if (phoneExtrasEnabled) {
// 搜索分流与出港计重页一致11 位数字精确匹配 wbNo其余走 likeNo 模糊
val key = waybillNo.value?.trim() ?: ""
if (key.isNotEmpty() && key.length != 11) {
filterParams["wbNo"] = null
filterParams["likeNo"] = key
}
filterParams["agentCode"] = agentCodePhone.value?.ifEmpty { null }
}
// 列表参数 (含分页)
val listParams = (filterParams + mapOf(
"pageNum" to pageModel.page,
@@ -315,8 +447,21 @@ class IntExpArriveViewModel : BasePageViewModel() {
// 获取列表 (带Loading)
launchLoadingCollect({ NetApply.api.getIntExpArriveList(listParams) }) {
onSuccess = {
pageModel.handleListBean(it) { updateCheckAllStatus() }
onSuccess = { result ->
// 手机版:自行维护完整累计列表(不依赖 adapter.items 的历史状态,见 allLoadedList 注释)
if (phoneExtrasEnabled) {
val newPageItems = result.list ?: emptyList()
allLoadedList = if (pageModel.page <= 1) newPageItems else allLoadedList + newPageItems
}
pageModel.handleListBean(result) {
updateCheckAllStatus()
if (phoneExtrasEnabled) {
// 用完整列表强制覆盖 adapter 数据集为当前 Tab 的过滤子集
applyTabFilterPhone()
updatePhoneTabCounts()
}
}
// 数据加载完成后,重置全局展开状态为收起
isAllExpanded.value = false
}

View File

@@ -0,0 +1,244 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="com.lukouguoji.module_base.ui.weight.search.layout.SearchLayoutType" />
<import type="com.lukouguoji.module_base.R" />
<variable
name="viewModel"
type="com.lukouguoji.gjc.viewModel.IntExpArriveViewModel" />
<!-- 平板端不使用仅为与手机变体layout/activity_int_exp_arrive.xml保持变量一致 -->
<variable
name="activity"
type="com.lukouguoji.gjc.activity.IntExpArriveActivity" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_f2"
android:orientation="vertical">
<include layout="@layout/title_tool_bar" />
<!-- 搜索区域 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp"
android:layout_marginTop="10dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<!-- 航班日期 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"请选择航班日期"}'
icon="@{@drawable/img_date}"
type="@{SearchLayoutType.DATE}"
value="@={viewModel.flightDate}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<!-- 航班号 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"请输入航班号"}'
type="@{SearchLayoutType.INPUT}"
value="@={viewModel.flightNo}"
setUpperCaseAlphanumeric="@{true}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<!-- 运单号 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"请输入运单号"}'
icon="@{@drawable/img_scan}"
setOnIconClickListener="@{(v)-> viewModel.scanWaybill()}"
type="@{SearchLayoutType.INPUT}"
value="@={viewModel.waybillNo}"
autoQueryEnabled="@{true}"
autoQueryUrl="@{`/IntExpArrive/queryWbNoList`}"
autoQueryParamKey="@{`wbNo`}"
autoQueryMinLength="@{4}"
autoQueryMaxLength="@{8}"
autoQueryTitle="@{`选择运单号`}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<!-- 分单号 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"请输入分单号"}'
icon="@{@drawable/img_scan}"
setOnIconClickListener="@{(v)-> viewModel.scanHaWb()}"
type="@{SearchLayoutType.INPUT}"
value="@={viewModel.hno}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<!-- 搜索按钮 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical|start"
android:orientation="horizontal"
android:paddingHorizontal="24dp">
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:onClick="@{()-> viewModel.searchClick()}"
android:padding="2dp"
android:src="@drawable/img_search" />
<!-- 全局展开/收起按钮 -->
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginStart="16dp"
android:onClick="@{()-> viewModel.toggleAllExpand()}"
android:padding="2dp"
android:scaleType="fitCenter"
loadImage="@{viewModel.isAllExpanded ? R.drawable.ic_new_expand_1 : R.drawable.ic_new_expand_1}"
android:contentDescription="展开/收起全部子列表" />
</LinearLayout>
</LinearLayout>
<!-- 列表 -->
<com.scwang.smart.refresh.layout.SmartRefreshLayout
android:id="@+id/srl"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginHorizontal="10dp"
android:layout_marginTop="10dp"
android:layout_weight="1">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
itemLayoutId="@{viewModel.itemLayoutId}"
viewHolder="@{viewModel.itemViewHolder}"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:itemCount="3"
tools:listitem="@layout/item_int_exp_arrive" />
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
<!-- 底部统计和操作按钮 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@android:color/white"
android:gravity="center_vertical"
android:paddingHorizontal="15dp">
<!-- 全选按钮 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:gravity="center_vertical"
android:onClick="@{()-> viewModel.checkAllClick()}"
android:orientation="horizontal">
<ImageView
android:id="@+id/checkIcon"
setIVCheckAllImage="@{viewModel.isAllChecked}"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="5dp"
android:src="@drawable/img_check_all_unchecked" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="全选"
android:textColor="@color/color_66"
android:textSize="18sp" />
</LinearLayout>
<!-- 统计信息 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text='@{"合计:"+viewModel.totalCount+"票"}'
android:textColor="@color/bottom_tool_tips_text_color"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text='@{"总件数:"+viewModel.totalPc}'
android:textColor="@color/bottom_tool_tips_text_color"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text='@{"总重量:"+viewModel.totalWeight}'
android:textColor="@color/bottom_tool_tips_text_color"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
<!-- 批量操作按钮组 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
style="@style/tv_bottom_btn"
android:layout_marginEnd="15dp"
android:onClick="@{()-> viewModel.resetDeclareClick()}"
android:text="状态重置" />
<TextView
style="@style/tv_bottom_btn"
android:layout_marginLeft="0dp"
android:layout_marginEnd="15dp"
android:onClick="@{()-> viewModel.deleteDeclareClick()}"
android:text="删除申报" />
<TextView
style="@style/tv_bottom_btn"
android:layout_marginLeft="0dp"
android:background="@drawable/bg_red_btn_bottom"
android:onClick="@{()-> viewModel.arriveReportClick()}"
android:text="运抵申报" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</layout>

View File

@@ -0,0 +1,520 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="android.view.View" />
<variable
name="bean"
type="com.lukouguoji.module_base.bean.GjcMaWb" />
<variable
name="position"
type="Integer" />
<!-- 以下两个变量平板端不使用仅为与手机变体layout/item_int_exp_arrive.xml保持变量一致 -->
<variable
name="activity"
type="com.lukouguoji.gjc.activity.IntExpArriveActivity" />
<variable
name="viewModel"
type="com.lukouguoji.gjc.viewModel.IntExpArriveViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp"
android:layout_marginTop="10dp"
android:orientation="vertical">
<!-- 白色卡片 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_white_radius_8"
android:orientation="vertical">
<!-- 主要内容区域 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingVertical="20dp"
android:paddingHorizontal="10dp">
<!-- 选中图标 (飞机图标,根据选择状态切换图片) -->
<ImageView
android:id="@+id/iv_icon"
loadImage="@{bean.checked.get() ? @drawable/img_plane_s : @drawable/img_plane}"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginTop="0.5px"
android:layout_gravity="center"
android:src="@drawable/img_plane" />
<!-- 运单信息区域 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_weight="0.8"
android:orientation="vertical">
<!-- 第一行:运单号、状态、代理、件数、重量 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<!-- 运单号 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
completeSpace="@{4}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="运单号:"
android:textColor="@color/text_normal"
android:textSize="15sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{bean.wbNo}"
android:textColor="@color/colorPrimary"
android:textSize="15sp"
android:textStyle="bold" />
</LinearLayout>
<!-- 状态 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
completeSpace="@{5}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="状态:"
android:textColor="@color/text_normal"
android:textSize="15sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@{`01`.equals(bean.declareStatus) ? @drawable/tag_status_green : (`W`.equals(bean.declareStatus) ? @drawable/tag_status_blue : @drawable/tag_status_gray)}"
android:paddingHorizontal="8dp"
android:paddingVertical="2dp"
android:text="@{bean.declareStatus}"
android:textColor="@{`01`.equals(bean.declareStatus) ? @color/text_green : (`W`.equals(bean.declareStatus) ? @color/colorPrimary : @color/text_gray)}"
android:textSize="14sp"
android:visibility="@{bean.declareStatus != null &amp;&amp; !bean.declareStatus.isEmpty() ? View.VISIBLE : View.GONE}" />
</LinearLayout>
<!-- 代理 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
completeSpace="@{5}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="代理:"
android:textColor="@color/text_normal"
android:textSize="15sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
android:maxLines="1"
android:text="@{bean.agentName}"
android:textColor="@color/text_normal"
android:textSize="15sp" />
</LinearLayout>
<!-- 件数 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
completeSpace="@{5}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="件数:"
android:textColor="@color/text_normal"
android:textSize="15sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(bean.pc)}"
android:textColor="@color/text_normal"
android:textSize="15sp" />
</LinearLayout>
<!-- 重量 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
completeSpace="@{4}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="重量:"
android:textColor="@color/text_normal"
android:textSize="15sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf((int)bean.weight)}"
android:textColor="@color/text_normal"
android:textSize="15sp" />
</LinearLayout>
</LinearLayout>
<!-- 第二行:航程、计重状态、运抵状态、运单类型、分单数 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<!-- 航程 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
completeSpace="@{4}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="航程:"
android:textColor="@color/text_normal"
android:textSize="15sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{bean.range}"
android:textColor="@color/text_normal"
android:textSize="15sp" />
</LinearLayout>
<!-- 计重状态 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
completeSpace="@{5}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="计重状态:"
android:textColor="@color/text_normal"
android:textSize="15sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@{`1`.equals(bean.checkIn) ? @drawable/tag_status_green : (`2`.equals(bean.checkIn) ? @drawable/tag_status_blue : @drawable/tag_status_gray)}"
android:paddingHorizontal="8dp"
android:paddingVertical="2dp"
android:text="@{bean.checkInText}"
android:textColor="@{`1`.equals(bean.checkIn) ? @color/text_green : (`2`.equals(bean.checkIn) ? @color/colorPrimary : @color/text_gray)}"
android:textSize="14sp"
android:visibility="@{bean.checkIn != null &amp;&amp; !bean.checkIn.isEmpty() ? View.VISIBLE : View.GONE}" />
</LinearLayout>
<!-- 运抵状态 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
completeSpace="@{5}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="运抵状态:"
android:textColor="@color/text_normal"
android:textSize="15sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@{`0`.equals(bean.arriveFlag) ? @drawable/tag_status_green : (`1`.equals(bean.arriveFlag) ? @drawable/tag_status_orange : @drawable/tag_status_gray)}"
android:paddingHorizontal="8dp"
android:paddingVertical="2dp"
android:text="@{bean.arriveFlagText}"
android:textColor="@{`0`.equals(bean.arriveFlag) ? @color/text_green : (`1`.equals(bean.arriveFlag) ? @color/text_orange : @color/text_gray)}"
android:textSize="14sp"
android:visibility="@{bean.arriveFlag != null &amp;&amp; !bean.arriveFlag.isEmpty() ? View.VISIBLE : View.GONE}" />
</LinearLayout>
<!-- 运单类型 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
completeSpace="@{5}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="运单类型:"
android:textColor="@color/text_normal"
android:textSize="15sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{bean.awbName}"
android:textColor="@color/text_normal"
android:textSize="15sp" />
</LinearLayout>
<!-- 分单数 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
completeSpace="@{4}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="分单数:"
android:textColor="@color/text_normal"
android:textSize="15sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(bean.haWbNumber)}"
android:textColor="@color/text_normal"
android:textSize="15sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<!-- 展开按钮 -->
<ImageView
android:id="@+id/iv_show"
android:layout_width="match_parent"
android:layout_height="20dp"
android:paddingVertical="2.5dp"
android:layout_marginTop="-20dp"
android:scaleType="center"
android:src="@mipmap/img_down" />
</LinearLayout>
<!-- 子订单列表容器(白色圆角卡片,圆角同主单) -->
<LinearLayout
visible="@{bean.showMore}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:background="@drawable/bg_white_radius_8"
android:orientation="vertical"
android:visibility="gone">
<!-- 暂无数据提示 -->
<TextView
android:id="@+id/tv_empty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingVertical="15dp"
android:text="暂无分单数据"
android:textColor="@color/text_gray"
android:textSize="14sp"
android:visibility="gone" />
<!-- 表头(浅蓝色背景,仅 Title 有背景色,顶部圆角同卡片) -->
<LinearLayout
android:id="@+id/ll_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_arrive_sub_header"
android:orientation="horizontal"
android:paddingHorizontal="10dp"
android:paddingVertical="10dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:gravity="center"
android:text="选项"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.2"
android:gravity="center"
android:text="分单号"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:gravity="center"
android:text="件数"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:gravity="center"
android:text="重量(KG)"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="申报状态"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="品名(中)"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.9"
android:gravity="center"
android:text="申报次数"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.9"
android:gravity="center"
android:text="申报费率"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.9"
android:gravity="center"
android:text="删除次数"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.9"
android:gravity="center"
android:text="删除费率"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
</LinearLayout>
<com.google.android.material.divider.MaterialDivider
android:id="@+id/divider_header"
android:layout_width="match_parent"
android:layout_height="1px"
app:dividerColor="@color/sub_list_divider" />
<!-- 子列表 RecyclerView -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_sub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@@ -1,239 +1,161 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="com.lukouguoji.module_base.ui.weight.search.layout.SearchLayoutType" />
<import type="com.lukouguoji.module_base.R" />
<variable
name="viewModel"
type="com.lukouguoji.gjc.viewModel.IntExpArriveViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_f2"
android:orientation="vertical">
<include layout="@layout/title_tool_bar" />
<!-- 搜索区域 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp"
android:layout_marginTop="10dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<!-- 航班日期 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"请选择航班日期"}'
icon="@{@drawable/img_date}"
type="@{SearchLayoutType.DATE}"
value="@={viewModel.flightDate}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<!-- 航班号 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"请输入航班号"}'
type="@{SearchLayoutType.INPUT}"
value="@={viewModel.flightNo}"
setUpperCaseAlphanumeric="@{true}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<!-- 运单号 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"请输入运单号"}'
icon="@{@drawable/img_scan}"
setOnIconClickListener="@{(v)-> viewModel.scanWaybill()}"
type="@{SearchLayoutType.INPUT}"
value="@={viewModel.waybillNo}"
autoQueryEnabled="@{true}"
autoQueryUrl="@{`/IntExpArrive/queryWbNoList`}"
autoQueryParamKey="@{`wbNo`}"
autoQueryMinLength="@{4}"
autoQueryMaxLength="@{8}"
autoQueryTitle="@{`选择运单号`}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<!-- 分单号 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"请输入分单号"}'
icon="@{@drawable/img_scan}"
setOnIconClickListener="@{(v)-> viewModel.scanHaWb()}"
type="@{SearchLayoutType.INPUT}"
value="@={viewModel.hno}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<!-- 搜索按钮 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical|start"
android:orientation="horizontal"
android:paddingHorizontal="24dp">
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:onClick="@{()-> viewModel.searchClick()}"
android:padding="2dp"
android:src="@drawable/img_search" />
<!-- 全局展开/收起按钮 -->
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginStart="16dp"
android:onClick="@{()-> viewModel.toggleAllExpand()}"
android:padding="2dp"
android:scaleType="fitCenter"
loadImage="@{viewModel.isAllExpanded ? R.drawable.ic_new_expand_1 : R.drawable.ic_new_expand_1}"
android:contentDescription="展开/收起全部子列表" />
</LinearLayout>
</LinearLayout>
<!-- 列表 -->
<com.scwang.smart.refresh.layout.SmartRefreshLayout
android:id="@+id/srl"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginHorizontal="10dp"
android:layout_marginTop="10dp"
android:layout_weight="1">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
itemLayoutId="@{viewModel.itemLayoutId}"
viewHolder="@{viewModel.itemViewHolder}"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:itemCount="3"
tools:listitem="@layout/item_int_exp_arrive" />
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
<!-- 底部统计和操作按钮 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@android:color/white"
android:gravity="center_vertical"
android:paddingHorizontal="15dp">
<!-- 全选按钮 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:gravity="center_vertical"
android:onClick="@{()-> viewModel.checkAllClick()}"
android:orientation="horizontal">
<ImageView
android:id="@+id/checkIcon"
setIVCheckAllImage="@{viewModel.isAllChecked}"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="5dp"
android:src="@drawable/img_check_all_unchecked" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="全选"
android:textColor="@color/color_66"
android:textSize="18sp" />
</LinearLayout>
<!-- 统计信息 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text='@{"合计:"+viewModel.totalCount+"票"}'
android:textColor="@color/bottom_tool_tips_text_color"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text='@{"总件数:"+viewModel.totalPc}'
android:textColor="@color/bottom_tool_tips_text_color"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text='@{"总重量:"+viewModel.totalWeight}'
android:textColor="@color/bottom_tool_tips_text_color"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
<!-- 批量操作按钮组 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
style="@style/tv_bottom_btn"
android:layout_marginEnd="15dp"
android:onClick="@{()-> viewModel.resetDeclareClick()}"
android:text="状态重置" />
<TextView
style="@style/tv_bottom_btn"
android:layout_marginLeft="0dp"
android:layout_marginEnd="15dp"
android:onClick="@{()-> viewModel.deleteDeclareClick()}"
android:text="删除申报" />
<TextView
style="@style/tv_bottom_btn"
android:layout_marginLeft="0dp"
android:background="@drawable/bg_red_btn_bottom"
android:onClick="@{()-> viewModel.arriveReportClick()}"
android:text="运抵申报" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</layout>
<?xml version="1.0" encoding="utf-8"?>
<!--
国际出港运抵 —— 手机版布局5.5 寸手持端,最小宽度 < 600dp 时生效)
平板版为同名文件 layout-sw600dp/activity_int_exp_arrive.xml两者是同一布局的资源变体
DataBinding 因此生成同一个 ActivityIntExpArriveBinding 类。
变体之间必须满足:
· DataBinding 变量完全一致viewModel / activity
· 保留 Activity 中引用的控件 idsrl / rv
→ IntExpArriveViewModel 的业务逻辑与接口调用全部复用,平板端行为不受影响
交互差异(均复用既有 ViewModel 字段与接口,或为纯客户端拆分,零新增请求):
· 平板 4 个横排搜索条 → 手机顶部搜索框(运单号)+ 底部筛选弹层(航班日期/航班号/代理)
· 新增「待运抵 / 已运抵」Tab客户端按 declareStatus 是否为空拆分,接口无此查询参数)
· 平板内嵌分单展开列表 → 手机「查看分单」按钮进入独立「分单明细」页
· 平板常驻底部全选+状态重置+删除申报+运抵申报 → 手机仅待运抵 Tab 显示全选+申报;
状态重置/回执改为卡片长按浮层(已运抵 Tab删除申报设计稿未提供手机端不可用
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View" />
<variable
name="viewModel"
type="com.lukouguoji.gjc.viewModel.IntExpArriveViewModel" />
<variable
name="activity"
type="com.lukouguoji.gjc.activity.IntExpArriveActivity" />
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/phone_page_bg">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/title_tool_bar" />
<!-- ==================== 搜索行 ==================== -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:orientation="vertical"
android:paddingHorizontal="16dp"
android:paddingTop="16dp"
android:paddingBottom="12dp">
<com.lukouguoji.module_base.ui.weight.phone.PhoneSearchBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
hint='@{"搜索运单号"}'
setOnFilterClickListener="@{(v)-> activity.toggleFilterPanel()}"
setOnScanClickListener="@{(v)-> viewModel.scanWaybill()}"
setRefreshCallBack="@{viewModel::searchClick}"
upperCase="@{true}"
value="@={viewModel.waybillNo}" />
</LinearLayout>
<!-- ==================== 待运抵 / 已运抵 Tab ==================== -->
<com.lukouguoji.module_base.ui.weight.phone.PhoneStatusTab
android:layout_width="match_parent"
android:layout_height="wrap_content"
counts="@{viewModel.arriveTabCounts}"
setOnTabChanged="@{()-> activity.onArriveTabChanged()}"
tabs="@{viewModel.arriveTabs}"
value="@={viewModel.currentTab}" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/phone_divider" />
<!-- ==================== 列表 ==================== -->
<com.scwang.smart.refresh.layout.SmartRefreshLayout
android:id="@+id/srl"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:overScrollMode="never"
android:paddingTop="4dp"
android:paddingBottom="12dp"
itemLayoutId="@{viewModel.itemLayoutId}"
viewHolder="@{viewModel.itemViewHolder}"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:itemCount="2"
tools:listitem="@layout/item_int_exp_arrive" />
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
<!-- ==================== 底部操作条(仅待运抵 Tab 显示) ==================== -->
<com.lukouguoji.module_base.ui.weight.phone.PhoneBottomBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
actionText='@{"申报"}'
allChecked="@{viewModel.isAllCheckedPhone}"
countText='@{"已选 " + viewModel.selectedCountPhone + " 项"}'
android:visibility="@{`pending`.equals(viewModel.currentTab) ? View.VISIBLE : View.GONE}"
setOnActionClick="@{(v)-> viewModel.arriveReportClick()}"
setOnAllCheckClick="@{(v)-> viewModel.checkAllClickPhone()}" />
</LinearLayout>
<!-- ==================== 筛选弹层 ==================== -->
<com.lukouguoji.module_base.ui.weight.phone.PhoneFilterPanel
android:layout_width="match_parent"
android:layout_height="match_parent"
android:elevation="8dp"
panelVisible="@{activity.filterPanelVisible}"
setOnConfirmClick="@{(v)-> activity.confirmFilter()}"
setOnDismissClick="@{(v)-> activity.toggleFilterPanel()}"
setOnResetClick="@{(v)-> activity.resetFilter()}"
title='@{"筛选条件"}'>
<com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
hint='@{"请选择航班日期"}'
title='@{"航班日期"}'
type="@{com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayoutType.DATE}"
value="@={viewModel.flightDate}" />
<com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
hint='@{"请输入航班号"}'
title='@{"航班号"}'
type="@{com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayoutType.INPUT}"
value="@={viewModel.flightNo}" />
<com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
hint='@{"请选择代理"}'
list="@{viewModel.agentListPhone}"
title='@{"代理"}'
type="@{com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayoutType.SPINNER}"
value="@={viewModel.agentCodePhone}" />
</com.lukouguoji.module_base.ui.weight.phone.PhoneFilterPanel>
</FrameLayout>
</layout>

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
国际出港运抵-回执内容 —— 5.5 寸手机版专属只读新页(平板端无对应页面)
数据来自主列表页已加载的 GjcMaWb.haWbList[].response / arrivalOpDate零新增请求。
对应设计稿 documents/5.5寸手持端设计文件/04_出港运抵/receipt.html。
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="com.lukouguoji.gjc.viewModel.IntExpArriveReceiptViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/phone_page_bg"
android:orientation="vertical">
<include layout="@layout/title_tool_bar" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:clipToPadding="false"
android:overScrollMode="never"
android:paddingTop="12dp"
android:paddingBottom="16dp"
itemLayoutId="@{viewModel.itemLayoutId}"
viewHolder="@{viewModel.itemViewHolder}"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:itemCount="3"
tools:listitem="@layout/item_int_exp_arrive_receipt" />
</LinearLayout>
</layout>

View File

@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
国际出港运抵-分单明细 —— 5.5 寸手机版专属新页(平板端无对应页面,分单在平板上内嵌展开于主列表)
数据来自主列表页已加载的 GjcMaWb.haWbListIntent 传入),不发起任何新增网络请求。
对应设计稿 documents/5.5寸手持端设计文件/04_出港运抵/suborder.html。
与设计稿的差异:
· 筛选弹层设计稿含"航班日期/航班号/代理"三项,但本页数据是单个运单的分单集合,
这三项在集合内恒为同一值,筛选无实际意义(判断为设计稿沿用主列表筛选组件模板未定制),
故只保留真正可筛选的「分单号」
· 搜索框设计稿占位符字面是"搜索运单号"(同样的模板复用),本页按实际语义改为"搜索分单号"
并去掉扫码图标(此场景无可扫描目标)
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="com.lukouguoji.gjc.viewModel.IntExpArriveSubOrderViewModel" />
<variable
name="activity"
type="com.lukouguoji.gjc.activity.IntExpArriveSubOrderActivity" />
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/phone_page_bg">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/title_tool_bar" />
<!-- ==================== 搜索行 ==================== -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:orientation="vertical"
android:paddingHorizontal="16dp"
android:paddingTop="16dp"
android:paddingBottom="12dp">
<com.lukouguoji.module_base.ui.weight.phone.PhoneSearchBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
hint='@{"搜索分单号"}'
setOnFilterClickListener="@{(v)-> activity.toggleFilterPanel()}"
setRefreshCallBack="@{viewModel::searchClick}"
showScan="@{false}"
value="@={viewModel.hnoFilter}" />
</LinearLayout>
<!-- ==================== 列表 ==================== -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:clipToPadding="false"
android:overScrollMode="never"
android:paddingTop="4dp"
android:paddingBottom="12dp"
itemLayoutId="@{viewModel.itemLayoutId}"
viewHolder="@{viewModel.itemViewHolder}"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:itemCount="3"
tools:listitem="@layout/item_int_exp_arrive_sub_order" />
<!-- ==================== 底部操作条 ==================== -->
<com.lukouguoji.module_base.ui.weight.phone.PhoneBottomBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
actionText='@{"申报"}'
allChecked="@{viewModel.isAllChecked}"
countText='@{"已选 " + viewModel.selectedCount + " 项"}'
setOnActionClick="@{(v)-> viewModel.declareClick()}"
setOnAllCheckClick="@{(v)-> activity.checkAllClick()}" />
</LinearLayout>
<!-- ==================== 筛选弹层 ==================== -->
<com.lukouguoji.module_base.ui.weight.phone.PhoneFilterPanel
android:layout_width="match_parent"
android:layout_height="match_parent"
android:elevation="8dp"
panelVisible="@{activity.filterPanelVisible}"
setOnConfirmClick="@{(v)-> activity.confirmFilter()}"
setOnDismissClick="@{(v)-> activity.toggleFilterPanel()}"
setOnResetClick="@{(v)-> activity.resetFilter()}"
title='@{"筛选条件"}'>
<com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
hint='@{"请输入分单号"}'
title='@{"分单号"}'
type="@{com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayoutType.INPUT}"
value="@={viewModel.hnoFilter}" />
</com.lukouguoji.module_base.ui.weight.phone.PhoneFilterPanel>
</FrameLayout>
</layout>

View File

@@ -0,0 +1,219 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
国际出港运抵-补充信息 —— 5.5 寸手机版专属新页(平板端无对应页面)
参照 Pad 端国际进港「收发货人信息」补充页IntArrSupplementInfoActivity的批量应用模式
对该运单整个 haWbList 批量应用同一份表单。后端暂无保存接口,见 ViewModel 顶部注释与
documents/后端接口对接问题清单.xlsx。对应设计稿 04_出港运抵/supplement.html。
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="com.lukouguoji.module_base.ui.weight.phone.PhoneFormRowType" />
<variable
name="viewModel"
type="com.lukouguoji.gjc.viewModel.IntExpArriveSupplementViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/phone_page_bg"
android:orientation="vertical">
<include layout="@layout/title_tool_bar" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:fillViewport="true"
android:overScrollMode="never">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<!-- 收货人信息 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_phone_card"
android:orientation="vertical"
android:padding="14dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<View
android:layout_width="4dp"
android:layout_height="16dp"
android:background="@color/phone_primary" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="收货人信息"
android:textColor="@color/phone_text_strong"
android:textSize="15sp"
android:textStyle="bold" />
</LinearLayout>
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
hint='@{"请输入收货人名称"}'
required="@{true}"
title='@{"收货人名称"}'
type="@{PhoneFormRowType.INPUT}"
value="@={viewModel.dataBean.consigneeName}" />
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
hint='@{"请选择国家代码"}'
list="@{viewModel.countryCodeList}"
required="@{true}"
title='@{"国家代码"}'
type="@{PhoneFormRowType.SELECT}"
value="@={viewModel.dataBean.consigneeCountryCode}" />
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
hint='@{"请选择"}'
list="@{viewModel.comTypeList}"
required="@{true}"
title='@{"通讯方式"}'
type="@{PhoneFormRowType.SELECT}"
value="@={viewModel.dataBean.consigneeComType}" />
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
hint='@{"请输入联系号码"}'
required="@{true}"
title='@{"联系号码"}'
type="@{PhoneFormRowType.INPUT}"
value="@={viewModel.dataBean.consigneePnum}" />
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
hint='@{"请输入地址"}'
title='@{"地址"}'
type="@{PhoneFormRowType.INPUT}"
value="@={viewModel.dataBean.consigneeAddress}" />
</LinearLayout>
<!-- 发货人信息 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:background="@drawable/bg_phone_card"
android:orientation="vertical"
android:padding="14dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<View
android:layout_width="4dp"
android:layout_height="16dp"
android:background="@color/phone_primary" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="发货人信息"
android:textColor="@color/phone_text_strong"
android:textSize="15sp"
android:textStyle="bold" />
</LinearLayout>
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
hint='@{"请输入发货人名称"}'
required="@{true}"
title='@{"发货人名称"}'
type="@{PhoneFormRowType.INPUT}"
value="@={viewModel.dataBean.consignorName}" />
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
hint='@{"请选择国家代码"}'
list="@{viewModel.countryCodeList}"
required="@{true}"
title='@{"国家代码"}'
type="@{PhoneFormRowType.SELECT}"
value="@={viewModel.dataBean.consignorCountryCode}" />
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
hint='@{"请选择"}'
list="@{viewModel.comTypeList}"
required="@{true}"
title='@{"通讯方式"}'
type="@{PhoneFormRowType.SELECT}"
value="@={viewModel.dataBean.consignorComType}" />
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
hint='@{"请输入联系号码"}'
required="@{true}"
title='@{"联系号码"}'
type="@{PhoneFormRowType.INPUT}"
value="@={viewModel.dataBean.consignorPnum}" />
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
hint='@{"请输入地址"}'
title='@{"地址"}'
type="@{PhoneFormRowType.INPUT}"
value="@={viewModel.dataBean.consignorAddress}" />
</LinearLayout>
</LinearLayout>
</ScrollView>
<!-- 确定 -->
<TextView
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_margin="16dp"
android:background="@drawable/bg_phone_btn_primary"
android:gravity="center"
android:onClick="@{()-> viewModel.save()}"
android:text="确定"
android:textColor="@color/white"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
</layout>

View File

@@ -1,511 +1,266 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="android.view.View" />
<variable
name="bean"
type="com.lukouguoji.module_base.bean.GjcMaWb" />
<variable
name="position"
type="Integer" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp"
android:layout_marginTop="10dp"
android:orientation="vertical">
<!-- 白色卡片 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_white_radius_8"
android:orientation="vertical">
<!-- 主要内容区域 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingVertical="20dp"
android:paddingHorizontal="10dp">
<!-- 选中图标 (飞机图标,根据选择状态切换图片) -->
<ImageView
android:id="@+id/iv_icon"
loadImage="@{bean.checked.get() ? @drawable/img_plane_s : @drawable/img_plane}"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginTop="0.5px"
android:layout_gravity="center"
android:src="@drawable/img_plane" />
<!-- 运单信息区域 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_weight="0.8"
android:orientation="vertical">
<!-- 第一行:运单号、状态、代理、件数、重量 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<!-- 运单号 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
completeSpace="@{4}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="运单号:"
android:textColor="@color/text_normal"
android:textSize="15sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{bean.wbNo}"
android:textColor="@color/colorPrimary"
android:textSize="15sp"
android:textStyle="bold" />
</LinearLayout>
<!-- 状态 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
completeSpace="@{5}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="状态:"
android:textColor="@color/text_normal"
android:textSize="15sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@{`01`.equals(bean.declareStatus) ? @drawable/tag_status_green : (`W`.equals(bean.declareStatus) ? @drawable/tag_status_blue : @drawable/tag_status_gray)}"
android:paddingHorizontal="8dp"
android:paddingVertical="2dp"
android:text="@{bean.declareStatus}"
android:textColor="@{`01`.equals(bean.declareStatus) ? @color/text_green : (`W`.equals(bean.declareStatus) ? @color/colorPrimary : @color/text_gray)}"
android:textSize="14sp"
android:visibility="@{bean.declareStatus != null &amp;&amp; !bean.declareStatus.isEmpty() ? View.VISIBLE : View.GONE}" />
</LinearLayout>
<!-- 代理 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
completeSpace="@{5}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="代理:"
android:textColor="@color/text_normal"
android:textSize="15sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
android:maxLines="1"
android:text="@{bean.agentName}"
android:textColor="@color/text_normal"
android:textSize="15sp" />
</LinearLayout>
<!-- 件数 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
completeSpace="@{5}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="件数:"
android:textColor="@color/text_normal"
android:textSize="15sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(bean.pc)}"
android:textColor="@color/text_normal"
android:textSize="15sp" />
</LinearLayout>
<!-- 重量 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
completeSpace="@{4}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="重量:"
android:textColor="@color/text_normal"
android:textSize="15sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf((int)bean.weight)}"
android:textColor="@color/text_normal"
android:textSize="15sp" />
</LinearLayout>
</LinearLayout>
<!-- 第二行:航程、计重状态、运抵状态、运单类型、分单数 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<!-- 航程 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
completeSpace="@{4}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="航程:"
android:textColor="@color/text_normal"
android:textSize="15sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{bean.range}"
android:textColor="@color/text_normal"
android:textSize="15sp" />
</LinearLayout>
<!-- 计重状态 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
completeSpace="@{5}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="计重状态:"
android:textColor="@color/text_normal"
android:textSize="15sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@{`1`.equals(bean.checkIn) ? @drawable/tag_status_green : (`2`.equals(bean.checkIn) ? @drawable/tag_status_blue : @drawable/tag_status_gray)}"
android:paddingHorizontal="8dp"
android:paddingVertical="2dp"
android:text="@{bean.checkInText}"
android:textColor="@{`1`.equals(bean.checkIn) ? @color/text_green : (`2`.equals(bean.checkIn) ? @color/colorPrimary : @color/text_gray)}"
android:textSize="14sp"
android:visibility="@{bean.checkIn != null &amp;&amp; !bean.checkIn.isEmpty() ? View.VISIBLE : View.GONE}" />
</LinearLayout>
<!-- 运抵状态 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
completeSpace="@{5}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="运抵状态:"
android:textColor="@color/text_normal"
android:textSize="15sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@{`0`.equals(bean.arriveFlag) ? @drawable/tag_status_green : (`1`.equals(bean.arriveFlag) ? @drawable/tag_status_orange : @drawable/tag_status_gray)}"
android:paddingHorizontal="8dp"
android:paddingVertical="2dp"
android:text="@{bean.arriveFlagText}"
android:textColor="@{`0`.equals(bean.arriveFlag) ? @color/text_green : (`1`.equals(bean.arriveFlag) ? @color/text_orange : @color/text_gray)}"
android:textSize="14sp"
android:visibility="@{bean.arriveFlag != null &amp;&amp; !bean.arriveFlag.isEmpty() ? View.VISIBLE : View.GONE}" />
</LinearLayout>
<!-- 运单类型 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
completeSpace="@{5}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="运单类型:"
android:textColor="@color/text_normal"
android:textSize="15sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{bean.awbName}"
android:textColor="@color/text_normal"
android:textSize="15sp" />
</LinearLayout>
<!-- 分单数 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
completeSpace="@{4}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="分单数:"
android:textColor="@color/text_normal"
android:textSize="15sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(bean.haWbNumber)}"
android:textColor="@color/text_normal"
android:textSize="15sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<!-- 展开按钮 -->
<ImageView
android:id="@+id/iv_show"
android:layout_width="match_parent"
android:layout_height="20dp"
android:paddingVertical="2.5dp"
android:layout_marginTop="-20dp"
android:scaleType="center"
android:src="@mipmap/img_down" />
</LinearLayout>
<!-- 子订单列表容器(白色圆角卡片,圆角同主单) -->
<LinearLayout
visible="@{bean.showMore}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:background="@drawable/bg_white_radius_8"
android:orientation="vertical"
android:visibility="gone">
<!-- 暂无数据提示 -->
<TextView
android:id="@+id/tv_empty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingVertical="15dp"
android:text="暂无分单数据"
android:textColor="@color/text_gray"
android:textSize="14sp"
android:visibility="gone" />
<!-- 表头(浅蓝色背景,仅 Title 有背景色,顶部圆角同卡片) -->
<LinearLayout
android:id="@+id/ll_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_arrive_sub_header"
android:orientation="horizontal"
android:paddingHorizontal="10dp"
android:paddingVertical="10dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:gravity="center"
android:text="选项"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.2"
android:gravity="center"
android:text="分单号"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:gravity="center"
android:text="件数"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:gravity="center"
android:text="重量(KG)"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="申报状态"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="品名(中)"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.9"
android:gravity="center"
android:text="申报次数"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.9"
android:gravity="center"
android:text="申报费率"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.9"
android:gravity="center"
android:text="删除次数"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.9"
android:gravity="center"
android:text="删除费率"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
</LinearLayout>
<com.google.android.material.divider.MaterialDivider
android:id="@+id/divider_header"
android:layout_width="match_parent"
android:layout_height="1px"
app:dividerColor="@color/sub_list_divider" />
<!-- 子列表 RecyclerView -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_sub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
</LinearLayout>
</LinearLayout>
</layout>
<?xml version="1.0" encoding="utf-8"?>
<!--
国际出港运抵 - 列表卡片(手机版变体)
平板版为 layout-sw600dp/item_int_exp_arrive.xml横排 KV + 内嵌分单展开列表)。
变量 bean / position 与平板一致;根节点保留 id ll不使用仅保持结构一致
手机独有radio 选择圈仅待运抵可选、长按操作浮层activity/viewModel 新增变量,
平板变体已同步补充但不使用)。
卡片形态按 Tab 区分(由 Activity 长按/点击驱动,视觉上两种形态共用同一布局,
仅申报状态标签、提前运抵标签、选择圈的显隐不同):
· 待运抵:显示选择圈 + 红色「提前运抵」标签arriveFlag=1 时);长按仅「补充」
· 已运抵显示申报状态三色标签01绿/W靛蓝/其余琥珀);长按「重置」+「回执」
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View" />
<variable
name="bean"
type="com.lukouguoji.module_base.bean.GjcMaWb" />
<variable
name="position"
type="Integer" />
<variable
name="activity"
type="com.lukouguoji.gjc.activity.IntExpArriveActivity" />
<variable
name="viewModel"
type="com.lukouguoji.gjc.viewModel.IntExpArriveViewModel" />
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="10dp">
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/ll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_phone_card"
android:onLongClick="@{()-> activity.showCardActionPhone(bean)}"
android:orientation="vertical"
android:padding="14dp">
<!-- 头行:(选择圈,仅待运抵)运单号 + 状态标签 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_select"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginEnd="8dp"
loadImage="@{bean.checked.get() ? @drawable/radiobtn_checked_style : @drawable/radiobtn_unchecked_style}"
android:src="@drawable/radiobtn_unchecked_style"
android:visibility="@{`pending`.equals(viewModel.currentTab) ? View.VISIBLE : View.GONE}" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@{bean.wbNo}"
android:textColor="@color/phone_text_strong"
android:textSize="15sp"
android:textStyle="bold"
tools:text="78133363396" />
<!-- 提前运抵(待运抵 Tab仅 arriveFlag=1 时显示) -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_phone_tag_red"
android:paddingHorizontal="8dp"
android:paddingVertical="3dp"
android:text="提前运抵"
android:textColor="@color/phone_tag_red_text"
android:textSize="11sp"
android:visibility="@{`pending`.equals(viewModel.currentTab) &amp;&amp; `1`.equals(bean.arriveFlag) ? View.VISIBLE : View.GONE}" />
<!-- 申报状态(已运抵 Tab三色 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@{`green`.equals(bean.declareTagColor) ? @drawable/bg_phone_tag_green : (`indigo`.equals(bean.declareTagColor) ? @drawable/bg_phone_tag_indigo : @drawable/bg_phone_tag_amber)}"
android:paddingHorizontal="8dp"
android:paddingVertical="3dp"
android:text="@{bean.declareStatus}"
android:textColor="@{`green`.equals(bean.declareTagColor) ? @color/phone_tag_green_text : (`indigo`.equals(bean.declareTagColor) ? @color/phone_tag_indigo_text : @color/phone_tag_amber_text)}"
android:textSize="11sp"
android:visibility="@{`shipped`.equals(viewModel.currentTab) &amp;&amp; !bean.declareTagColor.empty ? View.VISIBLE : View.GONE}"
tools:text="01" />
</LinearLayout>
<!-- 字段网格:代理 / 件数 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text='@{"代理: " + bean.agentName}'
android:textColor="@color/phone_text_body"
android:textSize="13sp"
tools:text="代理: 马道" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text='@{"件数: " + bean.pc}'
android:textColor="@color/phone_text_body"
android:textSize="13sp"
tools:text="件数: 444" />
</LinearLayout>
<!-- 字段网格:重量 / 航班日期 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text='@{"重量: " + (int) bean.weight + "kg"}'
android:textColor="@color/phone_text_body"
android:textSize="13sp"
tools:text="重量: 150kg" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text='@{"航班日期: " + bean.flightDateText}'
android:textColor="@color/phone_text_body"
android:textSize="13sp"
tools:text="航班日期: 20260713" />
</LinearLayout>
<!-- 字段网格:航班号 / 航程 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text='@{"航班号: " + bean.fno}'
android:textColor="@color/phone_text_body"
android:textSize="13sp"
tools:text="航班号: MU2033" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text='@{"航程: " + bean.rangeText}'
android:textColor="@color/phone_text_body"
android:textSize="13sp"
tools:text="航程: HFE-LAX" />
</LinearLayout>
<!-- 查看分单(无分单数据时不显示) -->
<TextView
android:layout_width="match_parent"
android:layout_height="36dp"
android:layout_marginTop="12dp"
android:background="@drawable/bg_phone_btn_weak"
android:gravity="center"
android:onClick="@{()-> activity.openSubOrder(bean)}"
android:text='@{"查看分单 " + bean.haWbNumber}'
android:textColor="@color/phone_primary"
android:textSize="14sp"
android:visibility="@{bean.haWbNumber != null &amp;&amp; bean.haWbNumber > 0 ? View.VISIBLE : View.GONE}"
tools:text="查看分单 3" />
</androidx.appcompat.widget.LinearLayoutCompat>
<!-- ==================== 长按操作浮层 ==================== -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#66000000"
android:clickable="true"
android:onClick="@{()-> activity.hideCardActionPhone(bean)}"
android:visibility="@{bean.actionMenuVisible ? View.VISIBLE : View.GONE}">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="horizontal">
<!-- 补充(仅待运抵) -->
<TextView
android:layout_width="56dp"
android:layout_height="56dp"
android:background="@drawable/bg_phone_fab_purple"
android:gravity="center"
android:onClick="@{()-> activity.openSupplement(bean)}"
android:text="补充"
android:textColor="@color/white"
android:textSize="12sp"
android:textStyle="bold"
android:visibility="@{`pending`.equals(viewModel.currentTab) ? View.VISIBLE : View.GONE}" />
<!-- 重置(仅已运抵) -->
<TextView
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_marginEnd="16dp"
android:background="@drawable/bg_phone_fab_amber"
android:gravity="center"
android:onClick="@{()-> viewModel.resetSingleDeclareClick(bean)}"
android:text="重置"
android:textColor="@color/white"
android:textSize="12sp"
android:textStyle="bold"
android:visibility="@{`shipped`.equals(viewModel.currentTab) ? View.VISIBLE : View.GONE}" />
<!-- 回执(仅已运抵) -->
<TextView
android:layout_width="56dp"
android:layout_height="56dp"
android:background="@drawable/bg_phone_fab_green"
android:gravity="center"
android:onClick="@{()-> activity.openReceipt(bean)}"
android:text="回执"
android:textColor="@color/white"
android:textSize="12sp"
android:textStyle="bold"
android:visibility="@{`shipped`.equals(viewModel.currentTab) ? View.VISIBLE : View.GONE}" />
</LinearLayout>
</FrameLayout>
</FrameLayout>
</layout>

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 国际出港运抵-回执内容 - 单条回执卡片5.5寸手机版专属只读页) -->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="bean"
type="com.lukouguoji.module_base.bean.GjcHaWb" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="10dp"
android:background="@drawable/bg_phone_card"
android:orientation="vertical"
android:padding="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<View
android:layout_width="6dp"
android:layout_height="6dp"
android:layout_marginTop="7dp"
android:background="@drawable/bg_phone_fab" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:text="@{bean.response}"
android:textColor="@color/phone_text_strong"
android:textSize="14sp"
tools:text="单一窗口回执内容45201 空运出口运抵报告传输成功。比对结果为:运抵正常。" />
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:text="@{bean.arrivalOpDateText}"
android:textColor="@color/phone_text_hint"
android:textSize="12sp"
tools:text="2026-07-10 11:03:38" />
</LinearLayout>
</layout>

View File

@@ -0,0 +1,130 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
国际出港运抵-分单明细 - 分单卡片5.5寸手机版专属页面)
对应设计稿卡片:分单号 + 申报状态标签 + 件数/重量,长按弹出「重置」单条操作。
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View" />
<variable
name="bean"
type="com.lukouguoji.module_base.bean.GjcHaWb" />
<variable
name="activity"
type="com.lukouguoji.gjc.activity.IntExpArriveSubOrderActivity" />
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="10dp">
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/ll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_phone_card"
android:onLongClick="@{()-> activity.showActionMenu(bean)}"
android:orientation="vertical"
android:padding="14dp">
<!-- 头行:选择圈 + 分单号 + 申报状态标签 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginEnd="8dp"
loadImage="@{bean.checked.get() ? @drawable/radiobtn_checked_style : @drawable/radiobtn_unchecked_style}"
android:src="@drawable/radiobtn_unchecked_style" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@{bean.hno}"
android:textColor="@color/phone_text_strong"
android:textSize="15sp"
android:textStyle="bold"
tools:text="10001" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@{`green`.equals(bean.haWbTagColor) ? @drawable/bg_phone_tag_green : (`indigo`.equals(bean.haWbTagColor) ? @drawable/bg_phone_tag_indigo : @drawable/bg_phone_tag_amber)}"
android:paddingHorizontal="8dp"
android:paddingVertical="3dp"
android:text="@{bean.arrivalStatus}"
android:textColor="@{`green`.equals(bean.haWbTagColor) ? @color/phone_tag_green_text : (`indigo`.equals(bean.haWbTagColor) ? @color/phone_tag_indigo_text : @color/phone_tag_amber_text)}"
android:textSize="11sp"
android:visibility="@{bean.haWbTagColor.empty ? View.GONE : View.VISIBLE}"
tools:text="W" />
</LinearLayout>
<!-- 字段网格:件数 / 重量 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text='@{"件数: " + (bean.hpc != null ? bean.hpc : bean.pc)}'
android:textColor="@color/phone_text_body"
android:textSize="13sp"
tools:text="件数: 150" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text='@{"重量: " + (int)(bean.hweight != null ? bean.hweight : bean.weight) + "kg"}'
android:textColor="@color/phone_text_body"
android:textSize="13sp"
tools:text="重量: 50kg" />
</LinearLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
<!-- ==================== 长按操作浮层:仅「重置」 ==================== -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#66000000"
android:clickable="true"
android:onClick="@{()-> activity.hideActionMenu(bean)}"
android:visibility="@{bean.actionMenuVisible ? View.VISIBLE : View.GONE}">
<TextView
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_gravity="center"
android:background="@drawable/bg_phone_fab_amber"
android:gravity="center"
android:onClick="@{()-> activity.resetSingleClick(bean)}"
android:text="重置"
android:textColor="@color/white"
android:textSize="12sp"
android:textStyle="bold" />
</FrameLayout>
</FrameLayout>
</layout>