diff --git a/.claude/skills/phone-adapt/references/api-doc.md b/.claude/skills/phone-adapt/references/api-doc.md
index 8634cee..6570f2e 100644
--- a/.claude/skills/phone-adapt/references/api-doc.md
+++ b/.claude/skills/phone-adapt/references/api-doc.md
@@ -70,6 +70,13 @@ curl -s -X POST "$URL" -H "$AUTH" -H "Content-Type: application/json" \
0 正常/1 故障(三态需求=缺口 #7);无「来源」字段(#8)、无 `checkInDate`/`ifNo` 筛选入参(#9)、
无批量删除(#10,`deleteUld` 是 `@Query` 单条);出参 `ifNo`/`efNo`/`checkInDate`/`checkOutDate`
文档无描述,按命名推断进/出港航班号与出入库时间(#11 待确认)
+- `IntExpArrive`(出港运抵,2026-07-30 内网实测):`declareStatus`(申报状态)只在出参,
+ `pageQuery`/`pageQueryTotal` 入参均无此字段(缺口 #20,待运抵/已运抵 Tab 靠客户端拆分);
+ `declareStatus`/`GjcHaWb.arrivalStatus` 三色编码:`01`=正常(绿)、`W`=靛蓝态、其余非空=琥珀异常态;
+ `haWbList[].response`/`arrivalOpDate` 是回执文本与对应时间,实测确认真实存在非空数据;
+ 分单补充收发货人信息**后端完全没有对应接口**(`search_endpoints` 对 `IntExpArrive`/`HaWb`
+ 关键字均搜不到分单更新接口,只有国际进港的 `IntImpAirManifest/complete`),
+ 实机调用拟定路径 `IntExpArrive/haWb/supplement` 确认 404(缺口 #19)
- `IntExpCheckIn`(出港计重,2026-07-29 内网实测):`likeNo` **并非任意模糊**——按 8 位 `no`
匹配(11 位 wbNo 或部分号均 0 条),11 位全号必须走 `wbNo`;`checkIn`/`checkInList`
文档有定义但 `pageQuery`/`pageQueryTotal` **均静默忽略**(缺口 #12,待计重/计重中计数依赖);
diff --git a/.claude/skills/phone-adapt/references/pad-safety.md b/.claude/skills/phone-adapt/references/pad-safety.md
index 9cc07d5..5c30f26 100644
--- a/.claude/skills/phone-adapt/references/pad-safety.md
+++ b/.claude/skills/phone-adapt/references/pad-safety.md
@@ -130,7 +130,7 @@ binding.btnMove?.setOnClickListener { showMoveConfirmDialog() }
例:手机「待交接」Tab 下理论上只有未交接记录(服务端按状态过滤),所以全选照原样全量勾选就是对的;
若为此加上「跳过已交接」的过滤,反而改变了平板端(平板列表混排两种状态)的行为。
-## 屏幕方向:Manifest 必须写资源引用
+## 屏幕方向:Manifest 一律写 `unspecified`
新增 Activity 注册时:
@@ -138,15 +138,20 @@ binding.btnMove?.setOnClickListener { showMoveConfirmDialog() }
+ android:screenOrientation="unspecified" />
```
-**不要写死 `userLandscape`。** `screenOrientation` 由系统在创建 Activity 窗口时生效,
-那时业务代码还没跑;写死横屏后即使 `BaseActivity` 在 `super.onCreate` 之前改成竖屏,
-用户也会看到「先横屏、约 1 秒后转竖屏」的闪屏和重建。
+**两种错误方案都实测踩过,别再试:**
+- 写死 `userLandscape` → 手机「先横屏、约 1 秒后转竖屏」(方向在建窗口时就定了,
+ `BaseActivity` 在 `super.onCreate` 之前纠正也来不及)
+- 用 `@integer/screen_orientation` 资源引用(曾经以为是优雅方案)→ **更糟**:系统解析
+ Manifest 属性不套用设备限定符,所有 Activity 实际都拿到 `values/` 默认值(竖屏),
+ 平板因此先竖后横,且 AutoSize 在竖屏配置下选中平板竖屏 720dp 基准
+ (正常应为 1152×720 横屏基准),交互几次后整个 UI 放大约 1.6 倍
-资源取值:`module_base/res/values/integers.xml` = 1(portrait),
-`values-sw600dp/integers.xml` = 11(userLandscape)。全项目已统一替换。
+`unspecified` 让系统按设备当前物理方向建窗口(平板横屏摆放→横屏起,手机→竖屏起,
+两端起始方向本就正确),`BaseActivity.applyDeviceOrientation()` 再按形态锁定,
+不产生二次纠正。全项目 192 处已统一为 `unspecified`。
## 改 module_base 公共代码时
@@ -158,6 +163,81 @@ binding.btnMove?.setOnClickListener { showMoveConfirmDialog() }
- Bean 上加只读计算属性是安全的(Gson 只序列化字段,不动 getter);
加**字段**要谨慎,会进请求体
+## RecyclerView 里不要用 item 级 visibility 做 Tab/分类过滤
+
+普通 ViewGroup(LinearLayout 等)里 `View.GONE` 的子 View 会自动塌陷为 0 高度、不占布局空间——
+但 **RecyclerView + LinearLayoutManager 不是这样**:它按子项的测量高度参与滚动区域计算,
+不会因为子项是 GONE 就跳过。给 item 根节点加 `visibility="@{tab条件 ? VISIBLE : GONE}"`
+切 Tab,会在列表里留下一段空白(隐藏项的高度仍被保留),角标数字和实际卡片数量对不上。
+
+出港运抵的「待运抵/已运抵」Tab 就踩了这个坑(实机截图验证:切到「已运抵」后顶部有一大块
+空白,隐藏的待运抵卡片高度并未塌陷)。正确做法是在数据层过滤,而不是视图层:
+
+```kotlin
+// ViewModel:自己维护完整列表,不依赖 adapter.items 的历史状态
+// (见下一节:adapter.items 在 loadMore 场景可能已经是上次过滤后的子集,不能当作真源)
+private var allLoadedList: List = emptyList()
+
+override fun getData() {
+ launchLoadingCollect({ ... }) {
+ onSuccess = { result ->
+ val newPageItems = result.list ?: emptyList()
+ allLoadedList = if (pageModel.page <= 1) newPageItems else allLoadedList + newPageItems
+
+ pageModel.handleListBean(result) {
+ // 无论 handleListBean 内部把 adapter.items 搞成什么样,这里用 allLoadedList
+ // 强制覆盖为「当前 Tab 的正确子集」,兜底纠正
+ val filtered = allLoadedList.filter { it.isPending == (currentTab.value == "pending") }
+ pageModel.rv?.commonAdapter()?.refresh(filtered)
+ }
+ }
+ }
+}
+
+fun onTabChangedPhone() {
+ val filtered = allLoadedList.filter { it.isPending == (currentTab.value == "pending") }
+ pageModel.rv?.commonAdapter()?.refresh(filtered) // 只是 items.clear()+addAll()+notifyDataSetChanged,无副作用
+}
+```
+
+`CommonAdapter.refresh()` 只是替换内部列表并 `notifyDataSetChanged()`,不影响
+SmartRefreshLayout 的分页/完成状态,可以放心在 `handleListBean` 回调里再调用一次。
+
+## Intent 传递 Serializable Bean:`@Transient` 字段反序列化后是 null
+
+`GjcMaWb`/`GjcHaWb` 的 `checked`/`showMore`/`actionMenuVisible` 三个 UI 状态字段都标了
+`@Transient`(本意是避免 Gson 把 `ObservableBoolean` 的内部结构序列化进网络请求体)。
+但 Kotlin 的 `@Transient` 注解生成的就是 JVM 的 `transient` 修饰符,这个修饰符对 **Java
+对象序列化**(`Intent.putExtra(String, Serializable)` 走的正是这条路径)有实际含义:
+反序列化时会跳过 `transient` 字段的恢复,对象引用类型的字段结果就是 **null**。
+
+新增手机专属页面时,如果要把 `List` 通过 `ArrayList` 塞进 `Intent`
+传给下一个页面,接收方拿到的对象「看起来」字段都对(wbNo、pc、weight 这些正常字段没问题,
+因为它们不是 `@Transient`),但只要调用 `bean.checked.set(...)` 就会立刻崩溃:
+
+```
+NullPointerException: Attempt to invoke virtual method
+'void androidx.databinding.ObservableBoolean.set(boolean)' on a null object reference
+```
+
+出港运抵的「分单明细」页第一版全选按钮就是这样崩的。**修复只需一行**,在接收方
+`initOnCreated` 里对拿到的列表整体 `.copy()` 一遍——`.copy()` 会重新触发一次真正的对象构造,
+类体里 `val checked = ObservableBoolean(false)` 这类初始化逻辑跟着重新跑一遍,
+把 null 补成全新实例:
+
+```kotlin
+@Suppress("UNCHECKED_CAST")
+fun initOnCreated(intent: Intent) {
+ val list = intent.getSerializableExtra(Constant.Key.DATA) as? ArrayList
+ // .copy() 补上被 Java 序列化跳过的 @Transient 字段
+ fullList = (list ?: emptyList()).map { it.copy() }
+}
+```
+
+这个坑只在「Intent 传递 Serializable Bean + 接收方要切换 checked/showMore 等状态」时才会
+触发;纯只读展示(如回执页)不调用这些字段的 setter,不会崩,但补一道 `.copy()` 无害,
+建议只要通过 Intent 传了 haWbList/maWbList 就统一加上,别等下次踩到才想起来。
+
## 已知的既有问题(不是你改坏的)
用 `am start` 直启页面时,若**先经过首页**再启目标页,会崩在
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c2753ac..73ea40e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,37 @@
## [Unreleased]
### 新增 (Added)
+- 「出港运抵」5.5 寸手机端适配(主列表 + 3 个手机专属新页,设计稿 04_出港运抵):
+ 主列表 `IntExpArriveActivity` 新增「待运抵/已运抵」Tab(客户端按 declareStatus 是否为空拆分数据集,
+ 接口无此查询参数)+ 卡片长按浮层(待运抵→补充、已运抵→重置+回执,纯 UI 长按)+ 底部全选/已选/申报
+ (仅待运抵 Tab 显示,选中范围独立于 Pad 全量选择逻辑);新增「分单明细」`IntExpArriveSubOrderActivity`
+ (数据直接复用主列表已加载的 haWbList,零新增请求,长按单条重置 + 底部批量申报);新增「回执内容」
+ `IntExpArriveReceiptActivity`(只读页,复用 haWbList[].response + arrivalOpDate);新增「补充信息」
+ `IntExpArriveSupplementActivity`(参照 Pad 端国际进港「收发货人信息」批量应用模式,对整个运单的
+ haWbList 批量应用同一份表单,后端接口不存在,已实机确认 404,见问题清单 #19)
+- 手机首页「国际」Tab 增加「出港运抵」入口
+- `GjcMaWb`/`GjcHaWb` 新增 `isPending`/`declareTagColor`/`haWbTagColor`/`arrivalOpDateText` 等
+ 手机版专属计算属性;`GjcHaWb` 补充 `Serializable` 实现(供 Intent 跨页传递分单列表)
+- 新增手机版资源:`bg_phone_tag_indigo`/`bg_phone_tag_amber`(申报状态三色标签)、
+ `bg_phone_fab_purple`/`bg_phone_fab_amber`/`bg_phone_fab_green`(长按浮层圆形操作按钮)
+- 后端缺口 2 项登记问题清单 #19~#20(分单补充信息保存接口不存在、Tab 无申报状态查询参数)
+
+### 修复 (Fixed)
+- **RecyclerView + Tab 过滤新坑**:给 item 根节点加 `visibility="@{...}"` 切 Tab 会在列表里
+ 留下空白——RecyclerView/LinearLayoutManager 不像普通 ViewGroup 那样让 GONE 子项自动塌陷为
+ 0 高度。改为在 ViewModel 数据层维护完整列表,Tab 切换时把过滤后的子集整体 `refresh()` 给
+ adapter(已实机截图验证空白消失、卡片数与角标一致)
+- **Serializable Intent + @Transient 崩溃新坑**:`GjcMaWb`/`GjcHaWb` 的 `checked` 等 UI 状态
+ 字段标了 `@Transient`(避免 Gson 序列化 ObservableBoolean),但这同时是 JVM `transient`
+ 修饰符,Java 序列化(Intent 传递机制)会跳过其恢复,反序列化后为 null,切换选中状态时
+ NullPointerException 崩溃。修复:接收方 `initOnCreated` 对列表 `.map { it.copy() }` 重新
+ 触发类体初始化补上(已实机崩溃复现并验证修复)
+
+### 验证 (Verified)
+- 出港运抵双端实机验证通过:手机端 Tab 切换(角标/卡片双向正确)/全选/单选/长按菜单/查看分单
+ /分单明细全选与长按重置/补充信息(真实数据回填+下拉字典+提交请求体完整+后端404如实呈现)/
+ 回执页 全链路 crash=0、方向无闪屏;平板端布局与交互(4 搜索条+分单内嵌展开+底部 5 元素操作栏)
+ 与改造前逐项一致
- 「出港计重」5.5 寸手机端适配(首个全链路 4+1 页模块,设计稿 03_出港计重):
待计重列表(三格统计 总票数/待计重/计重中 + 卡片状态标签 未计重/计重中 + 卡片内单票「提前运抵」+
FAB 进计重记录 + 筛选弹层 通道号/承运人/运单类型/代理人)、开始计重(头部预配统计卡 + PhoneFormRow 表单,
diff --git a/CLAUDE.md b/CLAUDE.md
index 9be348d..347b5f6 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -1110,6 +1110,18 @@ override fun dispatchRestoreInstanceState(container: SparseArray) =
isEditMode 复用为手机全屏「修改记录」覆层)+ 手机专属新页 `GjcWeighingWbDetailActivity`(运单详情)。
搜索分流规则(实测):含字母→fno、11 位数字→wbNo、其余→likeNo(likeNo 按 8 位 no 匹配并非模糊);
checkIn 过滤等 7 项后端缺口见问题清单 #12~#18
+ - 「出港运抵」主列表 + 3 个手机专属新页:`IntExpArriveActivity`(待运抵/已运抵 Tab,客户端按
+ `declareStatus` 是否为空拆分数据集,卡片长按浮层:待运抵→补充、已运抵→重置+回执)、
+ `IntExpArriveSubOrderActivity`(分单明细,数据直接复用主列表已加载的 `haWbList`,零新增请求)、
+ `IntExpArriveReceiptActivity`(回执内容只读页,复用 `haWbList[].response`)、
+ `IntExpArriveSupplementActivity`(补充信息,参照 Pad 端国际进港「收发货人信息」批量应用模式,
+ 后端接口不存在,实机 404 已确认,见问题清单 #19)。
+ Tab 过滤两个坑:① **RecyclerView 里 `View.GONE` 不会让 item 塌陷为 0 高度**(不同于普通
+ ViewGroup),必须在数据层整体 `refresh()` 过滤后的子集给 adapter,不能给 item 根节点加
+ visibility 绑定(实机截图验证过,见「常见编译错误速查」);② 通过 `Intent.putExtra(Serializable)`
+ 传递的 `GjcHaWb`/`GjcMaWb`,其 `checked`/`showMore`/`actionMenuVisible` 字段标了
+ `@Transient`(= JVM `transient`,Java 序列化会跳过),反序列化后为 null,直接
+ `.checked.set(...)` 会崩溃——接收方 `initOnCreated` 必须对列表 `.map { it.copy() }` 补上
- ⏳ **待办**:
- `PhoneSearchBar` 接入 AutoQuery 联想(`AutoQueryManager` 目前只对接了 Pad 系组件)
- 出库交接 Tab 角标恒 0:`IntExpOutHandover/pageQueryTotal` 出参恒 0(后端缺陷,问题清单 #6),
@@ -1202,6 +1214,8 @@ adb shell am start -n com.lukouguoji.aerologic/com.lukouguoji.gjc.activity.IntEx
| 手机版筛选项默认值(如日期)自动被清空 | 多个复合自定义 View 内部子控件 id 相同,系统按 id 恢复状态时跨实例串档 | 组件重写 `dispatchSaveInstanceState`/`dispatchRestoreInstanceState` 为 `dispatchFreezeSelfOnly`/`dispatchThawSelfOnly`(见「手机版公共组件库」) |
| 手机上页面先横屏再转竖屏(闪一下) | Manifest 写死 `screenOrientation="userLandscape"`,系统建窗口时已按横屏,代码纠正为时已晚 | 改成 `android:screenOrientation="unspecified"`,由 `BaseActivity` 按形态锁定(见「屏幕方向」小节) |
| 平板先竖屏再转横屏 + 交互后 UI 放大约 1.6 倍 | Manifest 用了 `@integer/screen_orientation` 资源引用;系统解析 Manifest 不套用限定符,全部取到竖屏值,AutoSize 随之选了平板竖屏 720dp 基准 | Manifest 改回 `unspecified`(见「屏幕方向」小节的 ⛔ 说明) |
+| Tab/分类切换后列表顶部留一大块空白,卡片数量却不对 | 给 item 根节点加了 `visibility="@{tab条件 ? VISIBLE : GONE}"`——RecyclerView/LinearLayoutManager 不会像普通 ViewGroup 那样让 GONE 的子项自动塌陷为 0 高度,仍按测量高度参与滚动区域计算 | 不要用 item 级 visibility 做过滤;在 ViewModel 里自行维护完整列表,Tab 切换时把过滤后的子集整体 `commonAdapter()?.refresh(filteredList)` 给 adapter |
+| 通过 `Intent.putExtra(Serializable)` 传递的 Bean,切换其 `checked`/`showMore` 等状态时崩溃 `NullPointerException: ... on a null object reference` | 这些字段标了 `@Transient`(= JVM `transient`,本意是避免 Gson 网络请求序列化 `ObservableBoolean`),但 Java 对象序列化(Intent 传递走的机制)会跳过 `transient` 字段的恢复,反序列化后是 null | 接收方 `initOnCreated` 里对列表做 `.map { it.copy() }`——`.copy()` 会重新走一遍类体初始化逻辑,用全新 `ObservableBoolean(false)` 补上 |
---
diff --git a/app/src/debug/AndroidManifest.xml b/app/src/debug/AndroidManifest.xml
index 3fabae5..a169c60 100644
--- a/app/src/debug/AndroidManifest.xml
+++ b/app/src/debug/AndroidManifest.xml
@@ -80,5 +80,29 @@
android:exported="true"
tools:replace="android:exported" />
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index cc1e1d7..c02e4dd 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -145,6 +145,24 @@
android:configChanges="orientation|keyboardHidden"
android:exported="false"
android:screenOrientation="unspecified" />
+
+
+
+
+
+
"green"
+ "W" -> "indigo"
+ else -> if (declareStatus.isNullOrEmpty()) "" else "amber"
+ }
+
// ==================== 状态转换扩展属性 ====================
/**
* 计重状态中文
@@ -277,15 +297,36 @@ data class GjcHaWb(
var tallyOpId: String? = null, // 理货操作人ID
var declareCount: Long? = null, // 申报次数
var activeId: Long? = null // 活动ID
-) {
+) : Serializable {
// ==================== UI扩展字段 ====================
@Transient
val checked: ObservableBoolean = ObservableBoolean(false) // 选中状态
+ @Transient
+ val actionMenuVisible: ObservableBoolean = ObservableBoolean(false) // 5.5寸手机版:卡片长按操作浮层显隐
// 兼容现有API的isSelected属性
var isSelected: Boolean
get() = checked.get()
set(value) = checked.set(value)
+
+ /**
+ * 5.5寸手机版:申报状态三色标签的着色分类(01=绿/W=靛蓝/其余非空=琥珀)。
+ * 与 GjcMaWb.declareTagColor 同源逻辑,作用于分单自身的 arrivalStatus。
+ */
+ val haWbTagColor: String
+ get() = when (arrivalStatus) {
+ "01" -> "green"
+ "W" -> "indigo"
+ else -> if (arrivalStatus.isNullOrEmpty()) "" else "amber"
+ }
+
+ /**
+ * 5.5寸手机版「回执」页:运抵操作时间(格式化)。
+ */
+ val arrivalOpDateText: String
+ get() = arrivalOpDate?.let {
+ SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(it)
+ } ?: ""
}
/**
diff --git a/module_base/src/main/java/com/lukouguoji/module_base/http/net/Api.kt b/module_base/src/main/java/com/lukouguoji/module_base/http/net/Api.kt
index b17d31f..284433f 100644
--- a/module_base/src/main/java/com/lukouguoji/module_base/http/net/Api.kt
+++ b/module_base/src/main/java/com/lukouguoji/module_base/http/net/Api.kt
@@ -851,6 +851,16 @@ interface Api {
@POST("IntExpArrive/deleteDeclare")
suspend fun deleteArriveDeclare(@Body data: RequestBody): BaseResultBean
+ /**
+ * 国际出港运抵-分单补充收发货人信息(5.5寸手机版新增)
+ *
+ * 后端暂无此接口(api-doc 搜索 IntExpArrive、HaWb 均无匹配),路径为参照 Pad 端国际进港
+ * IntImpAirManifest/complete 命名习惯拟定的建议值,见 documents/后端接口对接问题清单.xlsx。
+ * 请求体为分单数组,仅需 haWbId 与收发货人相关字段。
+ */
+ @POST("IntExpArrive/haWb/supplement")
+ suspend fun supplementArriveHaWb(@Body data: RequestBody): BaseResultBean
+
/**
* 国际出港移库-分页查询
* 接口路径: /IntExpMove/pageQuery
diff --git a/module_base/src/main/res/drawable/bg_phone_fab_amber.xml b/module_base/src/main/res/drawable/bg_phone_fab_amber.xml
new file mode 100644
index 0000000..7d921e1
--- /dev/null
+++ b/module_base/src/main/res/drawable/bg_phone_fab_amber.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/module_base/src/main/res/drawable/bg_phone_fab_green.xml b/module_base/src/main/res/drawable/bg_phone_fab_green.xml
new file mode 100644
index 0000000..cc2e7b6
--- /dev/null
+++ b/module_base/src/main/res/drawable/bg_phone_fab_green.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/module_base/src/main/res/drawable/bg_phone_fab_purple.xml b/module_base/src/main/res/drawable/bg_phone_fab_purple.xml
new file mode 100644
index 0000000..15aa096
--- /dev/null
+++ b/module_base/src/main/res/drawable/bg_phone_fab_purple.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/module_base/src/main/res/drawable/bg_phone_tag_amber.xml b/module_base/src/main/res/drawable/bg_phone_tag_amber.xml
new file mode 100644
index 0000000..abb4e6a
--- /dev/null
+++ b/module_base/src/main/res/drawable/bg_phone_tag_amber.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
diff --git a/module_base/src/main/res/drawable/bg_phone_tag_indigo.xml b/module_base/src/main/res/drawable/bg_phone_tag_indigo.xml
new file mode 100644
index 0000000..8979188
--- /dev/null
+++ b/module_base/src/main/res/drawable/bg_phone_tag_indigo.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
diff --git a/module_base/src/main/res/values/colors.xml b/module_base/src/main/res/values/colors.xml
index 8247886..074da37 100644
--- a/module_base/src/main/res/values/colors.xml
+++ b/module_base/src/main/res/values/colors.xml
@@ -75,5 +75,9 @@
#EA580C
#FEE2E2
#DC2626
+ #E0E7FF
+ #6366F1
+ #FEF3C7
+ #D97706
\ No newline at end of file
diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpArriveActivity.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpArriveActivity.kt
index a1ab477..ce5498f 100644
--- a/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpArriveActivity.kt
+++ b/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpArriveActivity.kt
@@ -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(bean.haWbList.orEmpty())
+ IntExpArriveSubOrderActivity.start(this, bean.wbNo.orEmpty(), list)
+ }
+
+ /**
+ * 进入「回执」页(手机专属只读页):复用 haWbList[].response + arrivalOpDate,零新增请求。
+ */
+ fun openReceipt(bean: GjcMaWb) {
+ bean.actionMenuVisible.set(false)
+ val list = ArrayList(bean.haWbList.orEmpty())
+ IntExpArriveReceiptActivity.start(this, bean.wbNo.orEmpty(), list)
+ }
+
+ /**
+ * 进入「补充信息」页(手机专属新页):对该运单整个 haWbList 批量应用(参照 Pad 端国际进港
+ * IntArrSupplementInfoViewModel 的批量复制模式)。后端暂无保存接口,见接口问题清单。
+ */
+ fun openSupplement(bean: GjcMaWb) {
+ bean.actionMenuVisible.set(false)
+ val list = ArrayList(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) {
diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpArriveReceiptActivity.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpArriveReceiptActivity.kt
new file mode 100644
index 0000000..1571b25
--- /dev/null
+++ b/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpArriveReceiptActivity.kt
@@ -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() {
+
+ 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) {
+ val starter = Intent(context, IntExpArriveReceiptActivity::class.java)
+ .putExtra(Constant.Key.CODE, wbNo)
+ .putExtra(Constant.Key.DATA, haWbList)
+ context.startActivity(starter)
+ }
+ }
+}
diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpArriveSubOrderActivity.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpArriveSubOrderActivity.kt
new file mode 100644
index 0000000..3e2259d
--- /dev/null
+++ b/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpArriveSubOrderActivity.kt
@@ -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寸手机版专属新页,平板端无对应页面)
+ *
+ * 数据来自主列表页已加载的 haWbList(Intent 传入),零新增请求。
+ * 对应设计稿 documents/5.5寸手持端设计文件/04_出港运抵/suborder.html。
+ */
+class IntExpArriveSubOrderActivity :
+ BaseBindingActivity() {
+
+ 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) {
+ val starter = Intent(context, IntExpArriveSubOrderActivity::class.java)
+ .putExtra(IntExpArriveSubOrderViewModel.KEY_WB_NO, wbNo)
+ .putExtra(Constant.Key.DATA, haWbList)
+ context.startActivity(starter)
+ }
+ }
+}
diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpArriveSupplementActivity.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpArriveSupplementActivity.kt
new file mode 100644
index 0000000..1d510b2
--- /dev/null
+++ b/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpArriveSupplementActivity.kt
@@ -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() {
+
+ 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) {
+ val starter = Intent(context, IntExpArriveSupplementActivity::class.java)
+ .putExtra(Constant.Key.CODE, wbNo)
+ .putExtra(Constant.Key.DATA, haWbList)
+ context.startActivity(starter)
+ }
+ }
+}
diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpArriveReceiptViewHolder.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpArriveReceiptViewHolder.kt
new file mode 100644
index 0000000..d757114
--- /dev/null
+++ b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpArriveReceiptViewHolder.kt
@@ -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
+
+/**
+ * 国际出港运抵-回执内容列表 ViewHolder(5.5寸手机版专属只读页)
+ */
+class IntExpArriveReceiptViewHolder(view: View) :
+ BaseViewHolder(view) {
+
+ override fun onBind(item: Any?, position: Int) {
+ val bean = getItemBean(item) ?: return
+ binding.bean = bean
+ binding.executePendingBindings()
+ }
+}
diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpArriveSubOrderViewHolder.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpArriveSubOrderViewHolder.kt
new file mode 100644
index 0000000..ca6450e
--- /dev/null
+++ b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpArriveSubOrderViewHolder.kt
@@ -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
+
+/**
+ * 国际出港运抵-分单明细列表 ViewHolder(5.5寸手机版专属页面)
+ *
+ * 选中状态变化只影响本页自身的 ViewModel(不复用全局 FlowBus.EVENT_CHECK_CHANGED,
+ * 避免与主列表页共享同一事件、产生跨页面的无意义联动)。
+ */
+class IntExpArriveSubOrderViewHolder(view: View) :
+ BaseViewHolder(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()
+ }
+ }
+}
diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpArriveViewHolder.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpArriveViewHolder.kt
index 6c2750a..963cb75 100644
--- a/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpArriveViewHolder.kt
+++ b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpArriveViewHolder.kt
@@ -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(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(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
}
}
}
diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpArriveReceiptViewModel.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpArriveReceiptViewModel.kt
new file mode 100644
index 0000000..f303f50
--- /dev/null
+++ b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpArriveReceiptViewModel.kt
@@ -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
+
+/**
+ * 国际出港运抵-回执内容 ViewModel(5.5寸手机版专属只读页)
+ *
+ * 数据直接复用主列表页已加载的 haWbList.response / arrivalOpDate 字段,无需任何新增请求。
+ * 对应设计稿 documents/5.5寸手持端设计文件/04_出港运抵/receipt.html。
+ */
+class IntExpArriveReceiptViewModel : BaseViewModel() {
+
+ val receiptList = MutableLiveData>(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
+ // .copy() 补上被 Java 序列化跳过的 @Transient 字段(checked 等),见分单明细页同款注释
+ receiptList.value = (list ?: emptyList())
+ .map { it.copy() }
+ .filter { !it.response.isNullOrEmpty() }
+ .sortedByDescending { it.arrivalOpDate }
+ }
+}
diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpArriveSubOrderViewModel.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpArriveSubOrderViewModel.kt
new file mode 100644
index 0000000..1c564e6
--- /dev/null
+++ b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpArriveSubOrderViewModel.kt
@@ -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
+
+/**
+ * 国际出港运抵-分单明细 ViewModel(5.5寸手机版专属页面)
+ *
+ * 数据直接复用主列表页已加载的 haWbList(Intent 传入),无需任何新增请求。
+ * 筛选仅「分单号」在客户端生效——航班日期/航班号/代理等字段在单个运单的分单集合内
+ * 恒为同一值,筛选它们没有实际意义(设计稿疑似沿用主列表筛选组件模板,未按此页场景定制)。
+ */
+class IntExpArriveSubOrderViewModel : BaseViewModel() {
+
+ // 运单号(页面标题辅助展示,非必需)
+ var wbNo: String = ""
+ private set
+
+ // 完整分单列表(Intent 传入,不随筛选变化)
+ private var fullList: List = emptyList()
+
+ // 当前展示列表(按分单号筛选后的结果)
+ val displayList = MutableLiveData>(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
+ // 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("haWbList" to listOf(bean))
+ if (dialogModel.resetStatusCode != null) {
+ params["restStatus"] = dialogModel.resetStatusCode
+ }
+ launchLoadingCollect({ NetApply.api.resetArriveDeclare(params.toRequestBody()) }) {
+ onSuccess = {
+ showToast("状态重置成功,请返回列表页下拉刷新查看最新状态")
+ viewModelScope.launch {
+ FlowBus.with(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(ConstantEvent.EVENT_REFRESH).emit("refresh")
+ }
+ getTopActivity().finish()
+ }
+ }
+ }
+
+ companion object {
+ const val KEY_WB_NO = "wbNo"
+ }
+}
diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpArriveSupplementViewModel.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpArriveSupplementViewModel.kt
new file mode 100644
index 0000000..eff362a
--- /dev/null
+++ b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpArriveSupplementViewModel.kt
@@ -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
+
+/**
+ * 国际出港运抵-补充信息 ViewModel(5.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 = emptyList()
+
+ // 国家代码下拉列表
+ val countryCodeList = MutableLiveData>(emptyList())
+
+ // 通讯方式下拉列表
+ val comTypeList = MutableLiveData>(emptyList())
+
+ @Suppress("UNCHECKED_CAST")
+ fun initOnCreated(intent: Intent) {
+ val list = intent.getSerializableExtra(Constant.Key.DATA) as? ArrayList
+ // .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(后端接口暂未支持,见接口问题清单)")
+ }
+ }
+ }
+}
diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpArriveViewModel.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpArriveViewModel.kt
index 663daf9..4693b2f 100644
--- a/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpArriveViewModel.kt
+++ b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpArriveViewModel.kt
@@ -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>(emptyList())
+
+ private var phoneExtrasEnabled = false
+
+ /**
+ * 完整已加载列表(跨分页累计,未按 Tab 过滤)。
+ *
+ * ⚠️ RecyclerView/LinearLayoutManager 不会像普通 ViewGroup 那样让 `View.GONE` 的子项
+ * 自动塌陷为 0 高度——它仍按子项的测量高度参与滚动区域计算,导致"隐藏"的卡片在列表里
+ * 留下一段空白(已实机截图验证)。因此 Tab 切换不能靠给 item 加 visibility 绑定,
+ * 必须真正地把适配器的数据集替换成过滤后的子集([applyTabFilterPhone])。
+ */
+ private var allLoadedList: List = 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 ?: 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 ?: 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("maWbList" to listOf(bean))
+ if (dialogModel.resetStatusCode != null) {
+ params["restStatus"] = dialogModel.resetStatusCode
+ }
+ launchLoadingCollect({ NetApply.api.resetArriveDeclare(params.toRequestBody()) }) {
+ onSuccess = {
+ showToast("状态重置成功")
+ viewModelScope.launch {
+ FlowBus.with(ConstantEvent.EVENT_REFRESH).emit("refresh")
+ }
+ refresh()
+ }
+ }
+ }
+ dialog.show()
+ }
+
/**
* 获取数据 (重写BasePageViewModel)
*/
override fun getData() {
// 构建搜索条件
- val filterParams = mapOf(
+ val filterParams = mutableMapOf(
"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
}
diff --git a/module_gjc/src/main/res/layout-sw600dp/activity_int_exp_arrive.xml b/module_gjc/src/main/res/layout-sw600dp/activity_int_exp_arrive.xml
new file mode 100644
index 0000000..c88ab26
--- /dev/null
+++ b/module_gjc/src/main/res/layout-sw600dp/activity_int_exp_arrive.xml
@@ -0,0 +1,244 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/module_gjc/src/main/res/layout-sw600dp/item_int_exp_arrive.xml b/module_gjc/src/main/res/layout-sw600dp/item_int_exp_arrive.xml
new file mode 100644
index 0000000..1a6b1af
--- /dev/null
+++ b/module_gjc/src/main/res/layout-sw600dp/item_int_exp_arrive.xml
@@ -0,0 +1,520 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/module_gjc/src/main/res/layout/activity_int_exp_arrive.xml b/module_gjc/src/main/res/layout/activity_int_exp_arrive.xml
index 8d05466..e6523c7 100644
--- a/module_gjc/src/main/res/layout/activity_int_exp_arrive.xml
+++ b/module_gjc/src/main/res/layout/activity_int_exp_arrive.xml
@@ -1,239 +1,161 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/module_gjc/src/main/res/layout/activity_int_exp_arrive_receipt.xml b/module_gjc/src/main/res/layout/activity_int_exp_arrive_receipt.xml
new file mode 100644
index 0000000..f9d7624
--- /dev/null
+++ b/module_gjc/src/main/res/layout/activity_int_exp_arrive_receipt.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/module_gjc/src/main/res/layout/activity_int_exp_arrive_sub_order.xml b/module_gjc/src/main/res/layout/activity_int_exp_arrive_sub_order.xml
new file mode 100644
index 0000000..4e4b534
--- /dev/null
+++ b/module_gjc/src/main/res/layout/activity_int_exp_arrive_sub_order.xml
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/module_gjc/src/main/res/layout/activity_int_exp_arrive_supplement.xml b/module_gjc/src/main/res/layout/activity_int_exp_arrive_supplement.xml
new file mode 100644
index 0000000..32bc29e
--- /dev/null
+++ b/module_gjc/src/main/res/layout/activity_int_exp_arrive_supplement.xml
@@ -0,0 +1,219 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/module_gjc/src/main/res/layout/item_int_exp_arrive.xml b/module_gjc/src/main/res/layout/item_int_exp_arrive.xml
index 6b026ed..af4e1f8 100644
--- a/module_gjc/src/main/res/layout/item_int_exp_arrive.xml
+++ b/module_gjc/src/main/res/layout/item_int_exp_arrive.xml
@@ -1,511 +1,266 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/module_gjc/src/main/res/layout/item_int_exp_arrive_receipt.xml b/module_gjc/src/main/res/layout/item_int_exp_arrive_receipt.xml
new file mode 100644
index 0000000..b9b9915
--- /dev/null
+++ b/module_gjc/src/main/res/layout/item_int_exp_arrive_receipt.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/module_gjc/src/main/res/layout/item_int_exp_arrive_sub_order.xml b/module_gjc/src/main/res/layout/item_int_exp_arrive_sub_order.xml
new file mode 100644
index 0000000..db52c92
--- /dev/null
+++ b/module_gjc/src/main/res/layout/item_int_exp_arrive_sub_order.xml
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/module_p/src/main/java/com/sixin/module_p/ui/enter/gj/GjViewModel.kt b/module_p/src/main/java/com/sixin/module_p/ui/enter/gj/GjViewModel.kt
index 15e7b15..77a6405 100644
--- a/module_p/src/main/java/com/sixin/module_p/ui/enter/gj/GjViewModel.kt
+++ b/module_p/src/main/java/com/sixin/module_p/ui/enter/gj/GjViewModel.kt
@@ -54,6 +54,12 @@ class GjViewModel : BaseViewModel() {
Constant.AuthName.GjcCheckWeighing,
ARouterConstants.ACTIVITY_URL_GJC_WEIGHING_LIST
),
+ ActionBean(
+ "出港运抵",
+ R.drawable.img_gjc_chugang_diyun,
+ Constant.AuthName.GjcIntExpArrive,
+ ARouterConstants.ACTIVITY_URL_INT_EXP_ARRIVE
+ ),
// ULD管理属综合管理业务(Pad 端在「综合管理」菜单组),手机端首页暂无综合 Tab,挂在国际 Tab 下
ActionBean(
"ULD管理",
diff --git a/module_p/src/main/res/drawable-xxhdpi/img_gjc_chugang_diyun.png b/module_p/src/main/res/drawable-xxhdpi/img_gjc_chugang_diyun.png
new file mode 100644
index 0000000..430eb62
Binary files /dev/null and b/module_p/src/main/res/drawable-xxhdpi/img_gjc_chugang_diyun.png differ