Compare commits
24 Commits
ef8e7cfacb
...
feature/ph
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42647c2136 | ||
|
|
5e8fe7d69d | ||
|
|
6f813f9cff | ||
|
|
68e6c7c52b | ||
|
|
cca62aae29 | ||
|
|
1229ecc920 | ||
|
|
d2340d46fb | ||
|
|
a431c09bd0 | ||
|
|
b522efa6b9 | ||
|
|
40edbe7c67 | ||
|
|
415b685a85 | ||
|
|
b3b884504d | ||
|
|
f6b3842882 | ||
|
|
18e438550c | ||
| 0d9406af13 | |||
| c595a3046b | |||
| f90c421d44 | |||
| 49f11ef8e6 | |||
| eb0655d3fc | |||
| a33776d959 | |||
| b2a2cce585 | |||
| 3b732c3aec | |||
| 33c9f0e030 | |||
| 436202f15b |
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"api-doc": {
|
||||
"type": "http",
|
||||
"url": "https://www.agentfoxapp.com/mcp/976caff7-5f98-4487-bccf-3aa20c92cf1f",
|
||||
"headers": {
|
||||
"Authorization": "Bearer afk_G_VKmHTdXUi3GjQdg5AeHeH-0BSYQEPP"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,8 +96,6 @@
|
||||
"Read(//Library/Java/JavaVirtualMachines/**)",
|
||||
"Read(//usr/local/**)",
|
||||
"Read(//opt/homebrew/opt/**)",
|
||||
"Bash(/Users/kid/.vfox/sdks/java/bin/java -version 2>&1)",
|
||||
"Bash(export JAVA_HOME=/Users/kid/.vfox/sdks/java)",
|
||||
"mcp__apifox__read_project_oas_kcl8s7",
|
||||
"mcp__apifox__refresh_project_oas_kcl8s7",
|
||||
"mcp__apifox__read_project_oas_ref_resources_kcl8s7",
|
||||
@@ -156,10 +154,5 @@
|
||||
"ask": []
|
||||
},
|
||||
"enableAllProjectMcpServers": true,
|
||||
"enabledMcpjsonServers": [
|
||||
"空港集团 - API 文档",
|
||||
"apifox",
|
||||
"aerologic-app",
|
||||
"apidoc"
|
||||
]
|
||||
"enabledMcpjsonServers": []
|
||||
}
|
||||
|
||||
@@ -66,6 +66,10 @@ python3 $S/design_shots.py --html "…/出库交接.html" --out /tmp/design \
|
||||
返回同一批数据,一度误判为「后端不支持」;后查 api-doc 才发现正确参数名是 `handoverState`——
|
||||
后端对不认识的参数是**静默忽略**,不报错,实测只能证明「这个名字不对」,证不出「后端没这能力」。
|
||||
|
||||
「参数是否真的生效」的 A/B 验证优先走 Proxyman MCP(`create_compose_http_from_flow` 复制
|
||||
真实请求改参重发,token 自动带上),分工与流程见 `references/proxyman.md`:
|
||||
**api-doc 管契约(该有什么),Proxyman 管事实(实际发/回了什么)**。
|
||||
|
||||
核对完把结论落两处(模板与格式见 `references/api-doc.md`):
|
||||
|
||||
- 后端真实缺口(缺入参/缺出参/数据不回填)→ 记入 `documents/后端接口对接问题清单.xlsx`,
|
||||
@@ -232,9 +236,12 @@ $P <phone> tap-text "已交接" # 按文字点击,比手算坐标可靠
|
||||
$P <phone> texts # 用文字变化断言点击确实生效(如底部条应消失)
|
||||
$P <phone> shot /tmp/p1.png
|
||||
$P <phone> crash # 必须为 0
|
||||
$P <phone> req pageQuery # 核对请求体参数确实带上了新字段
|
||||
```
|
||||
|
||||
核对请求/响应体优先用 Proxyman MCP(`filter_flows` + `get_flow_detail`,比 `req` 的
|
||||
logcat 抓包完整可靠;模拟器代理一行命令接入,见 `references/proxyman.md`);
|
||||
Proxyman 不可用时兜底 `$P <phone> req pageQuery`。
|
||||
|
||||
逐项走查:列表/卡片两种形态、详情页、筛选弹层(重置+确认)、Tab 切换、单选与全选联动、
|
||||
下拉真实取数、扫码入口。每步 `crash` 都要为 0。
|
||||
|
||||
@@ -253,7 +260,12 @@ $P <phone> req pageQuery # 核对请求体参数确实带上了新字段
|
||||
**空值兜底**(真实数据空字段很常见——出库交接就出现过「库位」为空时橙色高亮标签只剩一个孤零零的
|
||||
小色块,需要空值时不套标签底)。
|
||||
|
||||
服务端当天没数据时(列表空)先放宽条件重查;仍为空就临时在 Activity 里注入样例 Bean 截图比对:
|
||||
服务端当天没数据时(列表空)先放宽条件重查;仍为空、或要覆盖真实数据凑不出的形态
|
||||
(空字段、超长文本、罕见状态标签),**首选 Proxyman Map Local 造 mock**——零代码改动、
|
||||
零重构建,见 `references/proxyman.md` 场景 3(2026-07-31 出港查询用它一次验完
|
||||
已离港/已入库/未入库三种卡片形态)。验证完 `delete_rule` + 清模拟器代理。
|
||||
|
||||
Proxyman 不可用时才退回老办法:Activity 里临时注入样例 Bean 截图比对:
|
||||
|
||||
```kotlin
|
||||
// import com.lukouguoji.module_base.ktx.commonAdapter
|
||||
@@ -287,6 +299,7 @@ binding.rv.postDelayed({
|
||||
## 参考文件
|
||||
|
||||
- `references/api-doc.md` — api-doc MCP 连接与逐接口核对流程、后端缺口记录规范、已核对字段语义(阶段 2 前读)
|
||||
- `references/proxyman.md` — Proxyman MCP 抓包/直调 A/B/Map Local mock 的接入与四个场景(阶段 2、5、6 用;与 api-doc 的分工:契约 vs 事实)
|
||||
- `references/components.md` — 7 个手机版公共组件的属性表、用法与封装新组件的规矩(写布局前读)
|
||||
- `references/pad-safety.md` — 布局变体约束、Pad 零破坏模式、易崩点(写代码前读)
|
||||
- `references/verification.md` — 双端 adb 命令、登录与直启、已知环境坑(验证前读)
|
||||
|
||||
@@ -77,6 +77,60 @@ curl -s -X POST "$URL" -H "$AUTH" -H "Content-Type: application/json" \
|
||||
分单补充收发货人信息**后端完全没有对应接口**(`search_endpoints` 对 `IntExpArrive`/`HaWb`
|
||||
关键字均搜不到分单更新接口,只有国际进港的 `IntImpAirManifest/complete`),
|
||||
实机调用拟定路径 `IntExpArrive/haWb/supplement` 确认 404(缺口 #19)
|
||||
- `IntExpSearch`(出港查询,2026-07-31 内网实测):查询入参 `outState`/`fno`/`dest`/`spCode`/`awbType`/
|
||||
`businessType`/`goodsCn`/`beginDate`/`endDate`/`agentCode`/`wbNo` 全部真实生效(平板既有口径);
|
||||
文档定义的 `isFclose`(筛选航班是否关闭)**pageQuery 与 pageQueryTotal 均静默忽略**(A/B 对照
|
||||
全量 72 票与单日两组,加参前后结果完全一致,缺口 #21);`pageQueryTotal` 出参无已入库/已离港
|
||||
分项计数(#21);`detail` 出参 Map 无 `lockStatus`(锁定状态)与计费重量字段(#22);
|
||||
详情「入库件数/入库重量」= `warehouseList` 各批次 pc/weight 求和(mock 与实测均吻合);
|
||||
卡片状态推断口径:`fclose` 非空=已离港、否则 `opDate` 非空=已入库;
|
||||
特码字典沿用 `DictUtils.getSpecialCodeList(flag=1, ieFlag="")`(ieFlag 必须空串)
|
||||
- `IntExpStorageUse`(出港仓库,2026-07-31 文档核对,内网 A/B 未测——当日开发机不在内网):
|
||||
`pageQuery`/`pageQueryTotal` 同一套入参 schema:`fdate`/`fno`/`wbNo`/`likeNo`/`spCode`/`dest`/
|
||||
`agentCode`/`location`/`clearNormal`/`checkIn`/`reviewStatus`/`dep`/`hno`/`prefix`;设计稿筛选的
|
||||
**运单类型/业务类型/品名(中) 均无入参**(`awbType`/`businessType`/`goodsCn`,缺口 #23);
|
||||
手机三格统计按 `clearNormal=0/1` 各调一次 `pageQueryTotal` 取 `wbNumber`,该过滤**是否真实生效
|
||||
待内网 A/B**(缺口 #24,参照 isFclose 有定义但被忽略的先例);出参 `clearNormal` 0=未清仓/1=已清仓
|
||||
(卡片标签与「清仓」按钮置灰按 ==\"1\" 判定);详情复用 `IntExpSearch/detail`(maWbId Query 参数)
|
||||
- `IntImpStorage`(进港仓库,2026-07-31 文档核对;**注意前端 Api.kt 路径前缀是 `IntImpStorage`
|
||||
不是 `IntImpStorageUse`**,api-doc 按后者搜不到):`pageQuery`/`pageQueryTotal` 同一套入参:
|
||||
`fdate`/`fno`/`wbNo`/`hno`/`fdep`(始发站)/`location`/`clearNormal`/`fid`;比出港仓库还少
|
||||
`agentCode`/`spCode`/`dest`——设计稿筛选的代理/特码/运单类型/业务类型/品名(中) **5 项均无入参**
|
||||
(缺口 #25);分项统计与 clearNormal 过滤待实测同 #24(记为 #26);详情复用
|
||||
`IntImpSearch/detail`(Body 传 `prefix`+`no`,出参 `data.maWb` 无 schema,字段 key 以平板绑定为准:
|
||||
`awbPc`/`awbWeight`/`cashWeight`/`inPc`/`inWeight`/`lockState`(0/1 需转中文)/`mftStatus` 原始舱单/
|
||||
`tallyStatus` 理货报告/`command` 海关放行/`by1` 承运人/`dlvTime` 出库时间;`dep`/`dest1`/`dest`/
|
||||
`unNumber`/`opDate` 为按出港推断,待实测 #27)
|
||||
- `IntImpPickUpDlv`(提取出库,2026-07-31 文档核对):`pageQuery` 入参含 **`outState`
|
||||
(0 未出库/1 已出库)**——待出库/已出库 Tab 直接真实过滤(抓包证实携带,效果待内网 A/B #29);
|
||||
另有 `fno`/`dest`/`origin`/`carrier`/`awbType`/`businessType`/`goods`/`likeNo`/`pkId`/
|
||||
`beginDate`/`endDate`+`dateType`(0 入库/1 离港)/`chargeFlag`(0 未提取/1 已提取);
|
||||
**无 `fdate`(航班日期)入参**(缺口 #28);出参无车牌/目的港/业务类型名称(#28);
|
||||
运单号筛选参数名是 **`no`**(平板既有口径);`chargeName`/`chargeTime` = 柜台办理人/缴费(提取)时间,
|
||||
`dlvTime` = 出库时间,`dlvName` 按提货人语义推断作「出库人」展示(待确认 #29);
|
||||
确认出库接口 `pickUpOut` 文档注明**需将全字段传至后端**(平板 `selectedItems.toRequestBody()` 已满足)
|
||||
- `IntImpSearch`(进港查询,2026-07-31 文档核对):`pageQuery`/`pageQueryTotal` 分页参数名是
|
||||
**`page`/`limit`**(不是 pageNum/pageSize);手机筛选 9 项入参全部真实存在:`beginDate`/`endDate`/
|
||||
`fno`/`agentCode`/`spCode`/`origin`(始发站)/`awbType`/`businessType`/`goods`(品名,**不是 goodsCn**);
|
||||
`outState`(0 未出库/1 已出库)文档为 integer,前端传字符串靠 Jackson 隐式转换;`pageQueryTotal`
|
||||
出参无已入库/已出库分项计数(缺口 #30,手机三格统计为客户端计数口径:dlvTime 非空=已出库、
|
||||
inDate 非空=已入库);出参含 `agentName`(中文名)+ `agentCode`,agentName 可为 null
|
||||
- 「进港移库」(设计稿 11)**归属更正(2026-08-03 用户确认):属国内进港移库 `DomImpMove`**,
|
||||
不是国际进港移库——「后端模块缺失」的旧结论(原缺口 #31)作废,原按 IntExpMove 约定预接的
|
||||
IntImpMove 前端实现已整体删除。溯源:api-doc 53 模块中移库仅 `DomImpMove`(国内进港,8 接口)与
|
||||
`IntExpMove`(国际出港,4 接口),移库按转关业务前缀划分(DomImpMove 处理 `CI**`、IntExpMove
|
||||
处理 `IO**`),设计稿详情卡的「国际进港」红标签实为 `awbType` 值(如「国际进港(国内中转)」),
|
||||
不代表页面归属
|
||||
- `DomImpMove`(国内进港移库,2026-08-03 内网实测):手机 Tab 双端点——待移库 `search` /
|
||||
已移库 `searchMoved`(同一套入参 schema,分页参数名 **`page`/`limit`**);入参 A/B 实测:
|
||||
**`wbNo`、`awbType`(值为 CICO/CIII/CIIO 转关码)过滤生效;`fdate`/`fno`/`spCode` 文档有定义但
|
||||
被静默忽略**(缺口 #32);`searchMoved`/`detail` 出参 **`opId`/`opDate` 恒 null** 且无操作人姓名
|
||||
字段(缺口 #33,移库人/移库时间显示"-"),`moveId` 形如 `CICO240617155016` 疑似内嵌移库时间戳但无
|
||||
文档语义;`searchMoved` 出参**无 pic 三字段**(search 有)——拍照上传页统一先调 `GET detail`
|
||||
回填已有照片(#34 前端已规避);照片提交走 `modify` 最小体
|
||||
`{mawbId, remark, picNumber, pic, originalPic}`(平板移交编辑页同链路,removeEmptyOrNull);
|
||||
批量移库 `move` 入参 `{fid:"0", ids:[mawbId]}`;国内进港特码字典
|
||||
`DictUtils.getSpecialCodeList(flag=0, ieFlag="I")` 实测取数正常
|
||||
- `IntExpCheckIn`(出港计重,2026-07-29 内网实测):`likeNo` **并非任意模糊**——按 8 位 `no`
|
||||
匹配(11 位 wbNo 或部分号均 0 条),11 位全号必须走 `wbNo`;`checkIn`/`checkInList`
|
||||
文档有定义但 `pageQuery`/`pageQueryTotal` **均静默忽略**(缺口 #12,待计重/计重中计数依赖);
|
||||
@@ -104,3 +158,30 @@ curl -s -X POST "http://192.168.1.250:8093/IntExpOutHandover/pageQuery" \
|
||||
用它做「参数是否生效」的 A/B 对比(同条件只改一个参数看 total 变化),
|
||||
再回 App UI 走一遍确认端到端链路。UI 里的滚轮日期选择器可用
|
||||
`input swipe`(慢速 500ms、每次 3 格 ≈ 396px)驱动,滑完截图校准。
|
||||
|
||||
## 2026-10-09 后端反馈联调后的最新口径(与上文冲突时以本节为准)
|
||||
|
||||
后端在问题清单补「解决方案」后逐项内网实测的结论。**通用规则:后端对手机端新增筛选维度一律答复
|
||||
「与平板端查询参数保持一致」——手机筛选只放平板已用的入参;文档里定义了但平板没用的入参,
|
||||
多数实测也被忽略(agentCode/spCode/dest/opId 等),别再按文档加筛选。**
|
||||
|
||||
- **统一统计 DTO**:各 `*/pageQueryTotal` 出参现含 `uldNumber`/`storedNumber`/`departedNumber`/
|
||||
`notClearNumber`/`clearNumber`/`waitCheckInNumber`/`checkingNumber`/`flightNumber`(`ManifestTotalDto`
|
||||
已补齐)。分项统计一律取出参,**不要再按状态入参多调几次 total**
|
||||
- `IntExpOutHandover/pageQueryTotal` 已修复(与列表一致);Tab 角标取 `uldNumber`(板箱数);无交接人入参
|
||||
- `IntExpMove/pageQuery` 出参新增 `flight`("20260924/MU2222")/`businessName`/`opUserName`;已移库 `opId`/`opdate` 已回填
|
||||
- `eqm/uld`:状态维持两态;`source`(空运/陆运) 出参与保存入参支持、**查询入参不支持**;入库时间 = `inStoreTime`
|
||||
(date-time,**只传日期 400**)、所在港 = `nowPort`;批删 `deleteUldBatch`(Body 为字符串数组);
|
||||
⚠️ `pageQuery` 带 `uld` 即 500(#35);`saveUld` 缺 `maxVolume`/`maxWeight` 即 500(#36)
|
||||
- `IntExpCheckIn`:`listRecordByWh` 出参 `opUserName`/`trayNumber`/`trayTotalWeight`;
|
||||
`checked/pageQuery` 出参 `passageWay`;`splitCheckIn`/`completeCheckIn` 托盘入参 = `trayNumber` +
|
||||
`trayTotalWeight`(数量×自重);`arriveFlag` 已回填("0" 正常/"1" 提前运抵);
|
||||
⚠️ `pageQuery` 的 `checkIn` 过滤仍被忽略(#40,统计用分项出参);`checked/pageQuery` 的 `dest`/`opId` 被忽略
|
||||
- `IntExpArrive`:入参 `arrivalStatus`("0" 未运抵/"1" 已运抵)服务端过滤生效;`agentCode` 被忽略;补充信息页已删除
|
||||
- `IntExpSearch`:**`beginDate`/`endDate` 只有携带 `dateState`(0 入库/1 离港)才生效**;`outState` 生效
|
||||
- `IntExpStorageUse`:仅 `fdate`/`fno`/`wbNo`/`location`/`clearNormal` 有意义;⚠️ 列表 total 与统计 wbNumber 不一致(#38)
|
||||
- `IntImpStorage`:⚠️ `pageQuery` 当前**所有**过滤条件均失效(#37),`pageQueryTotal` 正常
|
||||
- `IntImpSearch/detail`:按平板展示 航程 `range`(无经停站)/`unNumber`/`lockState`/出库时间 `dlvTime`
|
||||
- `IntImpPickUpDlv`:运单号入参用 `wbNo`;出参新增 `refUserName`(出库人姓名,`dlvName` 是提货人);测试环境暂无数据
|
||||
- `DomImpMove`:`fdate`/`fno`/`spCode` 已生效;`searchMoved` 已回填 `opId`/`opDate`/`opUserName`;
|
||||
新增 `GET movedDetail?moveId=`(含 pic 三字段);⚠️ 已移库运单无 `mawbId`,`modify` 无法补传照片(#39)
|
||||
|
||||
@@ -16,13 +16,17 @@
|
||||
| `PhoneFilterPanel` | 底部筛选弹层(遮罩 + 面板 + 重置/确认) | `title`、`panelVisible`、`setOnResetClick`、`setOnConfirmClick`、`setOnDismissClick` |
|
||||
| `PhoneBottomBar` | 底部操作条(全选 + 已选统计 + 主按钮) | `allChecked`、`countText`、`actionText`、`setOnAllCheckClick`、`setOnActionClick` |
|
||||
| `PhoneStatBox` | 卡片内 2~4 列统计框,未传 label 的列自动隐藏 | `label1..4`、`value1..4` |
|
||||
| `PhoneKvItem` | 详情页字段项(灰标签 + 数值) | `title`、`value`、`tag`(true → 橙色高亮标签) |
|
||||
| `PhoneKvItem` | 详情页字段项(灰标签 + 数值) | `title`、`value`、`tag`(true → 高亮标签)、`tagColor`("orange" 默认 / "green" 放行正常态);占位符 "-"/"--" 不套标签底 |
|
||||
| `PhoneFormRow` | 行式表单项(左标签 minWidth 110dp + 右值 + 1px 分隔线),覆盖新增/修改/详情三态表单 | `title`、`hint`、`type`(`PhoneFormRowType.INPUT`/`SELECT`/`DATE`/`TEXT`)、`value`(双向)、`list`(SELECT 选项)、`required`、`enable`、`numeric`、`setRefreshCallBack` |
|
||||
|
||||
`PhoneFormRow` 要点:SELECT 内置 XPopup 底部选择面板(点击整行弹出,无需页面代码);TEXT 为只读右对齐、
|
||||
空值自动占位 "--"(详情态);type 用三元按 `pageType` 切换即可一套布局覆盖三态页面(参考
|
||||
`app/res/layout/activity_uld_edit.xml`)。`PhoneBottomBar` 的 `actionDanger="@{true}"` 切浅红删除按钮。
|
||||
|
||||
`PhoneFilterPanel` 内容插槽已内置 ScrollView(2026-07-31 加):筛选项少时行为不变;
|
||||
筛选项多到超屏(出港查询 9 项)时内容区收缩滚动,底部「重置/确认」按钮始终可见——
|
||||
此前无滚动时按钮会被挤出屏幕外且毫无报错,只表现为"点不到确认"。
|
||||
|
||||
⚠️ 两个已踩坑:
|
||||
- **FAB 盖住弹层**:浮动按钮带 elevation 时会浮在 `PhoneFilterPanel` 之上,弹层实例要加
|
||||
`android:elevation="8dp"`(> FAB 的 6dp)
|
||||
@@ -129,6 +133,8 @@ android.util.Log.d("DBG", "value '$field' -> '$v'", Throwable("trace"))
|
||||
`ic_phone_chevron_right/down` `ic_phone_calendar` `ic_phone_close`
|
||||
`ic_phone_check_round_checked/unchecked`(圆形复选框)
|
||||
`ic_phone_clipboard`(剪贴板,白色 FAB 用)`ic_phone_weight`(砝码,可 tint)
|
||||
`ic_phone_package`(件数)`ic_phone_tag`(特码/标签)
|
||||
- 圆点:`bg_phone_dot_green/blue/gray`(状态指示点;蓝=出港查询卡片头,灰=时间线未达节点)
|
||||
- 复用 Pad 的矢量图:`img_search` `img_scan` `img_filter`(可 `app:tint` 染色)
|
||||
|
||||
设计稿里的 MDI 图标若缺失,直接写 24×24 的 vector(用 MDI 官方 path),比找位图靠谱且能染色。
|
||||
|
||||
@@ -44,6 +44,26 @@ com/lukouguoji/gjc/databinding/ItemXxxBinding.java
|
||||
`activity_xxx_phone.xml` 会生成 `ActivityXxxPhoneBinding`,而字段声明的类型是
|
||||
`ActivityXxxBinding`。泛型擦除让**编译期查不出来**,一进页面就 `ClassCastException`。
|
||||
|
||||
### 弹框(BaseDialogModel)也要双变体,最容易漏
|
||||
|
||||
页面布局适配完,长按/批量操作弹出的 DialogModel 仍会以 Pad 居中样式出现在手机上
|
||||
(出港运抵的「状态重置」就漏过)。做法与页面完全同构:
|
||||
|
||||
1. dialog 布局 `git mv` 到 `layout-sw600dp/`,`layout/` 下写同名手机版(设计稿通常是底部弹层:
|
||||
`bg_phone_panel_top` + 居中标题 + `ic_phone_close` + 全宽 `bg_phone_btn_primary` 确定键)
|
||||
2. 弹出位置在构造参数按形态切换(XPopup 位置与布局是两回事,都要改):
|
||||
|
||||
```kotlin
|
||||
class XxxDialogModel(...) : BaseDialogModel<DialogXxxBinding>(
|
||||
if (DeviceUtil.isPhone()) DIALOG_TYPE_BOTTOM else DIALOG_TYPE_CENTER
|
||||
)
|
||||
```
|
||||
|
||||
3. 两变体 `<variable>` 一致(imports 不要求一致)
|
||||
|
||||
参考:`IntExpArriveResetDialogModel` + `dialog_int_exp_arrive_reset.xml` 双变体。
|
||||
**适配收尾时逐个 grep 该页 ViewModel 里 `DialogModel(` 的调用点**,每个弹框都过一遍。
|
||||
|
||||
## 业务层零破坏的三个模式
|
||||
|
||||
### 新增查询维度:默认空值 + 仅非空进请求
|
||||
|
||||
80
.claude/skills/phone-adapt/references/proxyman.md
Normal file
80
.claude/skills/phone-adapt/references/proxyman.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# Proxyman MCP:抓包 / 直调 / Mock(阶段 2、5、6 的调试利器)
|
||||
|
||||
Proxyman 桌面端 + `mcp__proxyman__*` 工具(会话内直接可用,缺 schema 时用 ToolSearch
|
||||
`select:mcp__proxyman__get_flows,...` 加载)。**2026-07-31 已在出港查询页全链路实测**:
|
||||
抓包核对请求体、Map Local mock 三种卡片形态(含真实数据不存在的「未入库」兜底态)一次跑通。
|
||||
|
||||
## 与 api-doc 的分工(先契约后事实)
|
||||
|
||||
| | api-doc MCP | Proxyman MCP |
|
||||
|---|---|---|
|
||||
| 回答什么 | **契约**:接口该有什么入参/出参、参数名叫什么 | **事实**:App 实际发了什么、后端实际回了什么 |
|
||||
| 用在何时 | 阶段 2 开工前逐接口核对 | 阶段 5/6 实机验证与 corner case 补测 |
|
||||
|
||||
标准配合流程:
|
||||
api-doc 拿权威参数名 → 前端实现 → Proxyman flow 核对请求体确实带上了 →
|
||||
compose 改参 A/B 验证后端认不认 → 不认 → 记问题清单(附 `export_flow_curl` 证据)→
|
||||
map local 造 mock 补 UI corner case 验证。
|
||||
|
||||
## 接入(一次性,实测步骤)
|
||||
|
||||
```bash
|
||||
# 1) 确认 Proxyman 在跑(返回 Recording: Active + 端口,默认 9090)
|
||||
# mcp__proxyman__get_proxy_status
|
||||
# 2) 模拟器全局代理指向宿主机(模拟器视角宿主机 = 10.0.2.2)
|
||||
adb -s <serial> shell settings put global http_proxy 10.0.2.2:9090
|
||||
# 3) 验证完【必须】清掉,否则 Proxyman 一关模拟器就断网,下次验证莫名全挂
|
||||
adb -s <serial> shell settings put global http_proxy :0
|
||||
```
|
||||
|
||||
本项目内网服务是**纯 HTTP**(192.168.1.250:8093)→ 不需要装证书,明文直接可见。
|
||||
(若未来切 HTTPS,才需要 `install_certificate` + `enable_ssl_proxying`。)
|
||||
|
||||
## 场景 1:核对请求/响应(替代 `ui_probe req`)
|
||||
|
||||
logcat 抓 OkHttp 多行 pretty JSON 脆弱且要人肉拼接;Proxyman 一步到位:
|
||||
|
||||
- `filter_flows`(key=url, value="IntExpSearch")→ 拿 flow ID 列表
|
||||
- `get_flow_detail`(flow_id)→ 完整请求体 + 响应体 + headers(Authorization 自动脱敏)
|
||||
|
||||
**出参无文档定义时(如 `IntExpSearch/detail` 返回裸 Map),用真实 flow 的 responseBody
|
||||
直接盘点字段清单**——判定「锁定状态/计费重量是否存在」这类问题的最快路径。
|
||||
|
||||
## 场景 2:直调后端 A/B 验证(替代 run-as 提 token + 手写 curl)
|
||||
|
||||
`create_compose_http_from_flow`(从真实 flow 复制请求,**token 自动带上,不用碰
|
||||
shared_prefs**)→ `update_compose_http` 改一个参数 → `send_compose_http` 看结果对比。
|
||||
isFclose 这类「参数是否生效」的 A/B 实验用这条链。给后端提缺口时用
|
||||
`export_flow_curl` 导出可复现的 curl 附进问题清单。
|
||||
|
||||
## 场景 3:Map Local 造 mock 验证 corner case(替代代码注入样例 Bean)
|
||||
|
||||
老流程「Activity 临时注入 Bean → 截图 → 删码 → 重构建」彻底淘汰:**零代码改动、零重构建**。
|
||||
|
||||
- `create_map_local`:url 精确到接口路径,method=POST,response_body 直接写目标 JSON
|
||||
(构造空字段/超长文本/罕见状态,比如出港查询的 fclose+opDate 双空「未入库」兜底态)
|
||||
- 改真实响应个别字段更省事时用 `create_map_local_from_flow`
|
||||
- 验证完 `delete_rule`(rule_type=maplocal)+ 清代理,**规则残留会污染后续真实数据验证**
|
||||
|
||||
响应结构照抄真实 flow 的顶层结构(如 pageQuery 是裸 PageInfo:`{total, list, pages, ...}`,
|
||||
不要包 `{status, data}`)。
|
||||
|
||||
⚠️ 实测坑(2026-07-31 出港仓库):mock `BaseResultBean` 包装的接口(pageQueryTotal/detail 等)时,
|
||||
**`status` 必须写 `"1"`**——`BaseResultBean.verifySuccess()` 判 `status == "1"`,写 "200" 会被当失败
|
||||
静默丢弃(UI 保持默认值,无任何报错,排查靠 flow 已命中但 UI 不变这一矛盾现象)。
|
||||
|
||||
⚠️ 实测坑:mock 响应到达后 UI 渲染可能滞后(冷启动首帧 Davey 卡顿 2s+),
|
||||
**截图断言前先 `ui_probe texts` 确认数据已上屏**——这次就因截图太早误判过一轮「mock 没生效」,
|
||||
其实 `get_flow_detail` 里 `matchedTools: ["Map Local"]` 早已证明规则命中,UI 只是还没画完。
|
||||
|
||||
## 场景 4:环境模拟(按需)
|
||||
|
||||
- `create_network_condition`:弱网/高延迟,验证 loading 弹窗与超时提示
|
||||
- `create_breakpoint`:单次拦截改包(比 map local 更临时的一次性实验)
|
||||
- `create_map_remote`:把请求转发到另一环境(如后端修复验证用的测试实例)
|
||||
|
||||
## 验证收尾清单
|
||||
|
||||
- [ ] `list_rules` 确认无本次遗留规则(maplocal/breakpoint/network_condition)
|
||||
- [ ] 模拟器代理已清(`settings get global http_proxy` 应为 `:0` 或空)
|
||||
- [ ] 用真实数据再过一遍被 mock 过的页面,确认无假数据残影
|
||||
@@ -6,12 +6,12 @@
|
||||
## 环境
|
||||
|
||||
```bash
|
||||
~/Library/Android/sdk/emulator/emulator -list-avds # Medium_Phone_API_36.1(手机) / Aerologic_Tablet(平板)
|
||||
/opt/homebrew/share/android-commandlinetools/emulator/emulator -list-avds # 本机现仅 AeroLogic_Phone(手机)
|
||||
adb devices -l
|
||||
adb -s <serial> shell wm size && adb -s <serial> shell wm density
|
||||
```
|
||||
|
||||
判定形态:手机 1080×2400@420dpi → `PHONE(sw=411dp)`;平板 1280×800@160dpi → `TABLET(sw=800dp)`。
|
||||
判定形态:手机 720×1440@292dpi → `PHONE(sw≈394dp)`;平板 1280×800@160dpi → `TABLET(sw=800dp)`(本机平板 AVD 待建,见文末工具选型纪要)。
|
||||
|
||||
`ui_probe.sh` 封装了常用操作,比手写 adb 省事且更可靠:
|
||||
|
||||
@@ -46,7 +46,7 @@ adb -s <serial> install -r -d app/build/outputs/apk/debug/app-debug.apk
|
||||
adb -s <serial> shell monkey -p com.lukouguoji.aerologic -c android.intent.category.LAUNCHER 1
|
||||
```
|
||||
|
||||
测试环境账号在记忆文件 `test-env-login.md`(ADMIN / 用户已授权保存),可自主登录。
|
||||
测试环境账号在记忆文件 `aerologic-test-account.md`(本机,admin / 用户已授权保存;旧机器文件名为 `test-env-login.md`),可自主登录。
|
||||
填表用 `input text`,**`#` 不需要转义**——新版 adb 的 input text 参数不经远端 shell 解析,
|
||||
写 `\#` 反而会把 `\` 也输进去(实测多出一位)。
|
||||
|
||||
@@ -179,3 +179,88 @@ adb -s <serial> logcat -d -s DBG | grep -A14 "'旧值' -> ''" | grep "at com.luk
|
||||
|
||||
本次靠这招定位到 `TextView.onRestoreInstanceState → EditText.setText → doOnTextChanged`,
|
||||
即复合自定义 View 的 id 串档(见 `components.md`)。**排完删日志。**
|
||||
|
||||
---
|
||||
|
||||
## 工具选型纪要:ADB(ui_probe.sh) × Mobile MCP 分工(2026-10-02)
|
||||
|
||||
背景:`mobile-mcp`(`@mobilenext/mobile-mcp`)已装入项目级 `.mcp.json`,与本手册的
|
||||
ADB/ui_probe.sh 流程并存。以下基于 2026-10-02 在 `AeroLogic_Phone` 模拟器上的实测对比
|
||||
(登录流程实测到“填表”一步,因内网不通放弃后续),给出后期开发的工具选择规则。
|
||||
|
||||
### 能力对照(只列有差异的维度)
|
||||
|
||||
| 维度 | ADB + ui_probe.sh | Mobile MCP |
|
||||
|------|-------------------|------------|
|
||||
| 元素定位 | `tap-text` 按文字点,**每次点击前重新 dump**,天然抗布局变化;同名多处可指定序号 | 按 ref 点,键盘弹出/页面导航后 **ref 失效**,必须重新 list(实测踩过) |
|
||||
| 元素读取 | `texts` 只出可见文字,token 便宜,配 grep 断言(`texts \| grep -c "全选"`) | 完整控件树(text/id/类型/focused/disabled/checked/坐标),信息全但 **token 重**(登录页 54 行) |
|
||||
| 文本输入 | `input text` + `keycombination`(CTRL+A/DEL 清空——登录 bcrypt 回填坑的标准解法) | `type_keys` 只能输入,**无清空原语**(实测需回落 adb) |
|
||||
| 请求核对 | `req <关键字>`(OkHttp 多行 pretty JSON 按关键字截取,为本项目定制) | `get_device_logs` 可过滤 tag/进程,多行报文截取不如 `req` 顺手 |
|
||||
| 崩溃检查 | `crash` | `list_crashes` / `get_crash`(等价) |
|
||||
| 前台断言 | `dumpsys activity`(手写 grep) | `get_foreground_app` 一次调用 |
|
||||
| 录屏 | `adb shell screenrecord`(手拉文件) | `start/stop_screen_recording` 直接回传路径,更省事 |
|
||||
| 批量操作 | 脚本串联,每条一次往返 | `mobile_batch_commands` 一次往返多步(**页面稳定时**才高效) |
|
||||
| iOS / 云真机 | 无 | 有(本项目 Android-only,暂无用武之地) |
|
||||
| 依赖 | 零依赖(本机 adb 即可) | npx 每会话冷启动、Node 20+、`@latest` 有版本漂移风险(建议固定 `@1.0.7`) |
|
||||
|
||||
### 选型规则(后期开发按此执行)
|
||||
|
||||
**默认走 ADB + ui_probe.sh**。本手册全部流程不变:构建安装、冷启动/直启、登录、
|
||||
wait-text 就绪等待、tap-text 交互、texts 断言、req 抓包、crash 归零、方向采样、Pad 回归、
|
||||
样例 Bean 注入。理由:为本项目的坑定制(bcrypt 回填、Loading 吞点击、参数名 A/B)、
|
||||
token 成本低、零外部依赖,且 tap-text 每次重新 dump,比 ref 更抗布局变化。
|
||||
|
||||
**以下四种场景切 Mobile MCP**:
|
||||
|
||||
1. **控件级语义断言**——要看 disabled/checked/focused 状态、控件 id、输入框变换后的值
|
||||
(如“密码框 9 个点”“角色 Spinner 是否禁用”“用户名框自动大写成 ADMIN”)。元素树比
|
||||
截图肉眼判读可靠,比 `texts` 信息全。实测:登录页一次拿到 `inputPass text="•••••••••"`、
|
||||
角色 Spinner `disabled`,这类断言 `texts` 做不到(密码框无明文文字)
|
||||
2. **页面稳定时的多步连续输入**——list 一次拿 ref,`batch_commands` 一次往返完成
|
||||
tap→type→tap→type;比逐条 adb 省 round-trip。前提:中间不弹键盘收不起/不导航
|
||||
(弹了就见下方回落规则)
|
||||
3. **录屏取证**——复现“先横屏闪 1 秒”类**时序 bug**,mp4 归档进问题清单,比连拍截图省力
|
||||
4. **前台应用/安装卸载等状态核查**——`get_foreground_app`、`install/uninstall/launch_app`
|
||||
一步到位,省得记 dumpsys/am 语法
|
||||
|
||||
**回落规则(两者随时可混用,操作同一设备无状态冲突)**:
|
||||
|
||||
- mobile-mcp ref 失效(键盘弹出/导航后点击落空)→ 重新 `list_elements`,或直接换
|
||||
`ui_probe.sh tap-text`(按文字,永远新鲜)
|
||||
- 需要清空输入框(登录 bcrypt 回填)→ 只能 adb:`input keycombination 113 29` + DEL
|
||||
- 多行请求/响应体核对 → `req`,不用 mobile-mcp 的日志过滤硬凑
|
||||
|
||||
### 实测踩坑(Mobile MCP,2026-10-02)
|
||||
|
||||
- ⚠️ **键盘弹出会平移布局**:之前 list 出的 ref/坐标失效。batch 里连续 click+type 会把
|
||||
两段文本打进同一个框(用户名框变成 `ADMINAA123456#`)。规避:每步输入完先
|
||||
`KEYCODE_BACK` 收键盘再点下一个目标;或点完先确认焦点再 type
|
||||
- 无“清空字段”原语;`type_keys` 输入即所得,不会帮你选中文本
|
||||
- 元素树 token 开销大,断言优先 `texts | grep`,确实要看状态/id 才上 list_elements
|
||||
|
||||
### 本机环境更新(2026-10-02)
|
||||
|
||||
- SDK 根目录:`/opt/homebrew/share/android-commandlinetools`(brew 安装,emulator 包已装)
|
||||
- 手机 AVD:`AeroLogic_Phone`——720×1440、5.51 寸 292dpi(sw≈394dp,落手机桶 360~411dp)、
|
||||
Android 12 / API 31(与 targetSdk 一致)、arm64 纯 64 位(本项目无 abiFilters,唯一含
|
||||
.so 的 fimage.aar 自带 arm64-v8a,兼容)、无边框(`showDeviceFrame=no`)
|
||||
- ⚠️ **旧文档里的 `Aerologic_Phone_5.5_API31`(300dpi/sw=384dp)、`Medium_Phone_API_36.1`、
|
||||
`Aerologic_Tablet` 均为旧机器 AVD,本机不存在**。平板回归前需先建平板 AVD
|
||||
(1280×800@160dpi,`avdmanager create avd` 后照本文「Pad 端回归」执行)
|
||||
- 启动:`/opt/homebrew/share/android-commandlinetools/emulator/emulator -avd AeroLogic_Phone`
|
||||
(Quick Boot 快照已存在,二次启动数秒就绪)
|
||||
- 模拟器 NAT 出网,**内网服务不可达**(本次登录实测“服务器不通”而放弃)——需要真实接口
|
||||
联调时先确认宿主机网络可达内网;不可达时按上文「无数据时怎么核对 UI」注入样例 Bean
|
||||
- `.mcp.json` 已加 `mobile-mcp` 条目(npx stdio),**建议把 `@latest` 固定为 `@1.0.7`**;
|
||||
该文件 git 跟踪,改动需提交后队友才可用
|
||||
|
||||
### 推荐配合模式(单页验证的完整动线)
|
||||
|
||||
adb 骨架 + mobile-mcp 点睛,一条龙:
|
||||
|
||||
1. **adb**:构建安装 → 冷启动/直启(`am start`)→ 按登录节填表(含 bcrypt 清空顺序)
|
||||
2. **ui_probe**:`wait-text` 就绪 → `tap-text` 交互 → `texts | grep` 断言 → `req` 抓包 → `crash` 归零
|
||||
3. `texts` 断言不够(要看状态/id/变换值)或要连续多步输入 → **mobile-mcp**:
|
||||
`list_elements` → `batch_commands`(tap/type)
|
||||
4. 时序类 bug(闪屏/动画/异步错位)→ **mobile-mcp 录屏**取证,问题清单贴 mp4 + 截图
|
||||
5. 全程崩溃检查两家等价(`crash` / `list_crashes`),任选
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -191,8 +191,6 @@ fabric.properties
|
||||
!/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/androidstudio,gradle,java,kotlin
|
||||
.vfox/
|
||||
.vfox/sdks/java
|
||||
|
||||
# Auto Claude data directory
|
||||
.auto-claude/
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"mobile-mcp": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "@mobilenext/mobile-mcp@1.0.7"]
|
||||
},
|
||||
"api-doc": {
|
||||
"type": "http",
|
||||
"url": "https://www.agentfoxapp.com/mcp/976caff7-5f98-4487-bccf-3aa20c92cf1f",
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
java 17.0.16+8-amzn
|
||||
@@ -1,2 +0,0 @@
|
||||
[tools]
|
||||
java = "17+35-amzn"
|
||||
203
CHANGELOG.md
203
CHANGELOG.md
@@ -7,7 +7,198 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### 变更 (Changed)
|
||||
- 【后端反馈联调 · 2026-10-09】后端在《问题清单》补「解决方案/备注」后,逐项(#1~#34)api-doc 核对 +
|
||||
内网直调 A/B + AeroLogic_Phone 模拟器端到端验证,并按后端意见调整前端:
|
||||
① 后端已补字段/接口 → 前端对接:出港移库 flight/businessName/opUserName;出库交接 uldNumber 角标;
|
||||
ULD source/inStoreTime/nowPort + `deleteUldBatch` 一次批删;出港计重 waitCheckInNumber/checkingNumber
|
||||
统计、passageWay、opUserName、trayNumber/trayTotalWeight;运抵 arrivalStatus 服务端 Tab;
|
||||
出港/进港查询 storedNumber/departedNumber;出港/进港仓库 notClearNumber/clearNumber(统计请求 3→1);
|
||||
提取出库 refUserName;国内进港移库 opUserName + `movedDetail` 照片回填。
|
||||
`ManifestTotalDto` 补齐后端统一统计 DTO 分项字段。
|
||||
② 后端「按平板端调整/设计如此」→ 前端对齐:出库交接/ULD/计重/记录/出港仓库/进港仓库/提取出库/运抵
|
||||
的手机筛选全部收敛为平板同款查询参数;ULD 状态回归两态;删除运抵「补充信息」页;出港详情移除
|
||||
锁定状态/计费重量;进港详情按平板改 航程/出库时间(无经停站);提取出库移除无出参占位。
|
||||
③ 联调新发现记入问题清单 #35~#41(ULD uld 搜索 500、saveUld 缺 maxVolume/maxWeight 500、
|
||||
IntImpStorage/pageQuery 过滤全失效、出港仓库列表与统计口径不一致、已移库无 mawbId 无法补传照片等)。
|
||||
- 【进港移库归属更正 · 2026-08-03】设计稿 11「进港移库」经确认归属**国内进港移库
|
||||
(DomImpMove,后端 8 接口齐全,Pad 首页「国内进港→进港移库」既有页面)**,此前误判为
|
||||
国际进港并按 IntExpMove 约定预接不存在的 IntImpMove 模块(原问题清单 #31 作废)。处置:
|
||||
① 删除 module_gjj 的 IntImpMove 全套前端实现(3 Activity + 3 ViewModel + Holder + 4 布局 +
|
||||
`IntImpMoveBean` + Api 4 方法 + 国际 Tab 菜单项 + 权限串/路由/双 Manifest 注册);
|
||||
② 按 phone-adapt 流程重新适配到 `GnjMoveStashListActivity`(app 模块):主列表双形态
|
||||
(Pad 布局移 layout-sw600dp 零改动;手机版 = PhoneSearchBar + 待移库/已移库 Tab
|
||||
(`DomImpMove/search`/`searchMoved` 双端点,`searchMoved` 无移库标识按端点打 `isMoved`)+
|
||||
角标(双端点 limit=1 取 total,仅手机发起)+ 筛选弹层 4 项 + 全选/已选计数 + 批量移库
|
||||
(复用平板 `move` 链路)+ 卡片长按「拍照」浮层);新增手机专属页
|
||||
`GnjMoveStashDetailActivity`(Intent 传 bean 零请求,三卡片)与
|
||||
`GnjMoveStashPhotoActivity`(先调 `detail` 回填已有照片,提交走 `modify` 最小体
|
||||
三字段规范,与平板移交编辑页同链路);`MoveStashBean` 增 `agentName`/`isMoved`/
|
||||
`actionMenuVisible`/`agentDisplay`/`orDash`;手机首页入口改挂**国内 Tab**(`GnViewModel`
|
||||
补通用 route 跳转,权限串 `GnjYiKu=AppDomImpMove` 与 Pad 一致,新路由
|
||||
`/app/GnjMoveStashListActivity`)。
|
||||
2026-08-03 内网真实数据双端验证通过(登录→国内 Tab→列表/Tab/详情/筛选/全选/长按拍照全链路
|
||||
crash=0;平板回归原行为零变化);Proxyman A/B:`wbNo`/`awbType` 过滤生效,
|
||||
`fdate`/`fno`/`spCode` 被后端静默忽略(新缺口 #32)、`searchMoved`/`detail` 出参
|
||||
`opId`/`opDate` 恒 null 且无姓名字段(#33)、`searchMoved` 无 pic 三字段(#34,前端已规避)
|
||||
|
||||
### 修复 (Fixed)
|
||||
- 出港计重「修改记录」托盘自重输入框:Double 回写导致光标跳回开头(输入 18 存成 81),改为保留输入原文
|
||||
- ULD 新增:入库时间日期行仅产出 yyyy-MM-dd(后端 400)→ 保存时补 00:00:00;补充最大装载容积/最大载重
|
||||
可编辑必填(缺失时 saveUld 500)
|
||||
- 提取出库运单号入参 no → wbNo(与主干平板端修复一致)
|
||||
|
||||
### 新增 (Added)
|
||||
- 「进港查询」5.5 寸手机端适配(设计稿 10_进港查询,06 出港查询的进港镜像;详情页与运单追踪
|
||||
复用 08/06 已适配页零新增):列表 `IntImpQueryActivity`(module_gjj,首页菜单实际跳转页;
|
||||
旧版 `GjjQueryListActivity` 路由已注释弃用)手机布局 = PhoneSearchBar(运单号+扫码+筛选)+
|
||||
三格统计(总票数/已入库/已出库,已入库/已出库为已加载数据客户端计数,`pageQueryTotal` 无分项
|
||||
出参,缺口 #30)+ 状态标签卡片(前端推断:`dlvTime` 非空=已出库绿 / `inDate` 非空=已入库橙 /
|
||||
兜底未入库灰)+ 卡片字段件数(inPc)/重量(inWeight)/代理人/特码;筛选弹层 9 项
|
||||
(航班日期起止/航班号/代理/特码/始发站/运单类型/业务类型/品名中,**全部经 api-doc 核对为
|
||||
pageQuery 真实入参**,无缺口);平板侧滑筛选面板代码判空守卫,Pad 端行为零变化
|
||||
- 「进港移库」5.5 寸手机端全新页面(设计稿 11_进港移库;**首个后端整模块缺失的适配页**:
|
||||
api-doc 确认无 IntImpMove 模块、权限体系无对应 key,缺口 #31):
|
||||
`IntImpMoveActivity`(待移库/已移库 Tab + 角标、搜索/扫码、筛选弹层 4 项(航班日期/航班号/
|
||||
特码/运单类型)、多选 + 全选 + 批量移库(ConfirmDialogModel 确认)、卡片长按浮层「拍照」)+
|
||||
`IntImpMoveDetailActivity`(运单详情三卡片:蓝头基本信息/绿头移库信息(仅已移库)/橙头异常照片,
|
||||
Intent 传 bean 零请求)+ `IntImpMovePhotoActivity`(拍照上传:图片网格复用 module_base
|
||||
`ImageSelectNewViewHolder`,提交走 pic/originalPic/picNumber 三字段规范);
|
||||
接口按 IntExpMove 同名约定预接四个(pageQuery/pageQueryTotal/move/uploadPic),权限串
|
||||
`AppIntImpMove` 预定义,后端交付后前端零改动生效(权限串下发前手机首页无入口,debug 直启验证)
|
||||
- 新增 `IntImpMoveBean`(镜像 GjcMove + 航班/照片字段 + isMoved/flightInfo/orDash 计算属性);
|
||||
`IntImpQueryBean` 新增 isQueryOutbound/isQueryStored/orDash/agentDisplay 计算属性;
|
||||
手机首页「国际」Tab 增加「进港查询」(图标 gjj_query_icon)与「进港移库」(图标复用
|
||||
gjc_yi_ku_icon)入口
|
||||
- 新增手机版资源:`bg_phone_btn_green`(绿色主按钮)、`bg_phone_card_header_orange`(橙色详情卡
|
||||
表头)、`bg_phone_photo_add`(虚线加号槽位)、色值 `phone_amber`
|
||||
|
||||
### 修复 (Fixed)
|
||||
- 【11 模块全量设计稿走查】修正 4 类差异(2026-07-31,3 个并行审计 + 逐态渲染比对):
|
||||
① 运单追踪手机竖排时间线补齐已发生节点的状态 pill(绿底标签展示该环节日志 content,
|
||||
如「放行状态:01」,超长省略,设计稿 06/08 运单追踪均有此元素);
|
||||
② 11 个页面手机端标题对齐设计稿短标题(出库交接/出港待计重/计重记录/计重明细/开始计重/
|
||||
出港运抵/出港移库/出港查询/出港货物/进港查询/进港货物),平板保持原长标题零变化;
|
||||
③ ULD 编辑表单「来源」字段移至「所在港」之后(设计稿顺序);
|
||||
④ 出港计重列表卡片(日期/航程/代理/特码)与计重记录卡片(代理)补齐字段小图标
|
||||
(复用 ic_phone_airplane/location/person/tag,与其余模块卡片风格统一)
|
||||
- 出港查询/进港查询卡片「代理人」空值兜底失效:转换器把 JSON null 归一成空串,DataBinding
|
||||
`??` 只判 null 不判空串导致 agentCode 回退永不生效;改用 Bean 计算属性 `agentDisplay`
|
||||
(isNullOrEmpty 双兜底),已同步修正 06 出港查询(`item_gjc_query.xml`)
|
||||
|
||||
### 验证 (Verified)
|
||||
- 进港查询手机端:Map Local mock 验证三格统计计数、三种状态标签、空值 "--" 兜底、筛选弹层
|
||||
9 项收缩滚动;平板端回归横排搜索条/侧滑筛选面板/底部统计栏零变化;全程崩溃数 0
|
||||
- 进港移库手机端:Map Local mock 验证双 Tab 角标、双形态卡片、单选/全选联动计数、空选拦截、
|
||||
移库确认弹框、长按拍照浮层、运单详情、拍照上传页;全程崩溃数 0(后端模块缺失,接口联调待
|
||||
后端交付,见问题清单 #31)
|
||||
- 「提取出库」5.5 寸手机端适配(设计稿 09_提取出库):列表 `IntImpPickUpDLVActivity`(module_gjj)
|
||||
手机布局 = PhoneSearchBar(运单号+扫码+筛选)+ **PhoneStatusTab 待出库/已出库**(`outState`
|
||||
为 pageQuery 文档定义入参 0/1,Tab 真实过滤 + 角标双 pageQueryTotal,抓包证实携带)+
|
||||
双形态卡片(待出库:圆形勾选框+橙标签+库位行;已出库:绿 √ 标签+出库人·出库时间行,
|
||||
`isPickedUp` = dlvTime 非空)+ 卡片内 PhoneStatBox 三列(代理人/件数/重量)+「查看详情」链接 +
|
||||
PhoneBottomBar(全选+已选 N 项+出库,仅待出库 Tab 显示,复用既有 confirmOutbound);
|
||||
筛选弹层 4 项(航班日期为 pageQuery 未定义入参预留;航班号 fno;代理人/特码下拉);
|
||||
手机端进入时清空平板默认「当天缴费日期」查全量(initPhoneExtras,平板默认值不变)
|
||||
- 手机专属新页「运单详情」`IntImpPickUpDetailActivity`:蓝头运单卡(红标签国际进港+品名大标题+
|
||||
两列 KV+库位橙标签)+ 绿头提货信息卡(柜台办理人/时间,已出库追加出库人/出库时间行),
|
||||
数据直接 Intent 传列表 bean(Serializable),零新增请求
|
||||
- `IntImpPickUpDLVBean` 新增 `isPickedUp` 计算属性;手机首页「国际」Tab 增加「提取出库」入口
|
||||
(权限 AppIntImpPickUpDLV 对应权限串,图标复用 Pad 端 gjj_chu_ku_icon)
|
||||
- 后端缺口 2 项登记问题清单 #28~#29(pageQuery 无 fdate 入参、出参无车牌/目的港/业务类型;
|
||||
outState 过滤与 dlvName=出库人语义待内网实测)
|
||||
|
||||
- 「进港仓库」5.5 寸手机端适配(设计稿 08_进港仓库,07 出港仓库的进港镜像 + 进港详情页首次适配):
|
||||
列表 `IntImpStorageUseActivity`(module_gjj,首页菜单实际跳转页;旧版 `GjjWareHouseActivity`
|
||||
路由已注释弃用)手机布局 = PhoneSearchBar(placeholder「搜索运单号/航班号」,`phoneSearchClick`
|
||||
分流:含字母→fno、其余→wbNo,实机抓包证实)+ 三格统计(总票数/未清仓/已清仓,clearNormal=0/1
|
||||
双 total)+ 卡片四操作按钮(清仓/修改库位/出库/入库,已清仓置灰)+ 卡片字段件数/重量/航班号/
|
||||
**始发站**(bean.dep,出港为目的站);筛选弹层 8 项(始发站走 fdep 入参;代理/特码/运单类型/
|
||||
业务类型/品名中 5 项为后端未定义入参,预留传参)
|
||||
- 进港详情页 `IntImpQueryDetailsActivity` + 3 Fragment(运单/仓库/库位信息)首次手机适配:
|
||||
移植 06 出港详情手机布局,报文区按设计稿 3 项(原始舱单 mftStatus/理货报告 tallyStatus/
|
||||
海关放行 command),件重区直取 detail 出参 awbPc/awbWeight/cashWeight/inPc/inWeight
|
||||
(进港自带无需求和),库位卡片优先显示中文姓名(inOpName/outOpName);
|
||||
ViewModel 增加 str/strOr/dec 取值帮助(与出港同口径)
|
||||
- 进港版 3 个操作弹框双变体化(清仓/入库/修改库位,手机底部弹层);修改库位手机版增加
|
||||
「原库位」单选且**只列未出库库位**(沿用平板「已出库不允许修改」校验,卡片级操作时全部已出库
|
||||
toast 拦截),单库位默认选中
|
||||
- 手机首页「国际」Tab 增加「进港仓库」入口(权限 AppGjjWareHouse=Constant.AuthName.GjjWareHouseActivity 对应权限串,图标复用出港仓库同款)
|
||||
- 后端缺口 3 项登记问题清单 #25~#27(pageQuery 无代理/特码/运单类型/业务类型/品名中 5 项筛选
|
||||
入参;clearNormal 分项统计待实测;detail 出参 dep/dest1/dest/unNumber/opDate 字段待实测确认)
|
||||
- 「出港仓库」5.5 寸手机端适配(设计稿 07_出港仓库,详情/运单追踪复用已适配页零新增):
|
||||
列表 `IntExpStorageUseActivity` 手机布局 = PhoneSearchBar(运单号 + 扫码 + 筛选)+ 三格统计
|
||||
(总票数/未清仓/已清仓,彩色左边条卡片;分项计数按同条件 + `clearNormal=0/1` 各调一次
|
||||
`pageQueryTotal`,仅手机形态发起)+ 状态标签卡片(已清仓绿/未清仓橙,`clearNormal=="1"` 判定);
|
||||
**卡片级四操作按钮**(清仓/修改库位/出库/入库,已清仓时清仓置灰拦截)取代平板的勾选+底部批量条,
|
||||
语义等价于「勾选该主单+全部库位」复用既有 `performClear/performModifyStorage/performOutStorage/
|
||||
performInStorage` 请求链路;卡片点击进详情(复用出港查询详情 `GjcQueryDetailsActivity` 3 Tab
|
||||
运单/仓库/库位信息,运单追踪同样复用 `LogDetailActivity`);筛选弹层 8 项按设计稿完整实现
|
||||
(航班日期/航班号/代理/特码/目的站/运单类型/业务类型/品名中,后三项为后端未定义入参,预留传参)
|
||||
- 清仓/入库/修改库位三个操作弹框(`IntExpMoveClearDialogModel`/`IntExpInStorageDialogModel`/
|
||||
`IntExpModifyStorageDialogModel`)双变体化:手机底部弹层(PhoneDataLayout)+ 平板居中弹框不变,
|
||||
弹出位置按 `DeviceUtil.isPhone()` 切换;修改库位弹框手机版新增「原库位」单选
|
||||
(卡片级操作时运单可能有多个库位,构造参数 `sourceStorageList` 传入,单库位默认选中,平板路径不受影响)
|
||||
- 出库二次确认由系统 `AlertDialog` 改为项目规范的 `ConfirmDialogModel`(平板批量出库与手机卡片出库共用)
|
||||
- 手机首页「国际」Tab 增加「出港仓库」入口(权限 AppIntExpStorageUse,图标复用 Pad 端 gjc_cang_ku_icon)
|
||||
- `GjcMaWb` 新增 `isCleared` 手机版计算属性;新增手机版资源 `bg_phone_btn_disabled`(灰底禁用按钮)
|
||||
- 后端缺口 2 项登记问题清单 #23~#24(pageQuery/pageQueryTotal 无 awbType/businessType/goodsCn
|
||||
筛选入参;pageQueryTotal 的 clearNormal 分项统计过滤待内网 A/B 实测确认)
|
||||
- 「出港查询」5.5 寸手机端适配(设计稿 06_出港查询,含列表/详情/运单追踪三页):
|
||||
列表 `GjcQueryActivity` 手机布局 = PhoneSearchBar(运单号 + 扫码 + 筛选)+ 三格统计
|
||||
(总票数/已入库/已离港,彩色左边条卡片)+ 状态标签卡片(已离港绿/已入库橙/未入库灰,
|
||||
前端推断口径:fclose 非空=已离港,否则 opDate 非空=已入库);筛选弹层 9 项(平板搜索行的
|
||||
日期起止/代理并入弹层,特码按设计稿改下拉,字典 `getSpecialCodeList(flag=1, ieFlag="")`,
|
||||
仅手机形态经 `initPhoneExtras()` 加载);详情 `GjcQueryDetailsActivity` 3 Tab 全部复用
|
||||
ViewPager2 + Fragment,手机变体以 PhoneKvItem 网格呈现「基本信息/件重信息/回执信息」,
|
||||
比平板多展示承运人/始发站/中转站/目的站/UN编号,入库件数/入库重量 = warehouseList 各批次求和;
|
||||
仓库/库位 Tab 改批次/库位卡片;「运单追踪」为公共页 `LogDetailActivity` 双变体首例——
|
||||
手机竖排流转时间线(Activity `buildVerticalSteps` 动态构建,节点绿=已达/灰=未达 + 环节时间),
|
||||
平板横向步骤条零改动,手机标题按形态显示「运单追踪」
|
||||
- 手机首页「国际」Tab 增加「出港查询」入口(权限 AppIntExpSearch,图标复用 Pad 端 gjc_query_icon)
|
||||
- `PhoneKvItem` 新增 `tagColor` 属性("green" 绿色高亮,海关放行正常态;默认 "orange"),
|
||||
且占位符 "-"/"--" 不再套高亮标签底
|
||||
- `GjcMaWb` 新增 `isQueryDeparted`/`isQueryStored`/`orDash` 手机版计算属性
|
||||
- 新增手机版资源:`ic_phone_package`(件数)、`ic_phone_tag`(特码)、`bg_phone_dot_blue/gray`
|
||||
- 后端缺口 2 项登记问题清单 #21~#22(isFclose 入参实测被 pageQuery/pageQueryTotal 静默忽略且
|
||||
无已入库/已离港分项统计出参;detail 出参无锁定状态/计费重量字段)
|
||||
|
||||
### 修复 (Fixed)
|
||||
- 提取出库手机版底部条「已选 N 项」在点全选后不更新:`checkAllClick` 只改勾选状态未同步
|
||||
`selectedCountText`(卡片单选走 FlowBus→updateCheckAllStatus 正常),补同步后实测「已选 3 项」正确
|
||||
- **`PhoneFilterPanel` 底部按钮被挤出屏幕**:面板高度 wrap_content 且内容插槽无滚动,筛选项多
|
||||
(出港查询 9 项)时「重置/确认」按钮直接超出屏幕外且无任何报错。修复:内容插槽外包
|
||||
ScrollView(weight=1),筛选项少时行为不变,超屏时内容区收缩滚动、按钮始终可见
|
||||
(已回归出港计重 4 项弹层,行为不变)
|
||||
|
||||
### 验证 (Verified)
|
||||
- 提取出库双端验证通过(2026-07-31,Proxyman Map Local mock 口径):手机端菜单入口、
|
||||
Tab 角标(双 total)、双形态卡片(含库位空值兜底)、单选/全选与「已选 N 项」联动、
|
||||
出库 ConfirmDialogModel、待出库/已出库两种详情页形态(出库人行按需显隐)、筛选弹层 4 项、
|
||||
Tab 切换请求体抓包证实 outState=1 正确携带、冷启动方向恒竖屏、崩溃 0;
|
||||
平板端回归:缴费日期默认当天/5 搜索条/全选/底部统计/确认出库与改造前一致,崩溃 0。
|
||||
**待内网补测**:outState 过滤 A/B、dlvName=出库人语义、出库真实提交链路
|
||||
- 进港仓库双端验证通过(2026-07-31,同出港仓库为 Proxyman Map Local mock 口径):
|
||||
手机端登录→国际 Tab→进港仓库菜单入口、三格统计、三种卡片形态(含空值 "--" 兜底)、
|
||||
详情 3 Tab 全字段(锁定状态转中文、库位中文姓名、时间截断、空值兜底)、四操作弹框、
|
||||
已出库库位过滤(双库位卡片原库位仅列未出库项并默认选中)、无库位/已清仓拦截、
|
||||
筛选弹层 8 项、搜索分流实机抓包证实(输入 MU1111 → 请求体 fno="MU1111"、wbNo=null)、
|
||||
冷启动方向恒竖屏、崩溃 0;平板端回归:5 搜索条/全选/底部统计/4 批量按钮与改造前一致,崩溃 0。
|
||||
**待内网补测**:clearNormal 分项统计 A/B、detail 推断字段(dep/dest1/dest/unNumber/opDate)、
|
||||
四操作真实提交链路
|
||||
- 出港仓库双端验证通过(2026-07-31,开发机不在内网 → 全程 Proxyman Map Local mock 口径):
|
||||
手机端登录→国际 Tab→出港仓库菜单入口、三格统计渲染、三种卡片形态(已清仓置灰清仓/未清仓/
|
||||
全空字段 "--" 兜底)、四操作按钮(清仓/入库底部弹层、修改库位弹层含原库位默认选中、
|
||||
出库 ConfirmDialogModel 文案带运单号与库位数、无库位卡片 toast 拦截、已清仓清仓点击拦截)、
|
||||
筛选弹层 8 项滚动 + 底部按钮可见、卡片点击进详情(Proxyman flow 证实 maWbId 正确传参且
|
||||
detail mock 命中)、详情右上运单追踪跳转、冷启动方向恒竖屏(ROTATION_0×3 采样)、崩溃 0;
|
||||
平板端同页面回归:5 搜索条/全选/底部统计/4 批量按钮与改造前一致,崩溃 0。
|
||||
**待内网补测**:clearNormal 分项统计 A/B、agentCode/spCode/dest 筛选实测、四操作真实提交链路
|
||||
- 出港查询双端实机验证通过(2026-07-31,内网真实数据 2026-06-09 共 14 票):
|
||||
手机端登录→国际 Tab→出港查询菜单入口、列表加载/状态标签/三格统计(10+4=14 与卡片一致)、
|
||||
筛选弹层(日期滚轮、特码/代理下拉真实取数、重置、确认后重新查询)、运单号搜索、扫码拉起、
|
||||
详情 3 Tab(含仓库批次卡与库位空态)、运单追踪时间线、冷启动方向恒竖屏(mRotation=0×8 采样)、
|
||||
全程 FATAL 0;平板端回归:列表 5 搜索条 + 底部统计 + 侧滑筛选面板 + 详情表格样式均与改造前一致
|
||||
- 「出港运抵」5.5 寸手机端适配(主列表 + 3 个手机专属新页,设计稿 04_出港运抵):
|
||||
主列表 `IntExpArriveActivity` 新增「待运抵/已运抵」Tab(客户端按 declareStatus 是否为空拆分数据集,
|
||||
接口无此查询参数)+ 卡片长按浮层(待运抵→补充、已运抵→重置+回执,纯 UI 长按)+ 底部全选/已选/申报
|
||||
@@ -22,6 +213,12 @@
|
||||
- 新增手机版资源:`bg_phone_tag_indigo`/`bg_phone_tag_amber`(申报状态三色标签)、
|
||||
`bg_phone_fab_purple`/`bg_phone_fab_amber`/`bg_phone_fab_green`(长按浮层圆形操作按钮)
|
||||
- 后端缺口 2 项登记问题清单 #19~#20(分单补充信息保存接口不存在、Tab 无申报状态查询参数)
|
||||
- 「出港运抵」对照设计稿 review 修正:状态重置弹框手机端改为设计稿底部弹层
|
||||
(**弹框适配首个先例**:`dialog_int_exp_arrive_reset.xml` 同名布局双变体,Pad 版移至
|
||||
`layout-sw600dp/`,`IntExpArriveResetDialogModel` 构造参数按 `DeviceUtil.isPhone()` 切
|
||||
`DIALOG_TYPE_BOTTOM`/`CENTER`);主列表补空态(图标 + 文案按 Tab 切换「暂无待/已运抵的运单」);
|
||||
回执页补空态兜底「暂无回执内容」(单分单入口常无回执,避免纯白屏);分单明细长按浮层按设计稿
|
||||
补「回执」按钮(单分单跳回执页);分单页底部统计加分母「已选 N / M 项」;Tab 角标初始显示 0
|
||||
|
||||
### 修复 (Fixed)
|
||||
- **RecyclerView + Tab 过滤新坑**:给 item 根节点加 `visibility="@{...}"` 切 Tab 会在列表里
|
||||
@@ -33,12 +230,18 @@
|
||||
修饰符,Java 序列化(Intent 传递机制)会跳过其恢复,反序列化后为 null,切换选中状态时
|
||||
NullPointerException 崩溃。修复:接收方 `initOnCreated` 对列表 `.map { it.copy() }` 重新
|
||||
触发类体初始化补上(已实机崩溃复现并验证修复)
|
||||
- `PhoneStatusTab`/`PhoneFilterPanel` 补上遗漏的 `dispatchSaveInstanceState`/
|
||||
`dispatchRestoreInstanceState` 屏蔽覆写(其余 5 个手机版复合组件均已重写,这两个是历史遗漏;
|
||||
同页多实例时子控件状态可能按 id 跨实例串档)
|
||||
|
||||
### 验证 (Verified)
|
||||
- 出港运抵双端实机验证通过:手机端 Tab 切换(角标/卡片双向正确)/全选/单选/长按菜单/查看分单
|
||||
/分单明细全选与长按重置/补充信息(真实数据回填+下拉字典+提交请求体完整+后端404如实呈现)/
|
||||
回执页 全链路 crash=0、方向无闪屏;平板端布局与交互(4 搜索条+分单内嵌展开+底部 5 元素操作栏)
|
||||
与改造前逐项一致
|
||||
- 出港运抵 review 修正双端实机验证通过:手机端重置底部弹层(长按→重置→下拉展开选项)/主列表空态
|
||||
/回执页空态/分单浮层重置+回执双按钮/「已选 0 / 2 项」分母 全部与设计稿一致且 crash=0;
|
||||
平板端回归:列表、批量「状态重置」弹框仍为居中 Pad 样式,行为与改造前一致
|
||||
- 「出港计重」5.5 寸手机端适配(首个全链路 4+1 页模块,设计稿 03_出港计重):
|
||||
待计重列表(三格统计 总票数/待计重/计重中 + 卡片状态标签 未计重/计重中 + 卡片内单票「提前运抵」+
|
||||
FAB 进计重记录 + 筛选弹层 通道号/承运人/运单类型/代理人)、开始计重(头部预配统计卡 + PhoneFormRow 表单,
|
||||
|
||||
94
CLAUDE.md
94
CLAUDE.md
@@ -975,7 +975,12 @@ Manifest 写死 `userLandscape` 时,即使 `BaseActivity` 在 `super.onCreate`
|
||||
3. **Kotlin 侧不动**:`layoutId()`、`itemLayoutId`、ViewHolder 全部保持原样
|
||||
4. **纯 UI 交互**(Tab 切换、弹层显隐)写在 Activity,不污染 ViewModel;状态过滤优先复用 ViewModel 既有字段
|
||||
5. 手机布局顶部 `<include layout="@layout/title_tool_bar" />` 不变(变体自动切换)
|
||||
6. **回到手机端首页加菜单入口**(最易遗忘,见下节)——不加的话页面在手机上根本进不去
|
||||
6. **弹框(BaseDialogModel)同样要适配**:dialog 布局照样走同名双变体(Pad 版移 `layout-sw600dp/`、
|
||||
手机版在 `layout/` 写设计稿的底部弹层样式),弹出位置在构造参数按形态切换:
|
||||
`BaseDialogModel<XxxBinding>(if (DeviceUtil.isPhone()) DIALOG_TYPE_BOTTOM else DIALOG_TYPE_CENTER)`
|
||||
(参考 `IntExpArriveResetDialogModel` + `dialog_int_exp_arrive_reset.xml` 双变体)。
|
||||
页面适配完要**逐个排查该页所有 DialogModel**,漏掉的会在手机上弹出 Pad 居中样式
|
||||
7. **回到手机端首页加菜单入口**(最易遗忘,见下节)——不加的话页面在手机上根本进不去
|
||||
|
||||
### 手机端首页菜单入口(适配完必须加,否则没入口)
|
||||
|
||||
@@ -1048,7 +1053,7 @@ DataBinding 适配器统一放在 `PhoneWidgetKtx.kt`(同名属性按控件类
|
||||
| `PhoneFilterPanel` | 底部筛选弹层(遮罩 + 面板 + 重置/确认) | `title`、`panelVisible`、`setOnResetClick`、`setOnConfirmClick`、`setOnDismissClick` |
|
||||
| `PhoneBottomBar` | 底部操作条:全选 + 已选统计 + 主按钮 | `allChecked`、`countText`、`actionText`、`setOnAllCheckClick`、`setOnActionClick` |
|
||||
| `PhoneStatBox` | 卡片内 2~4 列统计框(未传 label 的列自动隐藏) | `label1..4`、`value1..4` |
|
||||
| `PhoneKvItem` | 详情页字段项(灰标签 + 数值),`tag=true` 转橙色高亮 | `title`、`value`、`tag` |
|
||||
| `PhoneKvItem` | 详情页字段项(灰标签 + 数值),`tag=true` 转高亮标签(占位符 "-"/"--" 不套底) | `title`、`value`、`tag`、`tagColor`("orange" 默认/"green") |
|
||||
| `PhoneFormRow` | 行式表单项(左标签+右值+分隔线),`PhoneFormRowType` = `INPUT`/`SELECT`(内置底部选择面板)/`DATE`/`TEXT`(只读右对齐,空值 "--") | `title`、`hint`、`type`、`value`(双向)、`list`、`required`、`enable`、`numeric`、`setRefreshCallBack` |
|
||||
|
||||
`PhoneBottomBar` 追加 `actionDanger` 属性:true 时主按钮转浅红底红字 + 垃圾桶图标(ULD 管理批量删除)。
|
||||
@@ -1056,6 +1061,13 @@ DataBinding 适配器统一放在 `PhoneWidgetKtx.kt`(同名属性按控件类
|
||||
`ic_phone_trash`、`ic_phone_edit`、色值 `phone_danger_bg/text`。
|
||||
出港计重追加:`bg_phone_btn_weak`(浅蓝弱按钮,卡片内提前运抵)、`bg_phone_card_top_accent`
|
||||
(卡片顶部主色描边条)、`ic_phone_clipboard`(FAB 剪贴板)、`ic_phone_weight`(砝码图标,可 tint)。
|
||||
出港查询追加:`ic_phone_package`(件数)、`ic_phone_tag`(特码)、`bg_phone_dot_blue/gray`(状态圆点);
|
||||
`PhoneFilterPanel` 内容插槽已内置 ScrollView(筛选项超屏时收缩滚动,底部按钮始终可见——
|
||||
9 个筛选项曾把「重置/确认」挤出屏幕)。
|
||||
出港仓库追加:`bg_phone_btn_disabled`(灰底禁用按钮,与 `bg_phone_btn_weak` 同 10dp 圆角,
|
||||
卡片操作按钮禁用态配 `phone_tag_gray_text` 文字)。
|
||||
进港移库追加:`bg_phone_btn_green`(绿色主按钮,拍照上传「确认提交」)、`bg_phone_card_header_orange`
|
||||
(橙色详情卡表头,异常照片)、`bg_phone_photo_add`(虚线加号槽位)、色值 `phone_amber`。
|
||||
|
||||
⚠️ **弹层与浮动按钮的层级**:`PhoneFilterPanel` 默认无 elevation,页面里有带 elevation 的浮动按钮(FAB)时
|
||||
会穿透到弹层之上——给弹层实例加 `android:elevation="8dp"`(大于 FAB 的 6dp)。
|
||||
@@ -1121,11 +1133,71 @@ override fun dispatchRestoreInstanceState(container: SparseArray<Parcelable>) =
|
||||
visibility 绑定(实机截图验证过,见「常见编译错误速查」);② 通过 `Intent.putExtra(Serializable)`
|
||||
传递的 `GjcHaWb`/`GjcMaWb`,其 `checked`/`showMore`/`actionMenuVisible` 字段标了
|
||||
`@Transient`(= JVM `transient`,Java 序列化会跳过),反序列化后为 null,直接
|
||||
`.checked.set(...)` 会崩溃——接收方 `initOnCreated` 必须对列表 `.map { it.copy() }` 补上
|
||||
`.checked.set(...)` 会崩溃——接收方 `initOnCreated` 必须对列表 `.map { it.copy() }` 补上。
|
||||
2026-07-30 review 修正:状态重置弹框改手机底部弹层(弹框双变体首例,见改造步骤第 6 条)、
|
||||
主列表/回执页补空态、分单浮层补「回执」、分单统计加分母、Tab 角标初始 0
|
||||
- 「提取出库」`IntImpPickUpDLVActivity`(module_gjj,类型2 多选批量页 + 手机专属详情新页
|
||||
`IntImpPickUpDetailActivity`(Intent 传 Serializable bean 零请求)。待出库/已出库 Tab 绑
|
||||
**文档定义入参 `outState`**(0/1,抓包证实携带,效果待内网 #29)+ 角标双 pageQueryTotal;
|
||||
双形态卡片按 `isPickedUp`(dlvTime 非空)切换;手机进入时清空平板默认「当天缴费日期」查全量;
|
||||
缺口 #28:无 fdate 入参、出参无车牌(提货车辆)/目的港/业务类型。
|
||||
⚠️ 踩坑:`checkAllClick` 全选后底部「已选 N 项」不更新——批量勾选不走 FlowBus 单卡事件,
|
||||
必须在 checkAllClick 里同步 selectedCountText)
|
||||
- 「进港查询」`IntImpQueryActivity`(module_gjj;06 出港查询的进港镜像:三格统计
|
||||
总票数/已入库/已出库为已加载数据客户端计数(`pageQueryTotal` 无分项出参,缺口 #30),
|
||||
卡片状态前端推断:`dlvTime` 非空=已出库(绿)/`inDate` 非空=已入库(橙)/兜底未入库(灰);
|
||||
筛选弹层 9 项**入参全部经 api-doc 核对真实存在**(分页参数名 `page`/`limit`,品名参数名
|
||||
`goods`);详情页与运单追踪复用 08/06 已适配页零新增;平板侧滑筛选面板代码已判空守卫。
|
||||
⚠️ 踩坑:代理人绑定不能写 `bean.agentName ?? bean.agentCode`——转换器把 JSON null 归一成
|
||||
空串,`??` 只判 null 不判空串,须用 Bean 计算属性 `agentDisplay`(06 出港查询同步修正))
|
||||
- 「进港移库」`GnjMoveStashListActivity`(app 模块,**2026-08-03 归属更正后重做**:设计稿 11
|
||||
实际归属**国内进港移库 DomImpMove**(后端 8 接口齐全、Pad 首页「国内进港→进港移库」既有页面),
|
||||
最初误判为国际进港并按 IntExpMove 约定预接了不存在的 IntImpMove 模块(原缺口 #31),该套
|
||||
module_gjj 前端实现已整体删除。现行实现:主列表双形态(Pad 布局移 layout-sw600dp 零改动),
|
||||
待移库/已移库 Tab 走 **`search`/`searchMoved` 双端点**(`searchMoved` 出参无移库标识,前端按
|
||||
端点给 bean 打 `isMoved`),Tab 角标 = 两端点各调一次 limit=1 取分页 total(`initPhoneExtras`
|
||||
开关,仅手机发起);手机专属新页 `GnjMoveStashDetailActivity`(Intent 传 bean 零请求,三卡片:
|
||||
基本信息/移库信息(仅已移库)/异常照片)+ `GnjMoveStashPhotoActivity`(进入先调 `detail` 回填
|
||||
已有照片——`searchMoved` 出参无 pic 三字段 #34,提交走 **`modify` 最小体**
|
||||
`{mawbId,remark,picNumber,pic,originalPic}`,与平板移交编辑页同链路);批量移库复用平板
|
||||
`moveStashClick`(`move`:fid+ids)。手机首页入口在**国内 Tab**(`GnViewModel`,权限串
|
||||
`GnjYiKu=AppDomImpMove`,需补通用 route 跳转逻辑,图标从 module_gnj 复制);
|
||||
GnjMoveStashListActivity 补 @Route `/app/GnjMoveStashListActivity`。
|
||||
2026-08-03 内网真实数据双端验证通过;筛选 A/B:`wbNo`/`awbType` 生效,
|
||||
`fdate`/`fno`/`spCode` 被后端静默忽略(#32)、`opId`/`opDate` 恒 null(#33))
|
||||
- 「进港仓库」`IntImpStorageUseActivity`(module_gjj,07 出港仓库的进港镜像;**首页菜单实际跳转页,
|
||||
旧版 `GjjWareHouseActivity` 路由已注释弃用**。差异:卡片/筛选用始发站(fdep 入参)替代目的站;
|
||||
搜索框「运单号/航班号」分流(含字母→fno、其余→wbNo,抓包证实);筛选 5 项无入参(缺口 #25,
|
||||
比出港多 2 项);连带首次适配进港详情 `IntImpQueryDetailsActivity` + 3 Fragment(报文区 3 项:
|
||||
原始舱单/理货报告/海关放行,件重区直取 inPc/inWeight 无需求和,detail keys 以平板绑定为准 +
|
||||
dep/dest1/dest/unNumber/opDate 按出港推断待实测 #27);修改库位手机弹层「原库位」只列未出库
|
||||
库位(沿用平板校验);**前端接口前缀是 `IntImpStorage` 不是 `IntImpStorageUse`**,api-doc 按
|
||||
后者搜不到)
|
||||
- 「出港仓库」`IntExpStorageUseActivity`(嵌套多选列表页型的首个适配:平板「勾选主/子列表 +
|
||||
底部批量操作」在手机上改为**卡片级四按钮**(清仓/修改库位/出库/入库,已清仓置灰),语义等价
|
||||
「勾选该主单+全部库位」直接复用既有 performXxx 链路,ViewHolder 对双侧独有 id 全判空;
|
||||
三格统计 总票数/未清仓/已清仓(后两格 = 同条件 + `clearNormal=0/1` 各调一次 pageQueryTotal,
|
||||
过滤是否生效待内网 A/B,缺口 #24);筛选弹层 8 项中运单类型/业务类型/品名(中) 为后端未定义
|
||||
入参(缺口 #23,预留传参);三个操作弹框双变体化 + 手机版修改库位弹层加「原库位」单选;
|
||||
出库确认 AlertDialog → ConfirmDialogModel;详情与运单追踪完全复用出港查询已适配页,零新增页面)
|
||||
- 「出港查询」`GjcQueryActivity`(列表:三格统计 总票数/已入库/已离港 + 卡片状态标签,
|
||||
状态为前端推断:`fclose` 非空=已离港/`opDate` 非空=已入库;筛选弹层 9 项,日期起止与代理
|
||||
从平板搜索行并入,特码改下拉 `getSpecialCodeList(flag=1, ieFlag="")`;分项统计为已加载
|
||||
数据客户端计数,`isFclose` 实测被后端忽略,缺口 #21)+ `GjcQueryDetailsActivity`(3 Tab
|
||||
复用 ViewPager2+Fragment,手机变体 PhoneKvItem 网格;入库件数/重量= warehouseList 求和;
|
||||
锁定状态/计费重量后端无字段,缺口 #22)+ 「运单追踪」`LogDetailActivity`(app 模块公共页
|
||||
双变体首例:手机竖排时间线由 Activity `buildVerticalSteps` 动态构建,平板横向步骤条不动;
|
||||
手机标题按形态切「运单追踪」)。平板侧滑筛选面板代码已判空守卫(手机变体无 filter_panel
|
||||
include,Binding 字段为 @Nullable)
|
||||
- ✅ **设计稿 11 个入口(01~11)已于 2026-07-31 全部适配完成**
|
||||
- ⏳ **待办**:
|
||||
- `PhoneSearchBar` 接入 AutoQuery 联想(`AutoQueryManager` 目前只对接了 Pad 系组件)
|
||||
- 出库交接 Tab 角标恒 0:`IntExpOutHandover/pageQueryTotal` 出参恒 0(后端缺陷,问题清单 #6),
|
||||
后端修复后角标自动恢复(`handoverState` 过滤本身已于 2026-07-29 实机验证通过)生效
|
||||
- 联调新发现的后端缺口 #35~#41(ULD uld 搜索 500、IntImpStorage 列表过滤全失效、已移库无 mawbId
|
||||
无法补传照片等)待后端处理,详见问题清单
|
||||
- ✅ **2026-10-09 后端反馈联调完成**:问题清单 #1~#34 逐项内网直调 + 模拟器端到端验证,结论写入清单 P 列。
|
||||
**后端口径:手机筛选一律与平板端查询参数保持一致**(不为手机新增入参);分项统计统一取
|
||||
`pageQueryTotal` 出参(`ManifestTotalDto` 已补齐分项字段),不要再按状态多调 total。
|
||||
最新字段语义见 `.claude/skills/phone-adapt/references/api-doc.md` 末节
|
||||
- 📋 **接口对接**:适配中发现的后端接口缺口统一记录在 `documents/后端接口对接问题清单.xlsx`
|
||||
(按模块/页面/接口定义/接口地址索引,与后端对接的正式文档,每页适配完必须维护);
|
||||
接口入参/出参一律以 api-doc MCP 为准核对,流程见
|
||||
@@ -1216,6 +1288,10 @@ adb shell am start -n com.lukouguoji.aerologic/com.lukouguoji.gjc.activity.IntEx
|
||||
| 平板先竖屏再转横屏 + 交互后 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)` 补上 |
|
||||
| 布局构建报 `Error: The string "--" is not permitted within comments` | XML 注释中出现连续双横线(如写"兜底 \"--\""),XML 规范禁止 | 注释里改用文字描述(如「兜底双横线」),代码绑定表达式中的 `"--"` 不受影响 |
|
||||
| 多选页手机版点「全选」后底部「已选 N 项」不更新(单卡勾选正常) | 批量勾选在 `checkAllClick` 里直接 set,不走 FlowBus 的单卡 EVENT_CHECK_CHANGED 事件,`selectedCountText` 只在事件回调里更新 | `checkAllClick` 末尾自行同步 `selectedCountText`(平板布局不绑定该字段,无影响) |
|
||||
| 手机版数字输入框(`PhoneFormRow` 双向绑 Double 的 `xxxStr`)输入 "18" 变成 "81" | getter 由 Double 反推字符串("1" → "1.0"),与输入框文本不等触发 `setText`,光标回到开头 | Bean 里保留输入原文(`@Transient` 私有 String),getter 优先返回原文(参考 `GjcCheckInRecord.trayTotalWeightStr`) |
|
||||
| XML 里 `bean.a ?? bean.b` 兜底不生效,字段明明有值却显示占位符 | 网络层转换器把 JSON null 归一成空串 `""`,DataBinding 的 `??` 只判 null 不判空串,永远取到左侧的空串 | 在 Bean 上加计算属性做 `isNullOrEmpty` 双兜底(如 `agentDisplay`),XML 绑计算属性(进港查询/出港查询代理人已踩过) |
|
||||
|
||||
---
|
||||
|
||||
@@ -1460,10 +1536,14 @@ Glide.with(itemView.context).load(glideUrl).into(binding.ivThumbnail)
|
||||
### 双端验证命令
|
||||
|
||||
```bash
|
||||
~/Library/Android/sdk/emulator/emulator -list-avds # 可用:Medium_Phone_API_36.1(手机)、Aerologic_Tablet(平板)
|
||||
~/Library/Android/sdk/emulator/emulator -list-avds # 可用:Aerologic_Phone_5.5_API31(手机,首选)、Aerologic_Tablet(平板)、Medium_Phone_API_36.1
|
||||
adb -s <设备> shell wm size && adb -s <设备> shell wm density # 确认屏幕参数
|
||||
adb -s <设备> logcat -d -s BaseActivity:D # 查看形态识别结果 PHONE(sw=411dp) / TABLET(sw=800dp)
|
||||
adb -s <设备> logcat -d -s BaseActivity:D # 查看形态识别结果 PHONE(sw=384dp) / TABLET(sw=800dp)
|
||||
adb -s <设备> exec-out screencap -p > /tmp/shot.png # 截图比对
|
||||
```
|
||||
|
||||
> 手机端验证**首选 `Aerologic_Phone_5.5_API31`**:按真实交付手持机 1:1 定制——720×1440、5.51 寸(300dpi,sw=384dp)、
|
||||
> Android 12 / API 31(与 targetSdk 一致)、arm64-v8a,与实机的差异最小。`Medium_Phone_API_36.1`(1080×2400、API 36)
|
||||
> 仅作兼容性参考,分辨率与系统版本都和交付机不符。
|
||||
|
||||
> 改动 `BaseActivity` / `BaseBindingActivity` / 公共组件后,**必须在平板上回归**,确认现有平板版行为不变。
|
||||
|
||||
@@ -26,8 +26,8 @@ android {
|
||||
applicationId "com.lukouguoji.aerologic"
|
||||
minSdkVersion 24
|
||||
targetSdkVersion 30
|
||||
versionCode 88
|
||||
versionName "1.8.8"
|
||||
versionCode 87
|
||||
versionName "1.8.7"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
|
||||
@@ -98,9 +98,75 @@
|
||||
android:exported="true"
|
||||
tools:replace="android:exported" />
|
||||
|
||||
<!-- 出港运抵-补充信息(手机版适配验证页) -->
|
||||
<!-- 出港查询(手机版适配验证页) -->
|
||||
<activity
|
||||
android:name="com.lukouguoji.gjc.activity.IntExpArriveSupplementActivity"
|
||||
android:name="com.lukouguoji.gjc.activity.GjcQueryActivity"
|
||||
android:exported="true"
|
||||
tools:replace="android:exported" />
|
||||
|
||||
<!-- 出港查询-详情(手机版适配验证页) -->
|
||||
<activity
|
||||
android:name="com.lukouguoji.gjc.activity.GjcQueryDetailsActivity"
|
||||
android:exported="true"
|
||||
tools:replace="android:exported" />
|
||||
|
||||
<!-- 运单追踪/操作日志详情(手机版适配验证页) -->
|
||||
<activity
|
||||
android:name="com.lukouguoji.aerologic.page.log.detail.LogDetailActivity"
|
||||
android:exported="true"
|
||||
tools:replace="android:exported" />
|
||||
|
||||
<!-- 出港仓库(手机版适配验证页) -->
|
||||
<activity
|
||||
android:name="com.lukouguoji.gjc.activity.IntExpStorageUseActivity"
|
||||
android:exported="true"
|
||||
tools:replace="android:exported" />
|
||||
|
||||
<!-- 进港仓库(手机版适配验证页) -->
|
||||
<activity
|
||||
android:name="com.lukouguoji.gjj.activity.IntImpStorageUseActivity"
|
||||
android:exported="true"
|
||||
tools:replace="android:exported" />
|
||||
|
||||
<!-- 进港查询-详情(手机版适配验证页,进港仓库卡片点击进入) -->
|
||||
<activity
|
||||
android:name="com.lukouguoji.gjj.activity.IntImpQueryDetailsActivity"
|
||||
android:exported="true"
|
||||
tools:replace="android:exported" />
|
||||
|
||||
<!-- 提取出库(手机版适配验证页) -->
|
||||
<activity
|
||||
android:name="com.lukouguoji.gjj.activity.IntImpPickUpDLVActivity"
|
||||
android:exported="true"
|
||||
tools:replace="android:exported" />
|
||||
|
||||
<!-- 提取出库-运单详情(手机版适配验证页) -->
|
||||
<activity
|
||||
android:name="com.lukouguoji.gjj.activity.IntImpPickUpDetailActivity"
|
||||
android:exported="true"
|
||||
tools:replace="android:exported" />
|
||||
|
||||
<!-- 进港查询(手机版适配验证页) -->
|
||||
<activity
|
||||
android:name="com.lukouguoji.gjj.activity.IntImpQueryActivity"
|
||||
android:exported="true"
|
||||
tools:replace="android:exported" />
|
||||
|
||||
<!-- 进港移库(国内进港,手机版适配验证页) -->
|
||||
<activity
|
||||
android:name="com.lukouguoji.aerologic.page.gnj.move.stash.list.GnjMoveStashListActivity"
|
||||
android:exported="true"
|
||||
tools:replace="android:exported" />
|
||||
|
||||
<!-- 进港移库-运单详情(手机版专属页) -->
|
||||
<activity
|
||||
android:name="com.lukouguoji.aerologic.page.gnj.move.stash.detail.GnjMoveStashDetailActivity"
|
||||
android:exported="true"
|
||||
tools:replace="android:exported" />
|
||||
|
||||
<!-- 进港移库-拍照上传(手机版专属页) -->
|
||||
<activity
|
||||
android:name="com.lukouguoji.aerologic.page.gnj.move.stash.photo.GnjMoveStashPhotoActivity"
|
||||
android:exported="true"
|
||||
tools:replace="android:exported" />
|
||||
|
||||
|
||||
@@ -157,12 +157,6 @@
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:exported="false"
|
||||
android:screenOrientation="unspecified" />
|
||||
<!-- 国际出港运抵-补充信息(5.5寸手机版专属页面) -->
|
||||
<activity
|
||||
android:name="com.lukouguoji.gjc.activity.IntExpArriveSupplementActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:exported="false"
|
||||
android:screenOrientation="unspecified" />
|
||||
<!-- 国际出港仓库 -->
|
||||
<activity
|
||||
android:name="com.lukouguoji.gjc.activity.IntExpStorageUseActivity"
|
||||
@@ -375,6 +369,20 @@
|
||||
android:name=".page.gnj.move.stash.list.GnjMoveStashListActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:screenOrientation="unspecified" />
|
||||
|
||||
<!-- 国内进港移库-运单详情(5.5寸手机版专属) -->
|
||||
<activity
|
||||
android:name=".page.gnj.move.stash.detail.GnjMoveStashDetailActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:exported="false"
|
||||
android:screenOrientation="unspecified" />
|
||||
|
||||
<!-- 国内进港移库-拍照上传(5.5寸手机版专属) -->
|
||||
<activity
|
||||
android:name=".page.gnj.move.stash.photo.GnjMoveStashPhotoActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:exported="false"
|
||||
android:screenOrientation="unspecified" />
|
||||
<activity
|
||||
android:name=".page.gnj.stash.list.GnjStashListActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
@@ -558,6 +566,13 @@
|
||||
android:exported="false"
|
||||
android:screenOrientation="unspecified" />
|
||||
|
||||
<!-- 国际进港-提取出库-运单详情(5.5寸手机版专属) -->
|
||||
<activity
|
||||
android:name="com.lukouguoji.gjj.activity.IntImpPickUpDetailActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:exported="false"
|
||||
android:screenOrientation="unspecified" />
|
||||
|
||||
<!-- 国际进港-进港查询 -->
|
||||
<activity
|
||||
android:name="com.lukouguoji.gjj.activity.IntImpQueryActivity"
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.lukouguoji.aerologic.page.gnj.move.stash.detail
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import com.google.gson.Gson
|
||||
import com.lukouguoji.aerologic.R
|
||||
import com.lukouguoji.aerologic.databinding.ActivityGnjMoveStashDetailBinding
|
||||
import com.lukouguoji.aerologic.page.gnj.move.stash.photo.GnjMoveStashPhotoActivity
|
||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||
import com.lukouguoji.module_base.bean.MoveStashBean
|
||||
import com.lukouguoji.module_base.common.Constant
|
||||
|
||||
/**
|
||||
* 国内进港移库「运单详情」(5.5 寸手持端专属页面,无平板变体)
|
||||
*
|
||||
* 由列表卡片的「查看详情」进入;「异常照片」卡片的加号槽位跳拍照上传页。
|
||||
* 展示字段全部由列表项带入(Gson JSON),零新增请求。
|
||||
*/
|
||||
class GnjMoveStashDetailActivity :
|
||||
BaseBindingActivity<ActivityGnjMoveStashDetailBinding, GnjMoveStashDetailViewModel>() {
|
||||
|
||||
override fun layoutId() = R.layout.activity_gnj_move_stash_detail
|
||||
override fun viewModelClass() = GnjMoveStashDetailViewModel::class.java
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow("运单详情")
|
||||
binding.viewModel = viewModel
|
||||
binding.activity = this
|
||||
viewModel.initOnCreated(intent)
|
||||
}
|
||||
|
||||
/** 「异常照片」加号槽位 → 拍照上传页 */
|
||||
fun openPhoto() {
|
||||
viewModel.dataBean.value?.let {
|
||||
GnjMoveStashPhotoActivity.start(this, it.mawbId, it.wbNo, it.moveId)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun start(context: Context, bean: MoveStashBean) {
|
||||
context.startActivity(
|
||||
Intent(context, GnjMoveStashDetailActivity::class.java)
|
||||
.putExtra(Constant.Key.DATA, Gson().toJson(bean))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.lukouguoji.aerologic.page.gnj.move.stash.detail
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.google.gson.Gson
|
||||
import com.lukouguoji.module_base.base.BaseViewModel
|
||||
import com.lukouguoji.module_base.bean.MoveStashBean
|
||||
import com.lukouguoji.module_base.common.Constant
|
||||
|
||||
/**
|
||||
* 国内进港移库「运单详情」ViewModel(5.5 寸手持端专属页面)
|
||||
*
|
||||
* 列表项数据已包含详情页所需全部字段(含 isMoved 端点打标),直接由列表带入,不额外请求。
|
||||
*/
|
||||
class GnjMoveStashDetailViewModel : BaseViewModel() {
|
||||
|
||||
val dataBean = MutableLiveData(MoveStashBean())
|
||||
|
||||
fun initOnCreated(intent: Intent) {
|
||||
val json = intent.getStringExtra(Constant.Key.DATA).orEmpty()
|
||||
if (json.isNotEmpty()) {
|
||||
dataBean.value = Gson().fromJson(json, MoveStashBean::class.java)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +1,104 @@
|
||||
package com.lukouguoji.aerologic.page.gnj.move.stash.list
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import com.lukouguoji.aerologic.R
|
||||
import com.lukouguoji.aerologic.databinding.ActivityGnjMoveStashListBinding
|
||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||
import com.lukouguoji.module_base.ktx.getLifecycleOwner
|
||||
|
||||
class GnjMoveStashListActivity :
|
||||
BaseBindingActivity<ActivityGnjMoveStashListBinding, GnjMoveStashListViewModel>() {
|
||||
override fun layoutId() = R.layout.activity_gnj_move_stash_list
|
||||
|
||||
override fun viewModelClass() = GnjMoveStashListViewModel::class.java
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow("国内进港移库")
|
||||
|
||||
binding.viewModel = viewModel
|
||||
|
||||
viewModel.pageModel
|
||||
.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, getLifecycleOwner())
|
||||
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun start(context: Context) {
|
||||
val starter = Intent(context, GnjMoveStashListActivity::class.java)
|
||||
context.startActivity(starter)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.lukouguoji.aerologic.page.gnj.move.stash.list
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.databinding.ObservableBoolean
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.lukouguoji.aerologic.R
|
||||
import com.lukouguoji.aerologic.databinding.ActivityGnjMoveStashListBinding
|
||||
import com.lukouguoji.aerologic.page.gnj.move.stash.photo.GnjMoveStashPhotoActivity
|
||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||
import com.lukouguoji.module_base.bean.MoveStashBean
|
||||
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.getLifecycleOwner
|
||||
import com.lukouguoji.module_base.router.ARouterConstants
|
||||
import com.lukouguoji.module_base.util.DeviceUtil
|
||||
|
||||
@Route(path = ARouterConstants.ACTIVITY_URL_GNJ_MOVE_STASH_LIST)
|
||||
class GnjMoveStashListActivity :
|
||||
BaseBindingActivity<ActivityGnjMoveStashListBinding, GnjMoveStashListViewModel>() {
|
||||
override fun layoutId() = R.layout.activity_gnj_move_stash_list
|
||||
|
||||
override fun viewModelClass() = GnjMoveStashListViewModel::class.java
|
||||
|
||||
/** 筛选弹层显隐(仅手机 UI 状态,平板布局不绑定) */
|
||||
val filterPanelVisible = ObservableBoolean(false)
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
// 设计稿手机端标题为「进港移库」,平板保持原标题
|
||||
setBackArrow(if (DeviceUtil.isPhone()) "进港移库" else "国内进港移库")
|
||||
|
||||
binding.viewModel = viewModel
|
||||
binding.activity = this
|
||||
|
||||
viewModel.pageModel
|
||||
.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, getLifecycleOwner())
|
||||
|
||||
if (DeviceUtil.isPhone()) {
|
||||
// 手机专属:Tab 角标 + 特码字典等额外请求
|
||||
viewModel.initPhoneExtras()
|
||||
|
||||
// 卡片勾选变化 → 更新全选状态与已选计数
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_CHECK_CHANGED).observe(this) {
|
||||
viewModel.updateCheckAllStatus()
|
||||
}
|
||||
}
|
||||
|
||||
// 拍照上传等子页面完成后刷新列表(平板无发射方,观察无副作用)
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).observe(this) {
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
// ==================== 筛选弹层(仅手机) ====================
|
||||
|
||||
fun toggleFilterPanel() {
|
||||
filterPanelVisible.set(!filterPanelVisible.get())
|
||||
}
|
||||
|
||||
/** 筛选:重置(只清空弹层内条件,不影响 Tab 与顶部搜索框) */
|
||||
fun resetFilter() {
|
||||
viewModel.flightDate.value = ""
|
||||
viewModel.flightNo.value = ""
|
||||
viewModel.spCode.value = ""
|
||||
viewModel.businessType.value = ""
|
||||
}
|
||||
|
||||
fun confirmFilter() {
|
||||
filterPanelVisible.set(false)
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
// ==================== 卡片长按「拍照」浮层(仅手机) ====================
|
||||
|
||||
/** 卡片长按:展开操作浮层(View.OnLongClickListener 要求返回 Boolean) */
|
||||
fun showCardActionPhone(bean: MoveStashBean): Boolean {
|
||||
bean.actionMenuVisible.set(true)
|
||||
return true
|
||||
}
|
||||
|
||||
/** 点浮层空白处关闭 */
|
||||
fun hideCardActionPhone(bean: MoveStashBean) {
|
||||
bean.actionMenuVisible.set(false)
|
||||
}
|
||||
|
||||
/** 浮层「拍照」→ 拍照上传页 */
|
||||
fun openPhoto(bean: MoveStashBean) {
|
||||
bean.actionMenuVisible.set(false)
|
||||
GnjMoveStashPhotoActivity.start(this, bean.mawbId, bean.wbNo, bean.moveId)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun start(context: Context) {
|
||||
val starter = Intent(context, GnjMoveStashListActivity::class.java)
|
||||
context.startActivity(starter)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,34 +3,64 @@ package com.lukouguoji.aerologic.page.gnj.move.stash.list
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import com.lukouguoji.aerologic.databinding.ItemGnjMoveStashListBinding
|
||||
import com.lukouguoji.aerologic.page.gnj.move.stash.detail.GnjMoveStashDetailActivity
|
||||
import com.lukouguoji.gnj.page.yiku.handover.GnjYiKuHandoverActivity
|
||||
import com.lukouguoji.module_base.base.BaseViewHolder
|
||||
import com.lukouguoji.module_base.bean.MoveStashBean
|
||||
import com.lukouguoji.module_base.common.ConstantEvent
|
||||
import com.lukouguoji.module_base.impl.FlowBus
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* 国内进港移库列表项 ViewHolder(双形态共用)
|
||||
*
|
||||
* 平板/手机布局差异较大,单侧独有的控件 id 在 Binding 基类中为 @Nullable,
|
||||
* 全部走判空调用(平板:swipe_menu/btn_edit/ll;手机:ll_detail)。
|
||||
*/
|
||||
class GnjMoveStashListViewHolder(view: View) :
|
||||
BaseViewHolder<MoveStashBean, ItemGnjMoveStashListBinding>(view) {
|
||||
|
||||
override fun onBind(item: Any?, position: Int) {
|
||||
val bean = getItemBean(item)!!
|
||||
binding.bean = bean
|
||||
binding.position = position
|
||||
binding.activity = itemView.context as? GnjMoveStashListActivity
|
||||
|
||||
// 勾选框(双形态共有):切换选中;手机端另行广播刷新全选/已选计数
|
||||
binding.ivIcon.setOnClickListener {
|
||||
bean.checked.set(!bean.checked.get())
|
||||
binding.executePendingBindings()
|
||||
|
||||
GlobalScope.launch {
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_CHECK_CHANGED).emit("check_changed")
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 平板独有交互 =====
|
||||
|
||||
// 点击列表项进入移交详情
|
||||
binding.ll.setOnClickListener {
|
||||
binding.ll?.setOnClickListener {
|
||||
GnjYiKuHandoverActivity.startForDetails(itemView.context, bean.mawbId)
|
||||
}
|
||||
|
||||
// 侧滑菜单 - 编辑按钮
|
||||
binding.btnEdit.setOnClickListener {
|
||||
binding.swipeMenu.quickClose()
|
||||
binding.btnEdit?.setOnClickListener {
|
||||
binding.swipeMenu?.quickClose()
|
||||
if (bean.pickFlag == "1") {
|
||||
Toast.makeText(itemView.context, "已出库,不可编辑", Toast.LENGTH_SHORT).show()
|
||||
return@setOnClickListener
|
||||
}
|
||||
GnjYiKuHandoverActivity.startForEdit(itemView.context, bean.mawbId)
|
||||
}
|
||||
|
||||
// ===== 手机独有交互 =====
|
||||
|
||||
// 「查看详情」→ 手机版运单详情页
|
||||
binding.llDetail?.setOnClickListener {
|
||||
GnjMoveStashDetailActivity.start(itemView.context, bean)
|
||||
}
|
||||
|
||||
binding.executePendingBindings()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,41 @@ class GnjMoveStashListViewModel : BasePageViewModel() {
|
||||
val number = MutableLiveData("0")
|
||||
val weight = MutableLiveData("0")
|
||||
|
||||
// ========== 5.5 寸手持端专属字段(平板布局不绑定,默认值保证平板行为零变化) ==========
|
||||
|
||||
/** 移库状态 Tab:"0" 待移库(DomImpMove/search)/ "1" 已移库(DomImpMove/searchMoved) */
|
||||
val moveState = MutableLiveData("0")
|
||||
|
||||
/** 手机筛选弹层:航班日期 / 航班号 / 特码(默认空 → 不进请求) */
|
||||
val flightDate = MutableLiveData("")
|
||||
val flightNo = MutableLiveData("")
|
||||
val spCode = MutableLiveData("")
|
||||
val spCodeList = MutableLiveData<List<KeyValue>>(emptyList())
|
||||
|
||||
val moveStateTabs = MutableLiveData(
|
||||
listOf(KeyValue("待移库", "0"), KeyValue("已移库", "1"))
|
||||
)
|
||||
|
||||
/** 状态 Tab 角标(与 [moveStateTabs] 等长,取两端点分页 total) */
|
||||
val moveStateCounts = MutableLiveData(listOf("", ""))
|
||||
|
||||
/** 底部操作条「已选 N 项」 */
|
||||
val selectedCount = MutableLiveData("0")
|
||||
|
||||
/** 全选状态(手机 PhoneBottomBar 勾选图标) */
|
||||
val isAllChecked = MutableLiveData(false)
|
||||
|
||||
/** 手机专属的额外请求(Tab 角标、特码字典)开关,仅手机形态在 Activity 中开启 */
|
||||
private var phoneExtrasEnabled = false
|
||||
|
||||
fun initPhoneExtras() {
|
||||
phoneExtrasEnabled = true
|
||||
// 特码字典:flag=0 国内、ieFlag=I 进港(是否生效待实测,见问题清单)
|
||||
DictUtils.getSpecialCodeList(addAll = false, flag = 0, ieFlag = "I") { list ->
|
||||
spCodeList.postValue(listOf(KeyValue("全部", "")) + list)
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// 方法区
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@@ -95,25 +130,73 @@ class GnjMoveStashListViewModel : BasePageViewModel() {
|
||||
}
|
||||
|
||||
|
||||
/** 查询条件(分页参数除外),search / searchMoved / searchTotal 三处共用同一套入参 */
|
||||
private fun buildFilterParams(): Map<String, Any?> = mapOf(
|
||||
"awbType" to businessType.value!!.ifEmpty { null },
|
||||
"wbNo" to waybill.value!!.ifEmpty { null },
|
||||
"carrier" to carrier.value!!.ifEmpty { null },
|
||||
// 以下为手机筛选弹层字段,平板恒为空串 → 恒传 null,行为不变
|
||||
"fdate" to flightDate.value?.ifEmpty { null },
|
||||
"fno" to flightNo.value?.ifEmpty { null },
|
||||
"spCode" to spCode.value?.ifEmpty { null },
|
||||
)
|
||||
|
||||
override fun getData() {
|
||||
val body = mapOf(
|
||||
val body = (buildFilterParams() + mapOf(
|
||||
"page" to pageModel.page,
|
||||
"limit" to pageModel.limit,
|
||||
"awbType" to businessType.value!!.ifEmpty { null },
|
||||
"wbNo" to waybill.value!!.ifEmpty { null },
|
||||
"carrier" to carrier.value!!.ifEmpty { null },
|
||||
).toRequestBody()
|
||||
)).toRequestBody()
|
||||
val moved = moveState.value == "1"
|
||||
launchLoadingCollect({
|
||||
NetApply.api.getGnjMoveStashList(
|
||||
body
|
||||
)
|
||||
// 平板 moveState 恒为 "0" → 恒走 search(原行为);已移库 Tab 走 searchMoved
|
||||
if (moved) NetApply.api.getGnjMoveStashMovedList(body)
|
||||
else NetApply.api.getGnjMoveStashList(body)
|
||||
}) {
|
||||
onSuccess = {
|
||||
pageModel.handleListBean(it)
|
||||
// searchMoved 出参无移库标识,按端点打标(卡片形态/详情移库信息卡依赖)
|
||||
it.list?.forEach { bean -> bean.isMoved = moved }
|
||||
pageModel.handleListBean(it) { updateCheckAllStatus() }
|
||||
count.value = it.total
|
||||
}
|
||||
}
|
||||
getCountData(body)
|
||||
if (phoneExtrasEnabled) loadTabCounts()
|
||||
}
|
||||
|
||||
/** Tab 角标:search / searchMoved 各以 limit=1 查一次取分页 total(仅手机形态发起) */
|
||||
private fun loadTabCounts() {
|
||||
val body = (buildFilterParams() + mapOf("page" to 1, "limit" to 1)).toRequestBody()
|
||||
launchCollect({ NetApply.api.getGnjMoveStashList(body) }) {
|
||||
onSuccess = { updateTabCount(0, it.total) }
|
||||
}
|
||||
launchCollect({ NetApply.api.getGnjMoveStashMovedList(body) }) {
|
||||
onSuccess = { updateTabCount(1, it.total) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTabCount(index: Int, total: Int?) {
|
||||
val current = moveStateCounts.value?.toMutableList() ?: mutableListOf("", "")
|
||||
if (index < current.size) {
|
||||
current[index] = (total ?: 0).toString()
|
||||
moveStateCounts.value = current
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 手机端全选 / 已选计数 ==========
|
||||
|
||||
fun toggleSelectAll() {
|
||||
val list = pageModel.rv?.commonAdapter()?.items
|
||||
?.filterIsInstance<MoveStashBean>() ?: return
|
||||
CheckUtil.handleAllCheck(list)
|
||||
updateCheckAllStatus()
|
||||
pageModel.rv?.commonAdapter()?.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun updateCheckAllStatus() {
|
||||
val list = pageModel.rv?.commonAdapter()?.items
|
||||
?.filterIsInstance<MoveStashBean>() ?: return
|
||||
isAllChecked.value = list.isNotEmpty() && list.all { it.checked.get() }
|
||||
selectedCount.value = list.count { it.checked.get() }.toString()
|
||||
}
|
||||
|
||||
private fun getCountData(body: RequestBody) {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.lukouguoji.aerologic.page.gnj.move.stash.photo
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import com.lukouguoji.aerologic.R
|
||||
import com.lukouguoji.aerologic.databinding.ActivityGnjMoveStashPhotoBinding
|
||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||
import com.lukouguoji.module_base.common.Constant
|
||||
import com.lukouguoji.module_base.ktx.addOnItemClickListener
|
||||
|
||||
/**
|
||||
* 国内进港移库「拍照上传」(5.5 寸手持端专属页面,无平板变体)
|
||||
*
|
||||
* 由列表卡片长按浮层「拍照」或运单详情「异常照片」加号槽位进入。
|
||||
* 已有照片经 DomImpMove/detail 回填,提交走 DomImpMove/modify
|
||||
* (mawbId + pic/originalPic/picNumber 三字段规范,与平板移交编辑页同一链路)。
|
||||
*/
|
||||
class GnjMoveStashPhotoActivity :
|
||||
BaseBindingActivity<ActivityGnjMoveStashPhotoBinding, GnjMoveStashPhotoViewModel>() {
|
||||
|
||||
override fun layoutId() = R.layout.activity_gnj_move_stash_photo
|
||||
override fun viewModelClass() = GnjMoveStashPhotoViewModel::class.java
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow("拍照上传")
|
||||
binding.viewModel = viewModel
|
||||
|
||||
viewModel.rv = binding.rv
|
||||
binding.rv.addOnItemClickListener(viewModel)
|
||||
|
||||
viewModel.initOnCreated(intent)
|
||||
}
|
||||
|
||||
companion object {
|
||||
/** 已移库运单的 moveId(movedDetail 回填照片用) */
|
||||
const val EXTRA_MOVE_ID = "moveId"
|
||||
|
||||
@JvmStatic
|
||||
fun start(context: Context, mawbId: String, wbNo: String, moveId: String = "") {
|
||||
context.startActivity(
|
||||
Intent(context, GnjMoveStashPhotoActivity::class.java)
|
||||
.putExtra(Constant.Key.ID, mawbId)
|
||||
.putExtra(Constant.Key.CODE, wbNo)
|
||||
.putExtra(EXTRA_MOVE_ID, moveId)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
package com.lukouguoji.aerologic.page.gnj.move.stash.photo
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.lukouguoji.module_base.base.BaseViewModel
|
||||
import com.lukouguoji.module_base.bean.FileBean
|
||||
import com.lukouguoji.module_base.bean.GnjYiKuBean
|
||||
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.impl.ImageSelectNewViewHolder
|
||||
import com.lukouguoji.module_base.interfaces.IOnItemClickListener
|
||||
import com.lukouguoji.module_base.ktx.commonAdapter
|
||||
import com.lukouguoji.module_base.ktx.launchCollect
|
||||
import com.lukouguoji.module_base.ktx.launchLoadingCollect
|
||||
import com.lukouguoji.module_base.ktx.noNull
|
||||
import com.lukouguoji.module_base.ktx.showToast
|
||||
import com.lukouguoji.module_base.ktx.toRequestBody
|
||||
import com.lukouguoji.module_base.util.MediaUtil
|
||||
import com.lukouguoji.module_base.util.UploadUtil
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onCompletion
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* 国内进港移库「拍照上传」ViewModel(5.5 寸手持端专属页面)
|
||||
*
|
||||
* 图片选择/预览/删除复用 module_base 的 ImageSelectNewViewHolder(末位加号槽位)。
|
||||
* 已有照片回填:待移库经 DomImpMove/detail(mawbId),已移库经 DomImpMove/movedDetail(moveId,
|
||||
* searchMoved 出参不含 mawbId)。提交走 DomImpMove/modify 最小体
|
||||
* (mawbId/remark/picNumber/pic/originalPic),与平板移交编辑页同一链路。
|
||||
*/
|
||||
class GnjMoveStashPhotoViewModel : BaseViewModel(), IOnItemClickListener {
|
||||
|
||||
var mawbId = ""
|
||||
|
||||
/** 已移库运单的移库记录 ID(searchMoved 出参),用于 movedDetail 回填 */
|
||||
var moveId = ""
|
||||
|
||||
/** 运单号(副标题展示,由列表带入) */
|
||||
val wbNo = MutableLiveData("")
|
||||
|
||||
/** detail 回填的完整 bean(提交时保留 remark 等原值) */
|
||||
private var detailBean = GnjYiKuBean()
|
||||
|
||||
// 图片网格适配器配置(复用公共图片选择组件)
|
||||
val itemViewHolder = ImageSelectNewViewHolder::class.java
|
||||
val itemLayoutId = com.lukouguoji.module_base.R.layout.item_image_select_new
|
||||
|
||||
var rv: RecyclerView? = null
|
||||
|
||||
fun initOnCreated(intent: Intent) {
|
||||
mawbId = intent.getStringExtra(Constant.Key.ID).orEmpty()
|
||||
wbNo.value = intent.getStringExtra(Constant.Key.CODE).orEmpty()
|
||||
moveId = intent.getStringExtra(GnjMoveStashPhotoActivity.EXTRA_MOVE_ID).orEmpty()
|
||||
|
||||
// 已有照片回填(pic 缩略图 + originalPic 原图),末位补加号槽位;
|
||||
// 已移库运单无 mawbId,改按 moveId 走 movedDetail
|
||||
launchCollect({
|
||||
if (mawbId.isEmpty() && moveId.isNotEmpty()) NetApply.api.getGnjMoveStashMovedDetail(moveId)
|
||||
else NetApply.api.getGnjMoveStashDetail(mawbId)
|
||||
}) {
|
||||
onSuccess = {
|
||||
detailBean = it.data ?: GnjYiKuBean()
|
||||
val picList = detailBean.pic.split(",").filter { p -> p.isNotEmpty() }
|
||||
val originalList = detailBean.originalPic.split(",").filter { p -> p.isNotEmpty() }
|
||||
val images = picList.mapIndexed { index, picUrl ->
|
||||
FileBean(
|
||||
path = MediaUtil.fillUrl(picUrl),
|
||||
url = picUrl,
|
||||
originalPic = MediaUtil.fillUrl(originalList.getOrElse(index) { picUrl })
|
||||
)
|
||||
}
|
||||
rv?.post {
|
||||
rv?.commonAdapter()?.refresh(images + FileBean())
|
||||
}
|
||||
}
|
||||
onFailed = { _, _ ->
|
||||
// 详情取不到也允许直接新增照片
|
||||
rv?.post { rv?.commonAdapter()?.refresh(listOf(FileBean())) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认提交:先补传未上传的本地图片,再按三字段规范提交 modify
|
||||
*/
|
||||
fun submitClick() {
|
||||
// modify 以 mawbId 定位运单;已移库运单 searchMoved/movedDetail 均不返回 mawbId(后端缺口),无法提交
|
||||
if (mawbId.isEmpty()) {
|
||||
showToast("已移库运单缺少运单ID,暂不支持提交照片")
|
||||
return
|
||||
}
|
||||
(rv?.commonAdapter()?.items ?: emptyList())
|
||||
.asFlow()
|
||||
.map { it as FileBean }
|
||||
.filter { it.path.isNotEmpty() && it.url.isEmpty() }
|
||||
.onEach {
|
||||
val data = UploadUtil.upload(it.path).data
|
||||
// UploadUtil 返回:newName=原图(较大),zipFileName=缩略图(较小)
|
||||
it.url = data?.zipFileName ?: ""
|
||||
it.originalPic = data?.newName ?: ""
|
||||
}
|
||||
.flowOn(Dispatchers.IO)
|
||||
.onStart { showLoading() }
|
||||
.catch {
|
||||
showToast(it.message.noNull("上传图片失败"))
|
||||
dismissLoading()
|
||||
}
|
||||
.onCompletion {
|
||||
launchLoadingCollect({
|
||||
val list = (rv?.commonAdapter()?.items ?: emptyList())
|
||||
.filterIsInstance<FileBean>()
|
||||
.filter { it.path.isNotEmpty() }
|
||||
|
||||
// 最小体提交:只更新图片三字段(remark 保留 detail 原值),与平板移交编辑页一致
|
||||
val params = mapOf(
|
||||
"mawbId" to mawbId,
|
||||
"remark" to detailBean.remark,
|
||||
"picNumber" to list.size.toString(),
|
||||
"pic" to list.joinToString(",") { MediaUtil.removeUrl(it.url) },
|
||||
"originalPic" to list.joinToString(",") { MediaUtil.removeUrl(it.originalPic) },
|
||||
).toRequestBody(removeEmptyOrNull = true)
|
||||
|
||||
NetApply.api.modifyGnjMoveStash(params)
|
||||
}) {
|
||||
onSuccess = {
|
||||
showToast("提交成功")
|
||||
viewModelScope.launch {
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
|
||||
}
|
||||
getTopActivity().finish()
|
||||
}
|
||||
onFailed = { _, msg ->
|
||||
showToast(msg.noNull("提交失败"))
|
||||
}
|
||||
}
|
||||
}
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
/**
|
||||
* 「拍照/上传」按钮:直接唤起图片选择(含拍照入口)
|
||||
*/
|
||||
fun pickClick() {
|
||||
MediaUtil.pickImage(getTopActivity(), maxNum = 9) { results ->
|
||||
val adapter = rv?.commonAdapter() ?: return@pickImage
|
||||
results.forEach { result ->
|
||||
// 在加号槽位(最后一项)之前插入
|
||||
val insertPos = (adapter.items.size - 1).coerceAtLeast(0)
|
||||
adapter.items.add(insertPos, FileBean(path = result.realPath))
|
||||
adapter.notifyItemInserted(insertPos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 图片网格点击回调(长按出删除角标 / 点删除角标移除)
|
||||
*/
|
||||
override fun onItemClick(position: Int, type: Int) {
|
||||
val adapter = rv?.commonAdapter() ?: return
|
||||
val bean = adapter.getItem(position) as? FileBean ?: return
|
||||
when (type) {
|
||||
com.lukouguoji.module_base.R.id.rl -> {
|
||||
if (bean.path.isNotEmpty()) {
|
||||
bean.canDelete.set(!bean.canDelete.get())
|
||||
}
|
||||
}
|
||||
|
||||
com.lukouguoji.module_base.R.id.iv_delete -> {
|
||||
adapter.removeItem(position)
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||
import com.lukouguoji.module_base.bean.LogBean
|
||||
import com.lukouguoji.module_base.common.Constant
|
||||
import com.lukouguoji.module_base.router.ARouterConstants
|
||||
import com.lukouguoji.module_base.util.DeviceUtil
|
||||
|
||||
@Route(path = ARouterConstants.ACTIVITY_URL_LOG_DETAIL)
|
||||
class LogDetailActivity : BaseBindingActivity<ActivityLogDetailBinding, LogDetailViewModel>() {
|
||||
@@ -34,7 +35,8 @@ class LogDetailActivity : BaseBindingActivity<ActivityLogDetailBinding, LogDetai
|
||||
}
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow("操作日志详情")
|
||||
// 手机版设计稿标题为「运单追踪」,平板保持原标题
|
||||
setBackArrow(if (DeviceUtil.isPhone()) "运单追踪" else "操作日志详情")
|
||||
binding.viewModel = viewModel
|
||||
|
||||
// 配置操作详情 RecyclerView(垂直时间线)
|
||||
@@ -58,7 +60,139 @@ class LogDetailActivity : BaseBindingActivity<ActivityLogDetailBinding, LogDetai
|
||||
val activeCodes = viewModel.activeStepCodes.value ?: emptySet()
|
||||
val latestCode = viewModel.latestStepCode.value ?: ""
|
||||
if (steps.isEmpty()) return
|
||||
buildStepProgressBar(steps, activeCodes, latestCode)
|
||||
// 手机布局是竖排时间线(layout/activity_log_detail.xml),平板保持横向步骤条
|
||||
if (DeviceUtil.isPhone()) {
|
||||
buildVerticalSteps(steps, activeCodes, latestCode)
|
||||
} else {
|
||||
buildStepProgressBar(steps, activeCodes, latestCode)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机版竖排流转时间线(对应设计稿「运单追踪」):
|
||||
* 每个节点 = 左侧圆点 + 连接竖线,右侧步骤名 + 该环节最新操作时间。
|
||||
* 已发生节点绿色,未发生节点灰色。
|
||||
*/
|
||||
private fun buildVerticalSteps(
|
||||
steps: List<StepInfo>,
|
||||
activeCodes: Set<String>,
|
||||
latestCode: String
|
||||
) {
|
||||
val container = binding.llSteps
|
||||
container.removeAllViews()
|
||||
container.orientation = LinearLayout.VERTICAL
|
||||
|
||||
val logs = viewModel.statusLogList.value ?: emptyList()
|
||||
val colorGreen = 0xFF16A34A.toInt()
|
||||
val colorGray = 0xFF9CA3AF.toInt()
|
||||
val colorLine = 0xFFE5E7EB.toInt()
|
||||
|
||||
for (i in steps.indices) {
|
||||
val step = steps[i]
|
||||
val isActive = step.code in activeCodes
|
||||
val isLast = i == steps.size - 1
|
||||
val stepLog = logs.lastOrNull { it.status == step.code }
|
||||
val time = stepLog?.opDate ?: ""
|
||||
val statusContent = stepLog?.content ?: ""
|
||||
|
||||
val row = LinearLayout(this).apply {
|
||||
orientation = LinearLayout.HORIZONTAL
|
||||
layoutParams = LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
}
|
||||
|
||||
// 左列:圆点 + 连接竖线
|
||||
val dotColumn = LinearLayout(this).apply {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
gravity = Gravity.CENTER_HORIZONTAL
|
||||
layoutParams = LinearLayout.LayoutParams(dp(20), LinearLayout.LayoutParams.MATCH_PARENT)
|
||||
}
|
||||
val dot = View(this).apply {
|
||||
setBackgroundResource(
|
||||
if (isActive) com.lukouguoji.module_base.R.drawable.bg_phone_dot_green
|
||||
else com.lukouguoji.module_base.R.drawable.bg_phone_dot_gray
|
||||
)
|
||||
layoutParams = LinearLayout.LayoutParams(
|
||||
dp(if (isActive) 12 else 8), dp(if (isActive) 12 else 8)
|
||||
).apply { topMargin = dp(if (isActive) 2 else 4) }
|
||||
}
|
||||
dotColumn.addView(dot)
|
||||
if (!isLast) {
|
||||
val line = View(this).apply {
|
||||
setBackgroundColor(colorLine)
|
||||
layoutParams = LinearLayout.LayoutParams(dp(2), 0).apply {
|
||||
weight = 1f
|
||||
topMargin = dp(2)
|
||||
bottomMargin = dp(2)
|
||||
}
|
||||
}
|
||||
dotColumn.addView(line)
|
||||
}
|
||||
row.addView(dotColumn)
|
||||
|
||||
// 右列:步骤名 + 时间
|
||||
val content = LinearLayout(this).apply {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
layoutParams = LinearLayout.LayoutParams(
|
||||
0, LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
).apply {
|
||||
weight = 1f
|
||||
leftMargin = dp(10)
|
||||
}
|
||||
setPadding(0, 0, 0, if (isLast) 0 else dp(24))
|
||||
}
|
||||
// 名称行:步骤名(左)+ 已发生节点的状态 pill(右,设计稿如「放行状态:01」)
|
||||
val nameRow = LinearLayout(this).apply {
|
||||
orientation = LinearLayout.HORIZONTAL
|
||||
gravity = Gravity.CENTER_VERTICAL
|
||||
layoutParams = LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
}
|
||||
nameRow.addView(TextView(this).apply {
|
||||
text = step.name
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_SP, 15f)
|
||||
setTextColor(if (isActive) colorGreen else colorGray)
|
||||
if (isActive) setTypeface(typeface, android.graphics.Typeface.BOLD)
|
||||
layoutParams = LinearLayout.LayoutParams(
|
||||
0, LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
).apply { weight = 1f }
|
||||
})
|
||||
if (isActive && statusContent.isNotEmpty()) {
|
||||
nameRow.addView(TextView(this).apply {
|
||||
text = statusContent
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_SP, 11f)
|
||||
setTextColor(colorGreen)
|
||||
setBackgroundResource(com.lukouguoji.module_base.R.drawable.bg_phone_tag_green)
|
||||
setPadding(dp(8), dp(3), dp(8), dp(3))
|
||||
maxLines = 1
|
||||
ellipsize = android.text.TextUtils.TruncateAt.END
|
||||
maxWidth = dp(180)
|
||||
layoutParams = LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
).apply { leftMargin = dp(8) }
|
||||
})
|
||||
}
|
||||
content.addView(nameRow)
|
||||
if (time.isNotEmpty()) {
|
||||
content.addView(TextView(this).apply {
|
||||
text = time
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_SP, 12f)
|
||||
setTextColor(colorGray)
|
||||
layoutParams = LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
).apply { topMargin = dp(4) }
|
||||
})
|
||||
}
|
||||
row.addView(content)
|
||||
|
||||
container.addView(row)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildStepProgressBar(
|
||||
|
||||
@@ -36,7 +36,7 @@ class UldEditViewModel : BaseViewModel() {
|
||||
|
||||
// ========== 手机版(5.5 寸手持端)专用 ==========
|
||||
|
||||
/** 来源选项(本地枚举;后端字段暂不支持,需求已登记 documents/后端接口对接问题清单.xlsx) */
|
||||
/** 来源选项(与平板端一致:空运 / 陆运) */
|
||||
val sourceEditList = MutableLiveData<List<KeyValue>>(
|
||||
listOf(
|
||||
KeyValue("空运", "空运"),
|
||||
@@ -45,8 +45,8 @@ class UldEditViewModel : BaseViewModel() {
|
||||
)
|
||||
|
||||
/**
|
||||
* 手机版状态选项。设计稿为三态(可用/占用/维修),后端枚举当前仅 0/1,
|
||||
* 按语义映射 可用=0 / 维修=1;「占用」待后端扩展枚举后放开(需求已登记清单)。
|
||||
* 手机版状态选项。后端枚举维持两态(0 正常 / 1 故障,不新增「占用」),
|
||||
* 按设计稿文案映射 可用=0 / 维修=1。
|
||||
*/
|
||||
val statusPhoneList = listOf(
|
||||
KeyValue("可用", "0"),
|
||||
@@ -64,7 +64,7 @@ class UldEditViewModel : BaseViewModel() {
|
||||
loadCarrierList(null)
|
||||
// 手机版新增默认所在港 HFE(设计稿约定);平板无此预填,行为不变
|
||||
if (DeviceUtil.isPhone()) {
|
||||
uldBean.value = uldBean.value?.copy(airport = "HFE")
|
||||
uldBean.value = uldBean.value?.copy(nowPort = "HFE")
|
||||
}
|
||||
} else {
|
||||
getData()
|
||||
@@ -107,11 +107,24 @@ class UldEditViewModel : BaseViewModel() {
|
||||
showToast("自重不能为空")
|
||||
return
|
||||
}
|
||||
if (bean.checkInDate.isBlank()) {
|
||||
// saveUld 缺最大装载容积/最大载重时后端直接 500(内网实测),提前拦截
|
||||
if (bean.maxVolume.isBlank()) {
|
||||
showToast("最大装载容积不能为空")
|
||||
return
|
||||
}
|
||||
if (bean.maxWeight.isBlank()) {
|
||||
showToast("最大载重不能为空")
|
||||
return
|
||||
}
|
||||
if (bean.inStoreTime.isBlank()) {
|
||||
showToast("入库时间不能为空")
|
||||
return
|
||||
}
|
||||
}
|
||||
// 手机版日期行只产出 yyyy-MM-dd,而 inStoreTime 为 date-time(仅日期后端返回 400),补齐时分秒
|
||||
if (DeviceUtil.isPhone() && bean.inStoreTime.length == 10) {
|
||||
bean.inStoreTime = "${bean.inStoreTime} 00:00:00"
|
||||
}
|
||||
val isAdd = pageType.value == DetailsPageType.Add
|
||||
launchLoadingCollect({
|
||||
if (isAdd) NetApply.api.saveUld(bean.toRequestBody())
|
||||
@@ -121,7 +134,7 @@ class UldEditViewModel : BaseViewModel() {
|
||||
showToast(it.msg.noNull(if (isAdd) "新增成功" else "修改成功"))
|
||||
if (isAdd) {
|
||||
// 清空表单继续录入;手机版保持所在港默认 HFE(与进入页面时一致)
|
||||
uldBean.value = if (DeviceUtil.isPhone()) ULDBean(airport = "HFE") else ULDBean()
|
||||
uldBean.value = if (DeviceUtil.isPhone()) ULDBean(nowPort = "HFE") else ULDBean()
|
||||
} else {
|
||||
getData()
|
||||
}
|
||||
|
||||
@@ -70,13 +70,11 @@ class UldListActivity : BaseBindingActivity<ActivityUldListBinding, UldListViewM
|
||||
/**
|
||||
* 手机版筛选:重置
|
||||
*
|
||||
* 只清空弹层内的四个条件(入库时间 / 进港航班号 / 所属航司 / 来源),不影响顶部搜索框。
|
||||
* 只清空弹层内的两个条件(状态 / 所属航司),不影响顶部搜索框。
|
||||
*/
|
||||
fun resetFilter() {
|
||||
viewModel.checkInDateFilter.value = ""
|
||||
viewModel.ifNoFilter.value = ""
|
||||
viewModel.status.value = ""
|
||||
viewModel.uldSuffix.value = ""
|
||||
viewModel.sourceFilter.value = ""
|
||||
}
|
||||
|
||||
/** 手机版筛选:确认 */
|
||||
@@ -85,7 +83,7 @@ class UldListActivity : BaseBindingActivity<ActivityUldListBinding, UldListViewM
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
/** 手机版批量删除(二次确认后逐条调用单条删除接口) */
|
||||
/** 手机版批量删除(二次确认后调用批量删除接口) */
|
||||
fun showDeleteConfirmDialog() {
|
||||
val selected = viewModel.getSelectedItems()
|
||||
if (selected.isEmpty()) {
|
||||
|
||||
@@ -27,20 +27,15 @@ class UldListViewModel : BasePageViewModel() {
|
||||
val uldSuffix = MutableLiveData("")
|
||||
val uldNo = MutableLiveData("")
|
||||
|
||||
// ========== 手机版(5.5 寸手持端)专用筛选条件 ==========
|
||||
// 平板布局无对应控件,恒为空 → 不进请求参数,平板查询行为与改造前完全一致。
|
||||
// 三个入参后端暂不支持(api-doc 已核对),已登记 documents/后端接口对接问题清单.xlsx,
|
||||
// 按「以设计为准」的约定照传(后端静默忽略无副作用),后端支持后自动生效。
|
||||
val checkInDateFilter = MutableLiveData("") // 入库时间
|
||||
val ifNoFilter = MutableLiveData("") // 进港航班号
|
||||
val sourceFilter = MutableLiveData("") // 来源:空运 / 陆运
|
||||
// ========== 手机版(5.5 寸手持端)筛选 ==========
|
||||
// 后端确认查询入参与平板端保持一致(uld / status / uldSuffix),手机筛选弹层只放 状态 + 所属航司。
|
||||
|
||||
/** 来源下拉(本地枚举,后端字段需求已登记清单) */
|
||||
val sourceList = MutableLiveData<List<KeyValue>>(
|
||||
/** 手机版状态下拉:文案与卡片标签一致(可用=0 / 维修=1) */
|
||||
val statusPhoneFilterList = MutableLiveData<List<KeyValue>>(
|
||||
listOf(
|
||||
KeyValue("全部", ""),
|
||||
KeyValue("空运", "空运"),
|
||||
KeyValue("陆运", "陆运"),
|
||||
KeyValue("可用", "0"),
|
||||
KeyValue("维修", "1"),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -82,10 +77,6 @@ class UldListViewModel : BasePageViewModel() {
|
||||
"status" to status.value?.ifEmpty { null },
|
||||
"uldSuffix" to uldSuffix.value?.ifEmpty { null },
|
||||
"uld" to uldNo.value?.ifEmpty { null },
|
||||
// 手机版筛选维度(平板恒空不参与);后端暂不支持这三个入参,已登记清单
|
||||
"checkInDate" to checkInDateFilter.value?.ifEmpty { null },
|
||||
"ifNo" to ifNoFilter.value?.ifEmpty { null },
|
||||
"source" to sourceFilter.value?.ifEmpty { null },
|
||||
).toRequestBody()
|
||||
)
|
||||
}) {
|
||||
@@ -122,10 +113,7 @@ class UldListViewModel : BasePageViewModel() {
|
||||
?.filter { it.checked.get() } ?: emptyList()
|
||||
|
||||
/**
|
||||
* 批量删除选中的 ULD。
|
||||
*
|
||||
* 后端仅有单条删除接口(/eqm/uld/deleteUld,批量接口需求已登记清单),
|
||||
* 此处按队列逐条串行调用,全部完成后统一刷新;中途失败即停并提示。
|
||||
* 批量删除选中的 ULD(/eqm/uld/deleteUldBatch,请求体为 ULD 编号数组,一次调用)。
|
||||
*/
|
||||
fun deleteSelected() {
|
||||
val ulds = getSelectedItems().map { it.uld }
|
||||
@@ -133,19 +121,9 @@ class UldListViewModel : BasePageViewModel() {
|
||||
showToast("请选择要删除的ULD")
|
||||
return
|
||||
}
|
||||
deleteQueue(ulds, 0)
|
||||
}
|
||||
|
||||
private fun deleteQueue(ulds: List<String>, index: Int) {
|
||||
if (index >= ulds.size) {
|
||||
showToast("已删除 ${ulds.size} 条")
|
||||
refresh()
|
||||
return
|
||||
}
|
||||
launchLoadingCollect({ NetApply.api.deleteUld(ulds[index]) }) {
|
||||
onSuccess = { deleteQueue(ulds, index + 1) }
|
||||
onFailed = { _, msg ->
|
||||
showToast("删除 ${ulds[index]} 失败:${msg.noNull("未知错误")}")
|
||||
launchLoadingCollect({ NetApply.api.deleteUldBatch(ulds.toRequestBody()) }) {
|
||||
onSuccess = {
|
||||
showToast("已删除 ${ulds.size} 条")
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
|
||||
153
app/src/main/res/layout-sw600dp/activity_gnj_move_stash_list.xml
Normal file
153
app/src/main/res/layout-sw600dp/activity_gnj_move_stash_list.xml
Normal file
@@ -0,0 +1,153 @@
|
||||
<?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" />
|
||||
|
||||
<variable
|
||||
name="viewModel"
|
||||
type="com.lukouguoji.aerologic.page.gnj.move.stash.list.GnjMoveStashListViewModel" />
|
||||
|
||||
<!-- 平板不使用,仅为与手机变体保持 <variable> 一致(DataBinding 双变体强制约束) -->
|
||||
<variable
|
||||
name="activity"
|
||||
type="com.lukouguoji.aerologic.page.gnj.move.stash.list.GnjMoveStashListActivity" />
|
||||
</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">
|
||||
|
||||
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
||||
hint='@{"请选择业务类型"}'
|
||||
list="@{viewModel.businessTypeList}"
|
||||
type="@{SearchLayoutType.SPINNER}"
|
||||
value="@={viewModel.businessType}"
|
||||
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}"
|
||||
setInputWaybill="@{true}"
|
||||
setOnIconClickListener="@{()-> viewModel.waybillScanClick()}"
|
||||
setRefreshCallBack="@{viewModel::refresh}"
|
||||
setSearchListRefresh="@{viewModel::getWayBillList}"
|
||||
type="@{SearchLayoutType.INPUT}"
|
||||
value="@={viewModel.waybill}"
|
||||
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.carrier}"
|
||||
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">
|
||||
|
||||
<ImageView
|
||||
style="@style/iv_search_action"
|
||||
android:onClick="@{()-> viewModel.refresh()}"
|
||||
android:src="@drawable/img_search" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
</LinearLayout>
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingTop="10dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="15dp"
|
||||
android:onClick="@{()->viewModel.checkAllClick()}"
|
||||
android:text="全选" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/checkIcon"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:onClick="@{()->viewModel.checkAllClick()}"
|
||||
android:src="@drawable/img_check_all" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<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"
|
||||
itemLayoutId="@{viewModel.itemLayoutId}"
|
||||
viewHolder="@{viewModel.itemViewHolder}"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:listitem="@layout/item_gnj_move_stash_list" />
|
||||
|
||||
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:background="@color/color_bottom_layout"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingHorizontal="15dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text='@{"合计:"+viewModel.count+"条,总件数:"+viewModel.number+",总重量:"+viewModel.weight+"KG"}'
|
||||
android:textColor="@color/white"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="合计:3条,总件数:212,总重量:342KG" />
|
||||
|
||||
<TextView
|
||||
style="@style/tv_bottom_btn"
|
||||
android:onClick="@{()-> viewModel.moveStashClick()}"
|
||||
android:text="移库" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</layout>
|
||||
231
app/src/main/res/layout-sw600dp/activity_log_detail.xml
Normal file
231
app/src/main/res/layout-sw600dp/activity_log_detail.xml
Normal file
@@ -0,0 +1,231 @@
|
||||
<?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>
|
||||
|
||||
<variable
|
||||
name="viewModel"
|
||||
type="com.lukouguoji.aerologic.page.log.detail.LogDetailViewModel" />
|
||||
</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" />
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="15dp">
|
||||
|
||||
<!-- 运单信息 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- 标题区 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:background="@drawable/bg_white_radius_top_8"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingHorizontal="15dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="运单信息"
|
||||
android:textColor="#333333"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 分割线(贯穿卡片宽度) -->
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="#E7E7E7" />
|
||||
|
||||
<!-- 内容区 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_white_radius_bottom_8"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="30dp"
|
||||
android:layout_marginEnd="15dp"
|
||||
android:layout_marginVertical="12dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="运单号:"
|
||||
android:textColor="#666666"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{viewModel.waybillNo}"
|
||||
android:textColor="#333333"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="运单类型:"
|
||||
android:textColor="#666666"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{viewModel.waybillType}"
|
||||
android:textColor="#333333"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 流转状态 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="15dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- 标题区 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:background="@drawable/bg_white_radius_top_8"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingHorizontal="15dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="流转状态"
|
||||
android:textColor="#333333"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 分割线 -->
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="#E7E7E7" />
|
||||
|
||||
<!-- 内容区 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_white_radius_bottom_8"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_steps"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="23dp"
|
||||
android:layout_marginEnd="15dp"
|
||||
android:layout_marginVertical="12dp"
|
||||
android:orientation="horizontal" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 操作详情 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="15dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- 标题区 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:background="@drawable/bg_white_radius_top_8"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingHorizontal="15dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="操作详情"
|
||||
android:textColor="#333333"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 分割线 -->
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="#E7E7E7" />
|
||||
|
||||
<!-- 内容区 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_white_radius_bottom_8"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_timeline"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:paddingStart="8dp"
|
||||
android:nestedScrollingEnabled="false"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
</layout>
|
||||
296
app/src/main/res/layout-sw600dp/item_gnj_move_stash_list.xml
Normal file
296
app/src/main/res/layout-sw600dp/item_gnj_move_stash_list.xml
Normal file
@@ -0,0 +1,296 @@
|
||||
<?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>
|
||||
|
||||
<variable
|
||||
name="bean"
|
||||
type="com.lukouguoji.module_base.bean.MoveStashBean" />
|
||||
|
||||
<!-- 以下两个变量平板不使用,仅为与手机变体保持 <variable> 一致(DataBinding 双变体强制约束) -->
|
||||
<variable
|
||||
name="position"
|
||||
type="Integer" />
|
||||
|
||||
<variable
|
||||
name="activity"
|
||||
type="com.lukouguoji.aerologic.page.gnj.move.stash.list.GnjMoveStashListActivity" />
|
||||
</data>
|
||||
|
||||
<!-- 外层容器承载间距 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="15dp"
|
||||
android:layout_marginVertical="5dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- 侧滑布局 -->
|
||||
<com.mcxtzhang.swipemenulib.SwipeMenuLayout
|
||||
android:id="@+id/swipe_menu"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<!-- 主列表项容器 -->
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/ll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_item"
|
||||
android:orientation="horizontal"
|
||||
android:padding="10dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_icon"
|
||||
loadImage="@{bean.checked ? @drawable/img_plane_s : @drawable/img_plane}"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/img_plane" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.1"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
completeSpace="@{4}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="运单号:" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{bean.wbNo}"
|
||||
android:textColor="@color/colorPrimary"
|
||||
tools:text="789165431" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0.8"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
completeSpace="@{4}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="件数:" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text='@{bean.pc}' />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0.7"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
completeSpace="@{4}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="重量:" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{bean.weight}" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0.8"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
completeSpace="@{4}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="代理人:" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text='@{bean.agentCode}' />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.1"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
completeSpace="@{5}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="运单类型:" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text='@{bean.awbType}' />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp">
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.1"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
completeSpace="@{4}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="航班:" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{bean.flight}" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0.8"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
completeSpace="@{4}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="始发港:" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{bean.origin}" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0.8"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
completeSpace="@{4}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="起始站:" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{bean.dep}" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0.8"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
completeSpace="@{4}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="目的港:" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{bean.dest}" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.1"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
completeSpace="@{5}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="品名:" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{bean.goods}" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 右侧箭头 -->
|
||||
<ImageView
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:src="@drawable/img_pda_right" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<!-- 侧滑菜单区域 -->
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<!-- 编辑按钮 -->
|
||||
<TextView
|
||||
android:id="@+id/btn_edit"
|
||||
style="@style/tv_item_action"
|
||||
android:background="@color/colorPrimary"
|
||||
android:text="编辑" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
</com.mcxtzhang.swipemenulib.SwipeMenuLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</layout>
|
||||
332
app/src/main/res/layout/activity_gnj_move_stash_detail.xml
Normal file
332
app/src/main/res/layout/activity_gnj_move_stash_detail.xml
Normal file
@@ -0,0 +1,332 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
国内进港移库「运单详情」—— 5.5 寸手持端专属页面(无平板变体)
|
||||
|
||||
对应设计稿 11_进港移库 的「运单详情」页:
|
||||
· 卡片一:蓝色表头(运单号 + 绿点 + 操作时间)+ 类型标签行(红「运单类型」+ 货物类型)
|
||||
+ 品名大字 + 两列字段网格(件数/重量/特码/代理/出运路径/承运人)
|
||||
· 卡片二:绿色表头「移库信息」+ 移库人 / 移库时间(仅已移库显示)
|
||||
· 卡片三:橙色表头「异常照片」+ 三个虚线加号槽位(点击跳拍照上传页)
|
||||
-->
|
||||
<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="viewModel"
|
||||
type="com.lukouguoji.aerologic.page.gnj.move.stash.detail.GnjMoveStashDetailViewModel" />
|
||||
|
||||
<variable
|
||||
name="activity"
|
||||
type="com.lukouguoji.aerologic.page.gnj.move.stash.detail.GnjMoveStashDetailActivity" />
|
||||
</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">
|
||||
|
||||
<!-- 蓝色表头:运单号 + 绿点 + 操作时间 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_phone_card_header_blue"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingVertical="12dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@{viewModel.dataBean.wbNo}"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="17sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<View
|
||||
android:layout_width="8dp"
|
||||
android:layout_height="8dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:background="@drawable/bg_phone_dot_green" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{viewModel.dataBean.orDash(viewModel.dataBean.opDate)}"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<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:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="22dp"
|
||||
android:background="@drawable/bg_phone_tag_red"
|
||||
android:gravity="center"
|
||||
android:paddingHorizontal="8dp"
|
||||
android:text="@{viewModel.dataBean.orDash(viewModel.dataBean.awbType)}"
|
||||
android:textColor="@color/phone_tag_red_text"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<View
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="14dp"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:background="@color/phone_divider" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@{viewModel.dataBean.orDash(viewModel.dataBean.cargoType)}"
|
||||
android:textColor="@color/phone_text_body"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 品名(主字段大字) -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:text="@{viewModel.dataBean.orDash(viewModel.dataBean.goods)}"
|
||||
android:textColor="@color/phone_text_strong"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<!-- 第 1 行:件数 / 重量 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneKvItem
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
title='@{"件数"}'
|
||||
value="@{viewModel.dataBean.orDash(viewModel.dataBean.pc)}" />
|
||||
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneKvItem
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_weight="1"
|
||||
title='@{"重量"}'
|
||||
value='@{viewModel.dataBean.orDash(viewModel.dataBean.weight) + " kg"}' />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 第 2 行:特码 / 代理 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneKvItem
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
title='@{"特码"}'
|
||||
value="@{viewModel.dataBean.spCode}" />
|
||||
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneKvItem
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_weight="1"
|
||||
title='@{"代理"}'
|
||||
value="@{viewModel.dataBean.agentDisplay}" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 第 3 行:出运路径 / 承运人 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneKvItem
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
title='@{"出运路径"}'
|
||||
value="@{viewModel.dataBean.range}" />
|
||||
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneKvItem
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_weight="1"
|
||||
title='@{"承运人"}'
|
||||
value="@{viewModel.dataBean.by1}" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- ==================== 卡片二:移库信息(仅已移库显示) ==================== -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="@drawable/bg_phone_card"
|
||||
android:orientation="vertical"
|
||||
android:visibility="@{viewModel.dataBean.isMoved ? View.VISIBLE : View.GONE}">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_phone_card_header_green"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingVertical="10dp"
|
||||
android:text="移库信息"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingVertical="12dp">
|
||||
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneKvItem
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
title='@{"移库人"}'
|
||||
value="@{viewModel.dataBean.opUserDisplay}" />
|
||||
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneKvItem
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_weight="1"
|
||||
title='@{"移库时间"}'
|
||||
value="@{viewModel.dataBean.opDate}" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- ==================== 卡片三:异常照片 ==================== -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="@drawable/bg_phone_card"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_phone_card_header_orange"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingVertical="10dp"
|
||||
android:text="异常照片"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<!-- 三个虚线加号槽位(等宽正方形由 weight + 固定高实现),点击进拍照上传页 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="96dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_phone_photo_add"
|
||||
android:gravity="center"
|
||||
android:onClick="@{()-> activity.openPhoto()}"
|
||||
android:text="+"
|
||||
android:textColor="@color/phone_text_hint"
|
||||
android:textSize="24sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="96dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_phone_photo_add"
|
||||
android:gravity="center"
|
||||
android:onClick="@{()-> activity.openPhoto()}"
|
||||
android:text="+"
|
||||
android:textColor="@color/phone_text_hint"
|
||||
android:textSize="24sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="96dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_phone_photo_add"
|
||||
android:gravity="center"
|
||||
android:onClick="@{()-> activity.openPhoto()}"
|
||||
android:text="+"
|
||||
android:textColor="@color/phone_text_hint"
|
||||
android:textSize="24sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</layout>
|
||||
@@ -1,148 +1,166 @@
|
||||
<?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" />
|
||||
|
||||
<variable
|
||||
name="viewModel"
|
||||
type="com.lukouguoji.aerologic.page.gnj.move.stash.list.GnjMoveStashListViewModel" />
|
||||
</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">
|
||||
|
||||
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
||||
hint='@{"请选择业务类型"}'
|
||||
list="@{viewModel.businessTypeList}"
|
||||
type="@{SearchLayoutType.SPINNER}"
|
||||
value="@={viewModel.businessType}"
|
||||
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}"
|
||||
setInputWaybill="@{true}"
|
||||
setOnIconClickListener="@{()-> viewModel.waybillScanClick()}"
|
||||
setRefreshCallBack="@{viewModel::refresh}"
|
||||
setSearchListRefresh="@{viewModel::getWayBillList}"
|
||||
type="@{SearchLayoutType.INPUT}"
|
||||
value="@={viewModel.waybill}"
|
||||
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.carrier}"
|
||||
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">
|
||||
|
||||
<ImageView
|
||||
style="@style/iv_search_action"
|
||||
android:onClick="@{()-> viewModel.refresh()}"
|
||||
android:src="@drawable/img_search" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
</LinearLayout>
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingTop="10dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="15dp"
|
||||
android:onClick="@{()->viewModel.checkAllClick()}"
|
||||
android:text="全选" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/checkIcon"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:onClick="@{()->viewModel.checkAllClick()}"
|
||||
android:src="@drawable/img_check_all" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<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"
|
||||
itemLayoutId="@{viewModel.itemLayoutId}"
|
||||
viewHolder="@{viewModel.itemViewHolder}"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:listitem="@layout/item_gnj_move_stash_list" />
|
||||
|
||||
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:background="@color/color_bottom_layout"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingHorizontal="15dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text='@{"合计:"+viewModel.count+"条,总件数:"+viewModel.number+",总重量:"+viewModel.weight+"KG"}'
|
||||
android:textColor="@color/white"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="合计:3条,总件数:212,总重量:342KG" />
|
||||
|
||||
<TextView
|
||||
style="@style/tv_bottom_btn"
|
||||
android:onClick="@{()-> viewModel.moveStashClick()}"
|
||||
android:text="移库" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</layout>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
国内进港移库 —— 5.5 寸手持端布局(平板变体见 layout-sw600dp/ 同名文件)
|
||||
|
||||
对应设计稿 documents/5.5寸手持端设计文件/11_进港移库/进港移库.html:
|
||||
· 顶部搜索框(运单号,含扫码)+ 筛选弹层(航班日期 / 航班号 / 特码 / 运单类型)
|
||||
· 「待移库 / 已移库」Tab 绑定 viewModel.moveState("0"/"1"),
|
||||
分别走 DomImpMove/search 与 DomImpMove/searchMoved 两个端点
|
||||
· 已移库 Tab 下隐藏底部操作条(与设计稿一致)
|
||||
· 卡片长按出「拍照」浮层(见 item_gnj_move_stash_list.xml)
|
||||
-->
|
||||
<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" />
|
||||
|
||||
<import type="com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayoutType" />
|
||||
|
||||
<variable
|
||||
name="viewModel"
|
||||
type="com.lukouguoji.aerologic.page.gnj.move.stash.list.GnjMoveStashListViewModel" />
|
||||
|
||||
<variable
|
||||
name="activity"
|
||||
type="com.lukouguoji.aerologic.page.gnj.move.stash.list.GnjMoveStashListActivity" />
|
||||
</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.waybillScanClick()}"
|
||||
setRefreshCallBack="@{viewModel::refresh}"
|
||||
upperCase="@{true}"
|
||||
value="@={viewModel.waybill}" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- ==================== 待移库 / 已移库 Tab ==================== -->
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneStatusTab
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
counts="@{viewModel.moveStateCounts}"
|
||||
setOnTabChanged="@{viewModel::refresh}"
|
||||
tabs="@{viewModel.moveStateTabs}"
|
||||
value="@={viewModel.moveState}" />
|
||||
|
||||
<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:paddingBottom="12dp"
|
||||
itemLayoutId="@{viewModel.itemLayoutId}"
|
||||
viewHolder="@{viewModel.itemViewHolder}"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:itemCount="3"
|
||||
tools:listitem="@layout/item_gnj_move_stash_list" />
|
||||
|
||||
</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.isAllChecked}"
|
||||
countText='@{"已选 " + viewModel.selectedCount + " 项"}'
|
||||
setOnActionClick="@{(v)-> viewModel.moveStashClick()}"
|
||||
setOnAllCheckClick="@{(v)-> viewModel.toggleSelectAll()}"
|
||||
android:visibility="@{`1`.equals(viewModel.moveState) ? View.GONE : View.VISIBLE}" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- ==================== 筛选弹层 ==================== -->
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneFilterPanel
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
panelVisible="@{activity.filterPanelVisible}"
|
||||
setOnConfirmClick="@{(v)-> activity.confirmFilter()}"
|
||||
setOnDismissClick="@{(v)-> activity.toggleFilterPanel()}"
|
||||
setOnResetClick="@{(v)-> activity.resetFilter()}"
|
||||
title='@{"筛选条件"}'>
|
||||
|
||||
<!-- 航班日期(入参 fdate) -->
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
hint='@{"请选择航班日期"}'
|
||||
title='@{"航班日期"}'
|
||||
type="@{PhoneDataLayoutType.DATE}"
|
||||
value="@={viewModel.flightDate}" />
|
||||
|
||||
<!-- 航班号(入参 fno) -->
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
hint='@{"请输入航班号"}'
|
||||
title='@{"航班号"}'
|
||||
type="@{PhoneDataLayoutType.INPUT}"
|
||||
value="@={viewModel.flightNo}" />
|
||||
|
||||
<!-- 特码(入参 spCode) -->
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
hint='@{"请选择特码"}'
|
||||
list="@{viewModel.spCodeList}"
|
||||
title='@{"特码"}'
|
||||
type="@{PhoneDataLayoutType.SPINNER}"
|
||||
value="@={viewModel.spCode}" />
|
||||
|
||||
<!-- 运单类型(入参 awbType,复用平板既有 businessType 字段与字典) -->
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
hint='@{"请选择运单类型"}'
|
||||
list="@{viewModel.businessTypeList}"
|
||||
title='@{"运单类型"}'
|
||||
type="@{PhoneDataLayoutType.SPINNER}"
|
||||
value="@={viewModel.businessType}" />
|
||||
|
||||
</com.lukouguoji.module_base.ui.weight.phone.PhoneFilterPanel>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</layout>
|
||||
|
||||
123
app/src/main/res/layout/activity_gnj_move_stash_photo.xml
Normal file
123
app/src/main/res/layout/activity_gnj_move_stash_photo.xml
Normal file
@@ -0,0 +1,123 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
国内进港移库「拍照上传」—— 5.5 寸手持端专属页面(无平板变体)
|
||||
|
||||
对应设计稿 11_进港移库/photo.html:
|
||||
· 白卡「运单照片上传」+ 图片预览网格(复用公共 ImageSelectNewViewHolder,末位加号槽位)
|
||||
· 底部两个按钮:拍照/上传(蓝) + 确认提交(绿)
|
||||
|
||||
提交走 DomImpMove/modify(pic/originalPic/picNumber 三字段规范)。
|
||||
-->
|
||||
<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.aerologic.page.gnj.move.stash.photo.GnjMoveStashPhotoViewModel" />
|
||||
</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="16dp">
|
||||
|
||||
<!-- 标题:运单照片上传(副行展示运单号) -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="运单照片上传"
|
||||
android:textColor="@color/phone_text_strong"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="@{viewModel.wbNo}"
|
||||
android:textColor="@color/phone_text_body"
|
||||
android:textSize="13sp"
|
||||
tools:text="78133363573" />
|
||||
|
||||
<!-- 图片预览网格(末位加号槽位,长按出删除角标) -->
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:overScrollMode="never"
|
||||
itemLayoutId="@{viewModel.itemLayoutId}"
|
||||
viewHolder="@{viewModel.itemViewHolder}"
|
||||
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
||||
app:spanCount="3"
|
||||
tools:itemCount="3" />
|
||||
|
||||
<!-- 底部按钮:拍照/上传(蓝) + 确认提交(绿) -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="44dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_phone_btn_primary"
|
||||
android:gravity="center"
|
||||
android:onClick="@{()-> viewModel.pickClick()}"
|
||||
android:text="拍照/上传"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_phone_btn_green"
|
||||
android:gravity="center"
|
||||
android:onClick="@{()-> viewModel.submitClick()}"
|
||||
android:text="确认提交"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</layout>
|
||||
@@ -1,6 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
操作日志详情(运单追踪)—— 手机版布局(5.5 寸手持端,最小宽度 < 600dp 时生效)
|
||||
|
||||
平板版为同名文件 layout-sw600dp/activity_log_detail.xml(横向步骤条 + 操作详情时间线),
|
||||
两者是同一布局的资源变体,DataBinding 因此生成同一个 ActivityLogDetailBinding 类。
|
||||
|
||||
变体之间必须满足:
|
||||
· DataBinding 变量完全一致:viewModel
|
||||
· 保留 Activity 引用的控件 id:ll_steps / rv_timeline
|
||||
|
||||
手机版按设计稿「运单追踪」呈现:
|
||||
· 顶卡:运单号 + 运单类型标签
|
||||
· 流转状态:竖排时间线(LogDetailActivity 手机分支 buildVerticalSteps 动态填充 ll_steps)
|
||||
· 平板的「操作详情」时间线列表在手机设计稿中不存在,rv_timeline 保留 id 但隐藏
|
||||
-->
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<data>
|
||||
|
||||
@@ -12,7 +28,7 @@
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/color_f2"
|
||||
android:background="@color/phone_page_bg"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include layout="@layout/title_tool_bar" />
|
||||
@@ -20,208 +36,99 @@
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true">
|
||||
android:fillViewport="true"
|
||||
android:overScrollMode="never">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="15dp">
|
||||
android:padding="12dp">
|
||||
|
||||
<!-- 运单信息 -->
|
||||
<!-- ==================== 运单卡片 ==================== -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:background="@drawable/bg_phone_card"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<!-- 标题区 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:background="@drawable/bg_white_radius_top_8"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingHorizontal="15dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="运单信息"
|
||||
android:textColor="#333333"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 分割线(贯穿卡片宽度) -->
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="#E7E7E7" />
|
||||
|
||||
<!-- 内容区 -->
|
||||
<!-- 运单号 + 运单类型标签 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_white_radius_bottom_8"
|
||||
android:orientation="vertical">
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="30dp"
|
||||
android:layout_marginEnd="15dp"
|
||||
android:layout_marginVertical="12dp"
|
||||
android:orientation="horizontal">
|
||||
android:layout_weight="1"
|
||||
android:text="@{viewModel.waybillNo}"
|
||||
android:textColor="@color/phone_text_title"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="78133358743" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="运单号:"
|
||||
android:textColor="#666666"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{viewModel.waybillNo}"
|
||||
android:textColor="#333333"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="运单类型:"
|
||||
android:textColor="#666666"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{viewModel.waybillType}"
|
||||
android:textColor="#333333"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="22dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:background="@drawable/bg_phone_tag_indigo"
|
||||
android:gravity="center"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:text="@{viewModel.waybillType}"
|
||||
android:textColor="@color/phone_tag_indigo_text"
|
||||
android:textSize="12sp"
|
||||
tools:text="国际出港" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginTop="14dp"
|
||||
android:layout_marginBottom="14dp"
|
||||
android:background="@color/phone_divider" />
|
||||
|
||||
<!-- 流转状态标题 -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="流转状态"
|
||||
android:textColor="@color/phone_text_title"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<!-- 竖排时间线(Activity 手机分支动态填充) -->
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_steps"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="14dp"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<!-- 平板的操作详情时间线,手机设计稿无此区块,保留 id 但隐藏 -->
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_timeline"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 流转状态 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
<!-- 触底提示 -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="15dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- 标题区 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:background="@drawable/bg_white_radius_top_8"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingHorizontal="15dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="流转状态"
|
||||
android:textColor="#333333"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 分割线 -->
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="#E7E7E7" />
|
||||
|
||||
<!-- 内容区 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_white_radius_bottom_8"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_steps"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="23dp"
|
||||
android:layout_marginEnd="15dp"
|
||||
android:layout_marginVertical="12dp"
|
||||
android:orientation="horizontal" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 操作详情 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="15dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- 标题区 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:background="@drawable/bg_white_radius_top_8"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingHorizontal="15dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="操作详情"
|
||||
android:textColor="#333333"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 分割线 -->
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="#E7E7E7" />
|
||||
|
||||
<!-- 内容区 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_white_radius_bottom_8"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_timeline"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:paddingStart="8dp"
|
||||
android:nestedScrollingEnabled="false"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:letterSpacing="0.3"
|
||||
android:text="查询信息已触底"
|
||||
android:textColor="@color/phone_text_hint"
|
||||
android:textSize="12sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
· ULD修改(Modify):编号只读,其余可编辑 + 底部保存
|
||||
· ULD详情(Details):全只读右对齐 + 顶栏右侧铅笔进入修改 + 额外展示最大装载容积/最大载重
|
||||
|
||||
「来源」「状态三态(占用)」为后端暂不支持的设计稿要求,
|
||||
已登记 documents/后端接口对接问题清单.xlsx,UI 先行、后端补齐后自动生效。
|
||||
字段与平板端一致:来源 source(空运/陆运)、入库时间 inStoreTime、所在港 nowPort;
|
||||
状态维持两态(0 可用 / 1 维修,后端不新增「占用」)。
|
||||
-->
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
@@ -119,11 +119,11 @@
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="22dp"
|
||||
android:background="@{viewModel.uldBean.status.empty ? null : (viewModel.uldBean.isStatusAvailable ? @drawable/bg_phone_tag_green : (viewModel.uldBean.isStatusOccupied ? @drawable/bg_phone_tag_orange : @drawable/bg_phone_tag_red_light))}"
|
||||
android:background="@{viewModel.uldBean.status.empty ? null : (viewModel.uldBean.isStatusAvailable ? @drawable/bg_phone_tag_green : @drawable/bg_phone_tag_red_light)}"
|
||||
android:gravity="center"
|
||||
android:paddingHorizontal="8dp"
|
||||
android:text='@{viewModel.uldBean.status.empty ? "请选择状态" : viewModel.uldBean.statusPhoneName}'
|
||||
android:textColor="@{viewModel.uldBean.status.empty ? @color/phone_text_hint : (viewModel.uldBean.isStatusAvailable ? @color/phone_tag_green_text : (viewModel.uldBean.isStatusOccupied ? @color/phone_tag_orange_text : @color/phone_danger_text))}"
|
||||
android:textColor="@{viewModel.uldBean.status.empty ? @color/phone_text_hint : (viewModel.uldBean.isStatusAvailable ? @color/phone_tag_green_text : @color/phone_danger_text)}"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<!-- 编辑态右箭头 -->
|
||||
@@ -160,17 +160,6 @@
|
||||
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.SELECT}"
|
||||
value="@={viewModel.uldBean.carrier}" />
|
||||
|
||||
<!-- 来源(后端字段暂不支持,已登记清单;提交后端忽略) -->
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
||||
hint='@{"请选择来源"}'
|
||||
list="@{viewModel.sourceEditList}"
|
||||
title='@{"来源"}'
|
||||
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.SELECT}"
|
||||
value="@={viewModel.uldBean.source}" />
|
||||
|
||||
<!-- 自重(kg) -->
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
|
||||
android:layout_width="match_parent"
|
||||
@@ -183,25 +172,31 @@
|
||||
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.INPUT}"
|
||||
value="@={viewModel.uldBean.uldWeight}" />
|
||||
|
||||
<!-- 最大装载容积(仅详情展示,与设计稿一致) -->
|
||||
<!-- 最大装载容积:新增/修改可编辑(与平板一致;saveUld 缺该字段后端 500,内网实测) -->
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
||||
hint='@{"请输入最大装载容积"}'
|
||||
numeric="@{true}"
|
||||
required="@{viewModel.pageType == DetailsPageType.Add}"
|
||||
title='@{"最大装载容积(m³)"}'
|
||||
type="@{PhoneFormRowType.TEXT}"
|
||||
value="@{viewModel.uldBean.maxVolume}"
|
||||
android:visibility="@{viewModel.pageType == DetailsPageType.Details ? View.VISIBLE : View.GONE}" />
|
||||
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.INPUT}"
|
||||
value="@={viewModel.uldBean.maxVolume}" />
|
||||
|
||||
<!-- 最大载重(仅详情展示,与设计稿一致) -->
|
||||
<!-- 最大载重:新增/修改可编辑(与平板一致;saveUld 缺该字段后端 500,内网实测) -->
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
||||
hint='@{"请输入最大载重"}'
|
||||
numeric="@{true}"
|
||||
required="@{viewModel.pageType == DetailsPageType.Add}"
|
||||
title='@{"最大载重(kg)"}'
|
||||
type="@{PhoneFormRowType.TEXT}"
|
||||
value="@{viewModel.uldBean.maxWeight}"
|
||||
android:visibility="@{viewModel.pageType == DetailsPageType.Details ? View.VISIBLE : View.GONE}" />
|
||||
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.INPUT}"
|
||||
value="@={viewModel.uldBean.maxWeight}" />
|
||||
|
||||
<!-- 进港航班号(绑 ifNo,语义待后端确认,已登记清单) -->
|
||||
<!-- 进港航班号(ifNo) -->
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -211,7 +206,7 @@
|
||||
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.INPUT}"
|
||||
value="@={viewModel.uldBean.ifNo}" />
|
||||
|
||||
<!-- 所在港(新增默认 HFE,由 ViewModel 手机开关预填) -->
|
||||
<!-- 所在港(nowPort,与平板端一致;新增默认 HFE,由 ViewModel 手机开关预填) -->
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -219,9 +214,20 @@
|
||||
hint='@{"请输入所在港"}'
|
||||
title='@{"所在港"}'
|
||||
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.INPUT}"
|
||||
value="@={viewModel.uldBean.airport}" />
|
||||
value="@={viewModel.uldBean.nowPort}" />
|
||||
|
||||
<!-- 入库时间(绑 checkInDate,筛选/格式语义待后端确认,已登记清单) -->
|
||||
<!-- 来源(source:空运/陆运,设计稿顺序位于所在港之后) -->
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
||||
hint='@{"请选择来源"}'
|
||||
list="@{viewModel.sourceEditList}"
|
||||
title='@{"来源"}'
|
||||
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.SELECT}"
|
||||
value="@={viewModel.uldBean.source}" />
|
||||
|
||||
<!-- 入库时间(inStoreTime,与平板端一致) -->
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -230,7 +236,7 @@
|
||||
required="@{viewModel.pageType == DetailsPageType.Add}"
|
||||
title='@{"入库时间"}'
|
||||
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.DATE}"
|
||||
value="@={viewModel.uldBean.checkInDate}" />
|
||||
value="@={viewModel.uldBean.inStoreTime}" />
|
||||
|
||||
<!-- 备注 -->
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
|
||||
|
||||
@@ -130,23 +130,15 @@
|
||||
setOnResetClick="@{(v)-> activity.resetFilter()}"
|
||||
title='@{"筛选条件"}'>
|
||||
|
||||
<!-- 入库时间(后端筛选入参暂不支持,已登记清单) -->
|
||||
<!-- 状态(后端入参 status,与平板端查询参数一致) -->
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
hint='@{"请输入入库时间"}'
|
||||
title='@{"入库时间"}'
|
||||
type="@{PhoneDataLayoutType.DATE}"
|
||||
value="@={viewModel.checkInDateFilter}" />
|
||||
|
||||
<!-- 进港航班号(后端筛选入参暂不支持,已登记清单) -->
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
hint='@{"请输入进港航班号"}'
|
||||
title='@{"进港航班号"}'
|
||||
type="@{PhoneDataLayoutType.INPUT}"
|
||||
value="@={viewModel.ifNoFilter}" />
|
||||
hint='@{"请选择状态"}'
|
||||
list="@{viewModel.statusPhoneFilterList}"
|
||||
title='@{"状态"}'
|
||||
type="@{PhoneDataLayoutType.SPINNER}"
|
||||
value="@={viewModel.status}" />
|
||||
|
||||
<!-- 所属航司(后端入参 uldSuffix,真实生效) -->
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayout
|
||||
@@ -158,16 +150,6 @@
|
||||
type="@{PhoneDataLayoutType.SPINNER}"
|
||||
value="@={viewModel.uldSuffix}" />
|
||||
|
||||
<!-- 来源(后端字段暂不支持,已登记清单) -->
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
hint='@{"请选择来源"}'
|
||||
list="@{viewModel.sourceList}"
|
||||
title='@{"来源"}'
|
||||
type="@{PhoneDataLayoutType.SPINNER}"
|
||||
value="@={viewModel.sourceFilter}" />
|
||||
|
||||
</com.lukouguoji.module_base.ui.weight.phone.PhoneFilterPanel>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
@@ -1,287 +1,227 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
国内进港移库 —— 列表项 5.5 寸手持端布局(平板变体见 layout-sw600dp/ 同名文件)
|
||||
|
||||
一套布局覆盖设计稿两种卡片形态,按 bean.isMoved 切换(载入时按端点打标):
|
||||
· 待移库:圆形勾选框 + 蓝色运单号 + 橙色「待移库」标签
|
||||
· 已移库:无勾选框 + 深色运单号 + 绿色对勾「已移库」
|
||||
长按卡片出「拍照」浮层(跳拍照上传页),点浮层空白处收起。
|
||||
-->
|
||||
<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="bean"
|
||||
type="com.lukouguoji.module_base.bean.MoveStashBean" />
|
||||
|
||||
<variable
|
||||
name="position"
|
||||
type="Integer" />
|
||||
|
||||
<variable
|
||||
name="activity"
|
||||
type="com.lukouguoji.aerologic.page.gnj.move.stash.list.GnjMoveStashListActivity" />
|
||||
</data>
|
||||
|
||||
<!-- 外层容器承载间距 -->
|
||||
<LinearLayout
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="15dp"
|
||||
android:layout_marginVertical="5dp"
|
||||
android:orientation="vertical">
|
||||
android:layout_marginHorizontal="12dp"
|
||||
android:layout_marginTop="12dp">
|
||||
|
||||
<!-- 侧滑布局 -->
|
||||
<com.mcxtzhang.swipemenulib.SwipeMenuLayout
|
||||
android:id="@+id/swipe_menu"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_phone_card"
|
||||
android:onLongClick="@{()-> activity.showCardActionPhone(bean)}"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<!-- 主列表项容器 -->
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/ll"
|
||||
<!-- ==================== 卡片头部:勾选框 + 运单号 + 状态 ==================== -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_item"
|
||||
android:orientation="horizontal"
|
||||
android:padding="10dp">
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<!-- 圆形勾选框(已移库的记录不可勾选,隐藏) -->
|
||||
<ImageView
|
||||
android:id="@+id/iv_icon"
|
||||
loadImage="@{bean.checked ? @drawable/img_plane_s : @drawable/img_plane}"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/img_plane" />
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:src="@drawable/ic_phone_check_round_unchecked"
|
||||
android:visibility="@{bean.isMoved ? View.GONE : View.VISIBLE}"
|
||||
loadImage="@{bean.checked.get() ? @drawable/ic_phone_check_round_checked : @drawable/ic_phone_check_round_unchecked}" />
|
||||
|
||||
<LinearLayout
|
||||
<!-- 运单号 -->
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
android:text="@{bean.wbNo}"
|
||||
android:textColor="@{bean.isMoved ? @color/phone_text_title : @color/phone_primary}"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<!-- 待移库:橙色状态标签 -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:background="@drawable/bg_phone_tag_orange"
|
||||
android:gravity="center"
|
||||
android:paddingHorizontal="8dp"
|
||||
android:text="待移库"
|
||||
android:textColor="@color/phone_tag_orange_text"
|
||||
android:textSize="11sp"
|
||||
android:visibility="@{bean.isMoved ? View.GONE : View.VISIBLE}" />
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.1"
|
||||
android:gravity="center_vertical">
|
||||
<!-- 已移库:对勾 + 状态文字 -->
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="@{bean.isMoved ? View.VISIBLE : View.GONE}">
|
||||
|
||||
<TextView
|
||||
completeSpace="@{4}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="运单号:" />
|
||||
<ImageView
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:src="@drawable/ic_phone_check_circle" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{bean.wbNo}"
|
||||
android:textColor="@color/colorPrimary"
|
||||
tools:text="789165431" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0.8"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
completeSpace="@{4}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="件数:" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text='@{bean.pc}' />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0.7"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
completeSpace="@{4}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="重量:" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{bean.weight}" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0.8"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
completeSpace="@{4}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="代理人:" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text='@{bean.agentCode}' />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.1"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
completeSpace="@{5}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="运单类型:" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text='@{bean.awbType}' />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="match_parent"
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp">
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.1"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
completeSpace="@{4}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="航班:" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{bean.flight}" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0.8"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
completeSpace="@{4}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="始发港:" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{bean.origin}" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0.8"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
completeSpace="@{4}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="起始站:" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{bean.dep}" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0.8"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
completeSpace="@{4}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="目的港:" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{bean.dest}" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.1"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
completeSpace="@{5}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="品名:" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{bean.goods}" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
android:layout_marginStart="4dp"
|
||||
android:text="已移库"
|
||||
android:textColor="@color/phone_text_title"
|
||||
android:textSize="13sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 右侧箭头 -->
|
||||
<ImageView
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:src="@drawable/img_pda_right" />
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<!-- 侧滑菜单区域 -->
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
<!-- ==================== 航班信息行 ==================== -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<!-- 编辑按钮 -->
|
||||
<ImageView
|
||||
android:layout_width="14dp"
|
||||
android:layout_height="14dp"
|
||||
android:src="@drawable/ic_phone_airplane" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btn_edit"
|
||||
style="@style/tv_item_action"
|
||||
android:background="@color/colorPrimary"
|
||||
android:text="编辑" />
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_weight="1"
|
||||
android:text='@{"航班信息:" + bean.orDash(bean.flight)}'
|
||||
android:textColor="@color/phone_text_body"
|
||||
android:textSize="13sp"
|
||||
tools:text="航班信息:20260709/MU2311" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
</LinearLayout>
|
||||
|
||||
</com.mcxtzhang.swipemenulib.SwipeMenuLayout>
|
||||
<!-- ==================== 统计框:特码 / 件数 / 重量 ==================== -->
|
||||
<com.lukouguoji.module_base.ui.weight.phone.PhoneStatBox
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
label1='@{"特码"}'
|
||||
label2='@{"件数"}'
|
||||
label3='@{"重量"}'
|
||||
value1="@{bean.orDash(bean.spCode)}"
|
||||
value2='@{bean.orDash(bean.pc) + "件"}'
|
||||
value3='@{bean.orDash(bean.weight) + "kg"}' />
|
||||
|
||||
</LinearLayout>
|
||||
<!-- ==================== 出运路径 ==================== -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="14dp"
|
||||
android:layout_height="14dp"
|
||||
android:src="@drawable/ic_phone_location" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_weight="1"
|
||||
android:text='@{"出运路径:" + bean.orDash(bean.range)}'
|
||||
android:textColor="@color/phone_text_body"
|
||||
android:textSize="13sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- ==================== 查看详情 ==================== -->
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="@color/phone_stat_bg" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_detail"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical|end"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="12dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="查看详情"
|
||||
android:textColor="@color/phone_primary"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:src="@drawable/ic_phone_chevron_right" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- ==================== 长按操作浮层:拍照 ==================== -->
|
||||
<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}">
|
||||
|
||||
<TextView
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/bg_phone_fab_purple"
|
||||
android:gravity="center"
|
||||
android:onClick="@{()-> activity.openPhoto(bean)}"
|
||||
android:text="拍照"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</layout>
|
||||
|
||||
@@ -11,8 +11,7 @@
|
||||
· 平板独有 id(tv_modify / tv_delete / iv_icon)与手机独有 id(iv_check)
|
||||
在 Binding 基类中自动为 @Nullable,ViewHolder 判空使用
|
||||
|
||||
状态标签三色(设计稿):可用=浅绿 / 占用=浅橙 / 维修=浅红。
|
||||
后端当前仅两态(0 可用 / 1 维修),「占用」为后端扩展枚举后的预留,见 ULDBean.statusPhoneName。
|
||||
状态标签:可用=浅绿 / 维修=浅红(后端枚举维持两态 0/1,不含「占用」),见 ULDBean.statusPhoneName。
|
||||
「来源」字段后端暂无(恒空显示 "-"),已登记 documents/后端接口对接问题清单.xlsx。
|
||||
-->
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
@@ -61,16 +60,16 @@
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<!-- 状态标签:可用(绿) / 占用(橙) / 维修(红,浅红底红字) -->
|
||||
<!-- 状态标签:可用(绿) / 维修(红,浅红底红字) -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:background="@{bean.isStatusAvailable ? @drawable/bg_phone_tag_green : (bean.isStatusOccupied ? @drawable/bg_phone_tag_orange : @drawable/bg_phone_tag_red_light)}"
|
||||
android:background="@{bean.isStatusAvailable ? @drawable/bg_phone_tag_green : @drawable/bg_phone_tag_red_light}"
|
||||
android:gravity="center"
|
||||
android:paddingHorizontal="8dp"
|
||||
android:text="@{bean.statusPhoneName}"
|
||||
android:textColor="@{bean.isStatusAvailable ? @color/phone_tag_green_text : (bean.isStatusOccupied ? @color/phone_tag_orange_text : @color/phone_danger_text)}"
|
||||
android:textColor="@{bean.isStatusAvailable ? @color/phone_tag_green_text : @color/phone_danger_text}"
|
||||
android:textSize="11sp" />
|
||||
|
||||
<ImageView
|
||||
@@ -137,7 +136,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_weight="1"
|
||||
android:text='@{"入库时间:" + (bean.checkInDate.empty ? "-" : bean.checkInDate)}'
|
||||
android:text='@{"入库时间:" + (bean.inStoreTime.empty ? "-" : bean.inStoreTime)}'
|
||||
android:textColor="@color/phone_text_body"
|
||||
android:textSize="13sp" />
|
||||
|
||||
|
||||
Binary file not shown.
@@ -22,9 +22,16 @@ data class GjcCheckInRecord(
|
||||
var weight: Double = 0.0, // 运抵重量
|
||||
var volume: Double = 0.0, // 运抵体积
|
||||
var whId: Long = 0, // GJC_WAREHOUSE.ID
|
||||
var carWeight: String = "" // 托盘自重
|
||||
var carWeight: String = "", // 托盘车重(平板托盘车号反查值)
|
||||
var trayNumber: Int = 0, // 托盘数量
|
||||
var trayTotalWeight: Double = 0.0, // 托盘重量(托盘数量 × 托盘自重,与平板端一致)
|
||||
var opUserName: String = "" // 计重人姓名(opId 关联查询)
|
||||
) : BaseObservable() {
|
||||
|
||||
/** 计重人:优先姓名,为空回退操作员编码 */
|
||||
val opUserDisplay: String
|
||||
get() = opUserName.ifEmpty { opId }
|
||||
|
||||
// 数据变化回调
|
||||
var onDataChanged: (() -> Unit)? = null
|
||||
|
||||
@@ -54,14 +61,23 @@ data class GjcCheckInRecord(
|
||||
}
|
||||
}
|
||||
|
||||
// 托盘自重的字符串表示(用于双向绑定,5.5寸手机版「修改记录」覆层)
|
||||
/**
|
||||
* 托盘重量输入原文(手机「修改记录」覆层)。保留原文而非由 Double 反推:
|
||||
* 输入 "1" 时若 getter 返回 "1.0",输入框会被重设、光标回到开头,再输 "8" 就成了 "81"(实机踩过)。
|
||||
* transient:不参与 Gson 提交序列化。
|
||||
*/
|
||||
@Transient
|
||||
private var trayTotalWeightInput: String? = null
|
||||
|
||||
// 托盘重量的字符串表示(用于双向绑定,5.5寸手机版「修改记录」覆层)
|
||||
@get:Bindable
|
||||
var carWeightStr: String
|
||||
get() = carWeight
|
||||
var trayTotalWeightStr: String
|
||||
get() = trayTotalWeightInput ?: if (trayTotalWeight == 0.0) "" else trayTotalWeight.toString()
|
||||
set(value) {
|
||||
if (carWeight != value) {
|
||||
carWeight = value
|
||||
notifyPropertyChanged(BR.carWeightStr)
|
||||
if (trayTotalWeightStr != value) {
|
||||
trayTotalWeightInput = value
|
||||
trayTotalWeight = value.toDoubleOrNull() ?: 0.0
|
||||
notifyPropertyChanged(BR.trayTotalWeightStr)
|
||||
onDataChanged?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,8 +76,8 @@ data class GjcMaWb(
|
||||
var carNumber: String? = null, // 车牌号
|
||||
var passageWay: String? = null, // 通道号
|
||||
var passageWayId: String? = null,
|
||||
var palletNumber: String? = null, // 托盘数量(5.5寸手机版开始计重页,后端暂无该入参,见接口问题清单)
|
||||
var carWeight: String? = null, // 托盘自重(5.5寸手机版手输,后端暂无该入参,见接口问题清单)
|
||||
var trayNumber: Int? = null, // 托盘数量(splitCheckIn / completeCheckIn 入参,与平板端一致)
|
||||
var trayTotalWeight: Double? = null, // 托盘重量 = 托盘数量 × 托盘自重
|
||||
|
||||
// ==================== 状态信息 ====================
|
||||
var checkIn: String? = null, // 收运状态。0:待收运,1:已收运,2:收运中
|
||||
@@ -131,13 +131,6 @@ data class GjcMaWb(
|
||||
get() = checked.get()
|
||||
set(value) = checked.set(value)
|
||||
|
||||
/**
|
||||
* 5.5寸手机版:是否处于「待运抵」Tab(申报状态为空)。
|
||||
* 接口无按申报状态区分的查询参数,Tab 由客户端对已加载数据拆分。
|
||||
*/
|
||||
val isPending: Boolean
|
||||
get() = declareStatus.isNullOrEmpty()
|
||||
|
||||
/**
|
||||
* 5.5寸手机版:申报状态三色标签的着色分类(01=绿/W=靛蓝/其余非空=琥珀)。
|
||||
*/
|
||||
@@ -148,6 +141,34 @@ data class GjcMaWb(
|
||||
else -> if (declareStatus.isNullOrEmpty()) "" else "amber"
|
||||
}
|
||||
|
||||
/**
|
||||
* 5.5寸手机版-出港查询:卡片状态标签。
|
||||
* 已离港 = 航班关闭时间(fclose)非空;已入库 = 入库时间(opDate)非空;都为空 = 未入库(灰)。
|
||||
* 接口无独立状态出参,此判定为前端推断(与卡片「入库时间/离港时间」两列同源)。
|
||||
*/
|
||||
val isQueryDeparted: Boolean
|
||||
get() = !fclose.isNullOrEmpty()
|
||||
|
||||
val isQueryStored: Boolean
|
||||
get() = !opDate.isNullOrEmpty()
|
||||
|
||||
/** 5.5寸手机版:空值统一占位 "--"(空串与 null 都兜底,布局绑定用) */
|
||||
fun orDash(value: String?): String = if (value.isNullOrEmpty()) "--" else value
|
||||
|
||||
/**
|
||||
* 5.5寸手机版:代理人展示值(名称优先,空则回退代码)。
|
||||
* 不能在 XML 里用 `??` 兜底——转换器会把 JSON null 归一成空串,`??` 只判 null 不判空串。
|
||||
*/
|
||||
val agentDisplay: String?
|
||||
get() = if (agentName.isNullOrEmpty()) agentCode else agentName
|
||||
|
||||
/**
|
||||
* 5.5寸手机版-出港仓库:卡片状态标签(已清仓=绿 / 未清仓=橙,clearNormal 为空视作未清仓)。
|
||||
* 已清仓时卡片「清仓」按钮置灰不可点。
|
||||
*/
|
||||
val isCleared: Boolean
|
||||
get() = clearNormal == "1"
|
||||
|
||||
// ==================== 状态转换扩展属性 ====================
|
||||
/**
|
||||
* 计重状态中文
|
||||
|
||||
@@ -44,6 +44,9 @@ data class GjcMove(
|
||||
var likeNo: String = "", // 部分运单号no(模糊查询)
|
||||
|
||||
var range: String = "",
|
||||
var flight: String = "", // 航班信息(航班日期/航班号,如 20260924/MU2222)
|
||||
var businessName: String = "", // 业务类型名称(中)
|
||||
var opUserName: String = "", // 操作人(移库人)姓名
|
||||
|
||||
// UI扩展字段 - 使用ObservableBoolean实现自动UI更新
|
||||
val checked: ObservableBoolean = ObservableBoolean(false)
|
||||
@@ -67,6 +70,14 @@ data class GjcMove(
|
||||
val goodsName: String
|
||||
get() = goodsCn.ifEmpty { goods }
|
||||
|
||||
/** 业务类型:优先中文名称,为空回退编码 */
|
||||
val businessDisplay: String
|
||||
get() = businessName.ifEmpty { businessType }
|
||||
|
||||
/** 移库人:优先姓名,为空回退操作人ID */
|
||||
val opUserDisplay: String
|
||||
get() = opUserName.ifEmpty { opId }
|
||||
|
||||
/**
|
||||
* 详情页字段统一空值占位。
|
||||
* 接口对 businessType / opdate / opId 等字段常返回 null,
|
||||
|
||||
@@ -73,6 +73,7 @@ class GjcWeighingRecordBean : Serializable {
|
||||
var paperTime: String = "" // 单据时间
|
||||
|
||||
var userName: String = "" // 收运人
|
||||
var passageWay: String = "" // 通道号(计重时选定的通道号名称)
|
||||
var userId: String = "" // 收运人ID
|
||||
|
||||
var remark: String = "" // 备注
|
||||
|
||||
@@ -10,4 +10,6 @@ class GjcWeighingStatisticsBean {
|
||||
var totalPc: Long = 0 // 总件数
|
||||
var totalWeight: Double = 0.0 // 总重量
|
||||
var cargoWeight: Double = 0.0 // 总货重
|
||||
var waitCheckInNumber: Int = 0 // 待计重票数(IntExpCheckIn/pageQueryTotal)
|
||||
var checkingNumber: Int = 0 // 计重中票数(IntExpCheckIn/pageQueryTotal)
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ class IntImpPickUpDLVBean : Serializable {
|
||||
var dlvId: String = ""
|
||||
var dlvIdType: String = ""
|
||||
var dlvName: String = ""
|
||||
var refUserName: String = "" // 出库人姓名(refId 关联查询)
|
||||
var dlvPhone: String = ""
|
||||
var locFlag: String = ""
|
||||
var origin: String = ""
|
||||
@@ -74,4 +75,11 @@ class IntImpPickUpDLVBean : Serializable {
|
||||
var isSelected: Boolean
|
||||
get() = checked.get()
|
||||
set(value) = checked.set(value)
|
||||
|
||||
/**
|
||||
* 5.5寸手机版:是否已出库(出库时间非空)。
|
||||
* 卡片按此切两种形态:待出库(勾选框+橙标签+库位行)/已出库(绿标签+出库人行)。
|
||||
*/
|
||||
val isPickedUp: Boolean
|
||||
get() = dlvTime.isNotEmpty()
|
||||
}
|
||||
|
||||
@@ -54,4 +54,26 @@ data class IntImpQueryBean(
|
||||
// ==================== 其他 ====================
|
||||
var remark: String? = null, // 备注
|
||||
var activeId: Long? = null // 有效值
|
||||
)
|
||||
) {
|
||||
|
||||
/**
|
||||
* 5.5寸手机版-进港查询:卡片状态标签。
|
||||
* 已出库 = 出库时间(dlvTime)非空;已入库 = 入库时间(inDate)非空;都为空 = 未入库(灰)。
|
||||
* 接口无独立状态出参,此判定为前端推断(与平板列表「入库时间/出库时间」两列同源)。
|
||||
*/
|
||||
val isQueryOutbound: Boolean
|
||||
get() = !dlvTime.isNullOrEmpty()
|
||||
|
||||
val isQueryStored: Boolean
|
||||
get() = !inDate.isNullOrEmpty()
|
||||
|
||||
/** 5.5寸手机版:空值统一占位 "--"(空串与 null 都兜底,布局绑定用) */
|
||||
fun orDash(value: String?): String = if (value.isNullOrEmpty()) "--" else value
|
||||
|
||||
/**
|
||||
* 5.5寸手机版:代理人展示值(名称优先,空则回退代码)。
|
||||
* 不能在 XML 里用 `??` 兜底——转换器会把 JSON null 归一成空串,`??` 只判 null 不判空串。
|
||||
*/
|
||||
val agentDisplay: String?
|
||||
get() = if (agentName.isNullOrEmpty()) agentCode else agentName
|
||||
}
|
||||
|
||||
@@ -8,5 +8,15 @@ data class ManifestTotalDto(
|
||||
var wbNumber: Int = 0, // 运单票数/总票数
|
||||
var totalPc: Long = 0, // 总件数
|
||||
var totalWeight: Double = 0.0, // 总重量
|
||||
var cargoWeight: Double = 0.0 // 总货重
|
||||
var cargoWeight: Double = 0.0, // 总货重
|
||||
|
||||
// ===== 后端统一统计 DTO 的分项计数(2026-09 后端补齐,按接口各取所需) =====
|
||||
var flightNumber: Int = 0, // 航班数
|
||||
var uldNumber: Int = 0, // 板箱数(出库交接 Tab 角标)
|
||||
var storedNumber: Int = 0, // 已入库票数(出港/进港查询)
|
||||
var departedNumber: Int = 0, // 已离港(出港)/ 已出库(进港)票数
|
||||
var notClearNumber: Int = 0, // 未清仓票数(出港/进港仓库)
|
||||
var clearNumber: Int = 0, // 已清仓票数(出港/进港仓库)
|
||||
var waitCheckInNumber: Int = 0, // 待计重票数(出港计重)
|
||||
var checkingNumber: Int = 0 // 计重中票数(出港计重)
|
||||
)
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.lukouguoji.module_base.interfaces.ICheck
|
||||
class MoveStashBean : ICheck {
|
||||
var activeId: String = "" // null
|
||||
var agentCode: String = "" // HFEXB
|
||||
var agentName: String = "" // 代理人名称(search 出参有定义)
|
||||
var awbType: String = "" // 国际进港(国内中转)
|
||||
var businessType: String = "" // null
|
||||
var by1: String = "" // null
|
||||
@@ -26,7 +27,9 @@ class MoveStashBean : ICheck {
|
||||
var flight: String = "" // 20240711/MU7766
|
||||
var fno: String = "" // MU7766
|
||||
var goods: String = "" // 国际货
|
||||
var mawbId: String = "" // 996422
|
||||
var mawbId: String = "" // 996422(searchMoved 出参不含此字段)
|
||||
var moveId: String = "" // CIII260930141150(已移库,movedDetail 入参)
|
||||
var opUserName: String = "" // 移库人姓名(searchMoved / movedDetail 出参)
|
||||
var no: String = "" // 44445074
|
||||
var opDate: String = "" // null
|
||||
var opId: String = "" // null
|
||||
@@ -49,4 +52,23 @@ class MoveStashBean : ICheck {
|
||||
override fun getCheckObservable(): ObservableBoolean {
|
||||
return checked
|
||||
}
|
||||
|
||||
// ========== 5.5 寸手持端展示辅助字段(仅前端使用,不参与提交) ==========
|
||||
|
||||
/** 是否已移库:由列表加载端点决定(search=待移库 / searchMoved=已移库),载入时打标 */
|
||||
var isMoved: Boolean = false
|
||||
|
||||
/** 卡片长按「拍照」操作浮层显隐(仅 UI 状态) */
|
||||
val actionMenuVisible = ObservableBoolean(false)
|
||||
|
||||
/** 代理显示:网络层会把 null 归一成空串,须 isNullOrEmpty 双兜底(沿用进港/出港查询口径) */
|
||||
val agentDisplay: String
|
||||
get() = if (agentName.isNotEmpty()) agentName else agentCode
|
||||
|
||||
/** 移库人:优先姓名,为空回退操作人 ID */
|
||||
val opUserDisplay: String
|
||||
get() = opUserName.ifEmpty { opId }
|
||||
|
||||
/** 详情页/卡片字段统一空值占位 */
|
||||
fun orDash(value: String?): String = if (value.isNullOrEmpty()) "-" else value
|
||||
}
|
||||
@@ -19,18 +19,21 @@ data class ULDBean(
|
||||
var status: String = "",
|
||||
// 备注
|
||||
var remark: String = "",
|
||||
// ========== 以下字段接口出参已有(api-doc /eqm/uld/pageQuery),此前 Bean 未解析 ==========
|
||||
// 进港航班号(语义待后端确认,见 documents/后端接口对接问题清单.xlsx)
|
||||
// ========== 以下字段接口出参已有(api-doc /eqm/uld/pageQuery) ==========
|
||||
// 进港航班号
|
||||
var ifNo: String = "",
|
||||
// 出港航班号
|
||||
var efNo: String = "",
|
||||
// 入库时间
|
||||
var checkInDate: String = "",
|
||||
// 出库时间
|
||||
var checkOutDate: String = "",
|
||||
// ========== 后端暂无对应字段,前端按设计稿预留(提交后端忽略,无副作用) ==========
|
||||
// 来源:空运 / 陆运(后端字段需求已登记清单)
|
||||
// 来源(空运、陆运)
|
||||
var source: String = "",
|
||||
// 入库时间 yyyy-MM-dd HH:mm:ss(后端确认「入库时间」取 inStoreTime,与平板端一致)
|
||||
var inStoreTime: String = "",
|
||||
// 所在港
|
||||
var nowPort: String = "",
|
||||
// 位置信息
|
||||
var nowPosition: String = "",
|
||||
){
|
||||
val checked = ObservableBoolean(false)
|
||||
|
||||
@@ -40,22 +43,18 @@ data class ULDBean(
|
||||
else -> status
|
||||
}
|
||||
|
||||
// ========== 手机版(5.5 寸手持端)三态状态展示 ==========
|
||||
// 设计稿状态为 可用(绿)/占用(橙)/维修(红) 三态;后端当前仅两态(0/1),
|
||||
// 按语义映射 0→可用、1→维修,"2"→占用为后端扩展枚举后的预留(需求已登记清单)。
|
||||
// ========== 手机版(5.5 寸手持端)状态展示 ==========
|
||||
// 后端确认状态枚举维持两态(0 正常 / 1 故障),不新增「占用」;
|
||||
// 手机版按设计稿文案映射 0→可用(绿)、1→维修(红)。
|
||||
|
||||
/** 手机版状态文案 */
|
||||
val statusPhoneName: String
|
||||
get() = when (status) {
|
||||
"0" -> "可用"
|
||||
"1" -> "维修"
|
||||
"2" -> "占用"
|
||||
else -> statusName()
|
||||
}
|
||||
|
||||
/** 可用(绿色标签) */
|
||||
val isStatusAvailable: Boolean get() = status == "0"
|
||||
|
||||
/** 占用(橙色标签,后端扩展枚举后的预留) */
|
||||
val isStatusOccupied: Boolean get() = status == "2"
|
||||
}
|
||||
@@ -272,6 +272,8 @@ interface Constant {
|
||||
const val IntImpTally = "AppIntImpTally" //理货报告
|
||||
const val IntImpPickUpRecord = "AppIntImpPickUpRecord" //提取记录
|
||||
const val IntImpPickUpDLV = "AppIntImpPickUpDLV" //提取出库
|
||||
// 进港移库:后端暂无该模块与权限串(2026-07-31 api-doc 核对),按 AppIntImp* 命名约定预定义,
|
||||
// 权限串下发前手机首页菜单不会显示该入口(已登记后端接口对接问题清单)
|
||||
const val IntImpAccidentVisa = "AppIntImpAccidentVisa" //事故签证
|
||||
const val GjjManifestListActivity = "AppIntExpManifest" //舱单
|
||||
const val GjjTallyListActivity = "AppIntExpTally" //理货
|
||||
|
||||
@@ -1766,6 +1766,12 @@ interface Api {
|
||||
@POST("DomImpMove/search")
|
||||
suspend fun getGnjMoveStashList(@Body data: RequestBody): BaseListBean<MoveStashBean>
|
||||
|
||||
/**
|
||||
* 获取-国内进港移库-已移库列表(移库完成分页搜索,5.5 寸手机端「已移库」Tab)
|
||||
*/
|
||||
@POST("DomImpMove/searchMoved")
|
||||
suspend fun getGnjMoveStashMovedList(@Body data: RequestBody): BaseListBean<MoveStashBean>
|
||||
|
||||
/**
|
||||
* 获取-国内进港移库-列表--运单列表
|
||||
*/
|
||||
@@ -1790,6 +1796,13 @@ interface Api {
|
||||
@GET("DomImpMove/detail")
|
||||
suspend fun getGnjMoveStashDetail(@Query("mawbId") mawbId: String): BaseResultBean<GnjYiKuBean>
|
||||
|
||||
/**
|
||||
* 国内进港移库-移库完成详情(已移库运单无 mawbId,按 moveId 查,含 pic 三字段与移库人)
|
||||
* 接口路径: /DomImpMove/movedDetail
|
||||
*/
|
||||
@GET("DomImpMove/movedDetail")
|
||||
suspend fun getGnjMoveStashMovedDetail(@Query("moveId") moveId: String): BaseResultBean<GnjYiKuBean>
|
||||
|
||||
/**
|
||||
* 编辑-国内进港移库(新接口)
|
||||
*/
|
||||
@@ -2085,6 +2098,13 @@ interface Api {
|
||||
@POST("eqm/uld/deleteUld")
|
||||
suspend fun deleteUld(@Query("uld") uld: String): BaseResultBean<Any>
|
||||
|
||||
/**
|
||||
* 批量删除-ULD-信息(请求体为 ULD 编号字符串数组)
|
||||
* 接口路径: /eqm/uld/deleteUldBatch
|
||||
*/
|
||||
@POST("eqm/uld/deleteUldBatch")
|
||||
suspend fun deleteUldBatch(@Body data: RequestBody): BaseResultBean<Any>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// 冷库登记
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -104,6 +104,7 @@ object ARouterConstants {
|
||||
|
||||
// 国内进港移库(新版本)
|
||||
const val ACTIVITY_URL_GNJ_YIKU_LIST = "/gnj/GnjYiKuListActivity" //国内进港 移库列表
|
||||
const val ACTIVITY_URL_GNJ_MOVE_STASH_LIST = "/app/GnjMoveStashListActivity" //国内进港 移库(首页菜单实际跳转页,双形态)
|
||||
const val ACTIVITY_URL_GNJ_YIKU_DETAILS = "/gnj/GnjYiKuDetailsActivity" //国内进港 移库详情
|
||||
const val ACTIVITY_URL_GNJ_YIKU_EDIT = "/gnj/GnjYiKuEditActivity" //国内进港 移库编辑
|
||||
const val ACTIVITY_URL_GNJ_YIKU_HANDOVER = "/gnj/GnjYiKuHandoverActivity" //国内进港 移交编辑/详情
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.lukouguoji.module_base.ui.weight.phone
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Parcelable
|
||||
import android.util.AttributeSet
|
||||
import android.util.SparseArray
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
@@ -42,6 +44,18 @@ class PhoneFilterPanel @JvmOverloads constructor(
|
||||
defStyleAttr: Int = 0
|
||||
) : FrameLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
/**
|
||||
* 同一页面可能出现多个含内部 id 的手机版复合组件,系统按 id 保存/恢复视图状态会跨实例串档。
|
||||
* 这里只保存/恢复自身状态、不下发给子控件;筛选值由 ViewModel + DataBinding 持有,无需视图级恢复。
|
||||
*/
|
||||
override fun dispatchSaveInstanceState(container: SparseArray<Parcelable>) {
|
||||
dispatchFreezeSelfOnly(container)
|
||||
}
|
||||
|
||||
override fun dispatchRestoreInstanceState(container: SparseArray<Parcelable>) {
|
||||
dispatchThawSelfOnly(container)
|
||||
}
|
||||
|
||||
val llPanel: LinearLayout
|
||||
val llContent: LinearLayout
|
||||
val tvTitle: TextView
|
||||
|
||||
@@ -56,13 +56,25 @@ class PhoneKvItem @JvmOverloads constructor(
|
||||
applyStyle()
|
||||
}
|
||||
|
||||
/** 高亮标签配色:"orange"(默认,如库位)/ "green"(如海关放行正常态) */
|
||||
var tagColor: String = "orange"
|
||||
set(v) {
|
||||
field = v
|
||||
applyStyle()
|
||||
}
|
||||
|
||||
/**
|
||||
* 空值不套高亮标签底 —— 否则占位符 "-" 会显示成一个孤零零的橙色小方块。
|
||||
* 空值不套高亮标签底 —— 否则占位符 "-"/"--" 会显示成一个孤零零的色块。
|
||||
*/
|
||||
private fun applyStyle() {
|
||||
if (tag && value.isNotEmpty()) {
|
||||
tvValue.setBackgroundResource(R.drawable.bg_phone_value_orange)
|
||||
tvValue.setTextColor(ContextCompat.getColor(context, R.color.phone_orange_text))
|
||||
if (tag && value.isNotEmpty() && value != "-" && value != "--") {
|
||||
if (tagColor == "green") {
|
||||
tvValue.setBackgroundResource(R.drawable.bg_phone_tag_green)
|
||||
tvValue.setTextColor(ContextCompat.getColor(context, R.color.phone_tag_green_text))
|
||||
} else {
|
||||
tvValue.setBackgroundResource(R.drawable.bg_phone_value_orange)
|
||||
tvValue.setTextColor(ContextCompat.getColor(context, R.color.phone_orange_text))
|
||||
}
|
||||
tvValue.setTypeface(tvValue.typeface, android.graphics.Typeface.BOLD)
|
||||
val padH = (4 * resources.displayMetrics.density).toInt()
|
||||
tvValue.setPadding(padH, 0, padH, 0)
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.lukouguoji.module_base.ui.weight.phone
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Parcelable
|
||||
import android.util.AttributeSet
|
||||
import android.util.SparseArray
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
@@ -37,6 +39,18 @@ class PhoneStatusTab @JvmOverloads constructor(
|
||||
defStyleAttr: Int = 0
|
||||
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
/**
|
||||
* 同一页面可能出现多个含内部 id 的手机版复合组件,系统按 id 保存/恢复视图状态会跨实例串档。
|
||||
* 这里只保存/恢复自身状态、不下发给子控件;选中值由 ViewModel + DataBinding 持有,无需视图级恢复。
|
||||
*/
|
||||
override fun dispatchSaveInstanceState(container: SparseArray<Parcelable>) {
|
||||
dispatchFreezeSelfOnly(container)
|
||||
}
|
||||
|
||||
override fun dispatchRestoreInstanceState(container: SparseArray<Parcelable>) {
|
||||
dispatchThawSelfOnly(container)
|
||||
}
|
||||
|
||||
/** 双向绑定回调 */
|
||||
var onChangeListener: InverseBindingListener? = null
|
||||
|
||||
|
||||
@@ -219,10 +219,17 @@ fun setPhoneStatBoxAttrs(
|
||||
// PhoneKvItem
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@BindingAdapter("title", "value", "tag", requireAll = false)
|
||||
fun setPhoneKvItemAttrs(item: PhoneKvItem, title: String?, value: String?, tag: Boolean?) {
|
||||
@BindingAdapter("title", "value", "tag", "tagColor", requireAll = false)
|
||||
fun setPhoneKvItemAttrs(
|
||||
item: PhoneKvItem,
|
||||
title: String?,
|
||||
value: String?,
|
||||
tag: Boolean?,
|
||||
tagColor: String?
|
||||
) {
|
||||
title?.let { item.title = it }
|
||||
// tag 需先于 value 生效,确保样式切换后再填内容
|
||||
// tag/tagColor 需先于 value 生效,确保样式切换后再填内容
|
||||
tagColor?.let { item.tagColor = it }
|
||||
tag?.let { item.tag = it }
|
||||
item.value = value.orEmpty()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 手机版禁用态操作按钮:灰底 + 10dp 圆角(出港仓库卡片「清仓」已清仓时置灰) -->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/phone_tag_gray_bg" />
|
||||
<corners android:radius="10dp" />
|
||||
</shape>
|
||||
16
module_base/src/main/res/drawable/bg_phone_btn_green.xml
Normal file
16
module_base/src/main/res/drawable/bg_phone_btn_green.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 手机版绿色操作按钮:完成态绿实底 + 10dp 圆角(进港移库-拍照上传「确认提交」) -->
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="#0E9F6E" />
|
||||
<corners android:radius="10dp" />
|
||||
</shape>
|
||||
</item>
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/phone_green" />
|
||||
<corners android:radius="10dp" />
|
||||
</shape>
|
||||
</item>
|
||||
</selector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 手机版详情卡片表头:橙色底 + 顶部 12dp 圆角(进港移库-异常照片卡片) -->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/phone_amber" />
|
||||
<corners
|
||||
android:topLeftRadius="12dp"
|
||||
android:topRightRadius="12dp" />
|
||||
</shape>
|
||||
6
module_base/src/main/res/drawable/bg_phone_dot_blue.xml
Normal file
6
module_base/src/main/res/drawable/bg_phone_dot_blue.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 手机版状态圆点:主色蓝(出港查询卡片运单号前的指示点) -->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="@color/phone_primary" />
|
||||
</shape>
|
||||
6
module_base/src/main/res/drawable/bg_phone_dot_gray.xml
Normal file
6
module_base/src/main/res/drawable/bg_phone_dot_gray.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 手机版状态圆点:灰色(运单追踪时间线未到达节点) -->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="@color/phone_text_hint" />
|
||||
</shape>
|
||||
12
module_base/src/main/res/drawable/bg_phone_photo_add.xml
Normal file
12
module_base/src/main/res/drawable/bg_phone_photo_add.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 手机版照片加号槽位:灰色虚线边框 + 8dp 圆角(进港移库-异常照片) -->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@android:color/transparent" />
|
||||
<corners android:radius="8dp" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/phone_divider"
|
||||
android:dashGap="4dp"
|
||||
android:dashWidth="4dp" />
|
||||
</shape>
|
||||
11
module_base/src/main/res/drawable/ic_phone_package.xml
Normal file
11
module_base/src/main/res/drawable/ic_phone_package.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 手机版件数图标(MDI package-variant-closed),默认灰色,可 tint -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#9CA3AF"
|
||||
android:pathData="M21,16.5C21,16.88 20.79,17.21 20.47,17.38L12.57,21.82C12.41,21.94 12.21,22 12,22C11.79,22 11.59,21.94 11.43,21.82L3.53,17.38C3.21,17.21 3,16.88 3,16.5V7.5C3,7.12 3.21,6.79 3.53,6.62L11.43,2.18C11.59,2.06 11.79,2 12,2C12.21,2 12.41,2.06 12.57,2.18L20.47,6.62C20.79,6.79 21,7.12 21,7.5V16.5M12,4.15L10.11,5.22L16,8.61L17.96,7.5L12,4.15M6.04,7.5L12,10.85L13.96,9.75L8.08,6.35L6.04,7.5M5,15.91L11,19.29V12.58L5,9.21V15.91M19,15.91V9.21L13,12.58V19.29L19,15.91Z" />
|
||||
</vector>
|
||||
11
module_base/src/main/res/drawable/ic_phone_tag.xml
Normal file
11
module_base/src/main/res/drawable/ic_phone_tag.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 手机版特码/标签图标(MDI tag-outline),默认灰色,可 tint -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#9CA3AF"
|
||||
android:pathData="M21.41,11.58L12.41,2.58C12.05,2.22 11.55,2 11,2H4C2.9,2 2,2.9 2,4V11C2,11.55 2.22,12.05 2.59,12.42L11.59,21.42C11.95,21.78 12.45,22 13,22C13.55,22 14.05,21.78 14.41,21.41L21.41,14.41C21.78,14.05 22,13.55 22,13C22,12.45 21.77,11.94 21.41,11.58M13,20L4,11V4H11L20,13M6.5,5C7.33,5 8,5.67 8,6.5C8,7.33 7.33,8 6.5,8C5.67,8 5,7.33 5,6.5C5,5.67 5.67,5 6.5,5Z" />
|
||||
</vector>
|
||||
@@ -44,12 +44,24 @@
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<!-- 内容插槽:筛选条件项由使用方在 XML 中声明 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_content"
|
||||
<!-- 内容插槽:筛选条件项由使用方在 XML 中声明。
|
||||
外包 ScrollView + weight=1:筛选项少时行为不变(wrap 高度),
|
||||
筛选项多到超屏时内容区收缩滚动,保证底部「重置/确认」按钮始终可见
|
||||
(出港查询 9 个筛选项时曾把按钮挤出屏幕) -->
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" />
|
||||
android:layout_weight="1"
|
||||
android:overScrollMode="never"
|
||||
android:scrollbars="none">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" />
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<!-- 底部按钮行 -->
|
||||
<LinearLayout
|
||||
|
||||
@@ -79,5 +79,6 @@
|
||||
<color name="phone_tag_indigo_text">#6366F1</color>
|
||||
<color name="phone_tag_amber_bg">#FEF3C7</color> <!-- 状态标签-琥珀底(出港运抵申报状态 E) -->
|
||||
<color name="phone_tag_amber_text">#D97706</color>
|
||||
<color name="phone_amber">#F59E0B</color> <!-- 橙色信息卡表头(进港移库-异常照片) -->
|
||||
|
||||
</resources>
|
||||
@@ -18,6 +18,7 @@ import com.lukouguoji.module_base.ktx.getLifecycleOwner
|
||||
import com.lukouguoji.module_base.ktx.setUpperCaseAlphanumericFilter
|
||||
import com.lukouguoji.module_base.ktx.setUpperCaseLetterFilter
|
||||
import com.lukouguoji.module_base.router.ARouterConstants
|
||||
import com.lukouguoji.module_base.util.DeviceUtil
|
||||
|
||||
/**
|
||||
* 国际出港查询列表页
|
||||
@@ -31,7 +32,7 @@ class GjcQueryActivity :
|
||||
override fun viewModelClass() = GjcQueryViewModel::class.java
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow("国际出港查询")
|
||||
setBackArrow(if (DeviceUtil.isPhone()) "出港查询" else "国际出港查询")
|
||||
|
||||
binding.viewModel = viewModel
|
||||
|
||||
@@ -48,23 +49,36 @@ class GjcQueryActivity :
|
||||
viewModel.initAgentList()
|
||||
viewModel.initFilterLists()
|
||||
|
||||
// 观察筛选面板显示状态
|
||||
viewModel.filterVisible.observe(this) { visible ->
|
||||
if (visible) showFilterPanel() else hideFilterPanel()
|
||||
// 平板变体才有侧滑筛选面板(filter_panel/filter_overlay 手机变体不存在,Binding 字段为 null)
|
||||
val padFilterPanel = binding.filterPanel
|
||||
if (padFilterPanel != null) {
|
||||
// 观察筛选面板显示状态(滑入/滑出动画)
|
||||
viewModel.filterVisible.observe(this) { visible ->
|
||||
if (visible) showFilterPanel() else hideFilterPanel()
|
||||
}
|
||||
|
||||
// 航班号:大写字母+数字
|
||||
padFilterPanel.filterFlightNo.et.setUpperCaseAlphanumericFilter()
|
||||
// 目的港:仅大写字母
|
||||
padFilterPanel.filterDest.et.setUpperCaseLetterFilter()
|
||||
} else {
|
||||
// 手机变体:PhoneFilterPanel 的显隐由 XML 直接绑定 viewModel.filterVisible,无需动画代码
|
||||
binding.phoneFilterFlightNo?.et?.setUpperCaseAlphanumericFilter()
|
||||
binding.phoneFilterDest?.et?.setUpperCaseLetterFilter()
|
||||
}
|
||||
|
||||
// 航班号:大写字母+数字
|
||||
binding.filterPanel.filterFlightNo.et.setUpperCaseAlphanumericFilter()
|
||||
// 目的港:仅大写字母
|
||||
binding.filterPanel.filterDest.et.setUpperCaseLetterFilter()
|
||||
// 手机形态专属:特码下拉字典 + 已入库/已离港统计
|
||||
if (DeviceUtil.isPhone()) {
|
||||
viewModel.initPhoneExtras()
|
||||
}
|
||||
|
||||
// 初始加载
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
private fun showFilterPanel() {
|
||||
val panel = binding.filterPanel.root
|
||||
val overlay = binding.filterOverlay
|
||||
val panel = binding.filterPanel?.root ?: return
|
||||
val overlay = binding.filterOverlay ?: return
|
||||
val panelWidth = window.decorView.width / 3
|
||||
|
||||
panel.layoutParams = (panel.layoutParams as FrameLayout.LayoutParams).apply {
|
||||
@@ -86,8 +100,8 @@ class GjcQueryActivity :
|
||||
}
|
||||
|
||||
private fun hideFilterPanel() {
|
||||
val panel = binding.filterPanel.root
|
||||
val overlay = binding.filterOverlay
|
||||
val panel = binding.filterPanel?.root ?: return
|
||||
val overlay = binding.filterOverlay ?: return
|
||||
|
||||
if (panel.visibility != View.VISIBLE) return
|
||||
|
||||
|
||||
@@ -1,90 +1,91 @@
|
||||
package com.lukouguoji.gjc.activity
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.Gravity
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.lukouguoji.gjc.R
|
||||
import com.lukouguoji.gjc.databinding.ActivityGjcQueryDetailsBinding
|
||||
import com.lukouguoji.gjc.viewModel.GjcQueryDetailsViewModel
|
||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||
import com.lukouguoji.module_base.base.CustomVP2Adapter
|
||||
import com.lukouguoji.module_base.common.Constant
|
||||
import com.lukouguoji.module_base.router.ARouterConstants
|
||||
|
||||
/**
|
||||
* 国际出港查询详情页面
|
||||
*/
|
||||
@Route(path = ARouterConstants.ACTIVITY_URL_GJC_QUERY_DETAILS)
|
||||
class GjcQueryDetailsActivity :
|
||||
BaseBindingActivity<ActivityGjcQueryDetailsBinding, GjcQueryDetailsViewModel>() {
|
||||
|
||||
override fun layoutId() = R.layout.activity_gjc_query_details
|
||||
override fun viewModelClass() = GjcQueryDetailsViewModel::class.java
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow("国际出港查询详情")
|
||||
binding.viewModel = viewModel
|
||||
|
||||
// 初始化ViewModel(传入maWbId)
|
||||
viewModel.initOnCreated(intent)
|
||||
|
||||
// 配置ViewPager2
|
||||
binding.vp.adapter = CustomVP2Adapter(
|
||||
viewModel.fragmentList,
|
||||
supportFragmentManager,
|
||||
lifecycle
|
||||
)
|
||||
binding.vp.isUserInputEnabled = false // 禁用滑动
|
||||
binding.vp.offscreenPageLimit = 3 // 预加载3个Fragment
|
||||
|
||||
// 监听Tab索引变化,切换Fragment
|
||||
viewModel.currentTab.observe(this) {
|
||||
binding.vp.setCurrentItem(it, false) // false:无动画
|
||||
}
|
||||
|
||||
// 标题栏右侧添加日志查询图标
|
||||
val toolbar = findViewById<Toolbar>(com.lukouguoji.module_base.R.id.toolbar)
|
||||
val logIcon = ImageView(this).apply {
|
||||
setImageResource(com.lukouguoji.module_base.R.drawable.img_log)
|
||||
layoutParams = Toolbar.LayoutParams(
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
).apply {
|
||||
gravity = Gravity.END or Gravity.CENTER_VERTICAL
|
||||
marginEnd = 15
|
||||
width = 30.dp
|
||||
height = 30.dp
|
||||
}
|
||||
setOnClickListener {
|
||||
val wbNo = viewModel.maWbData.value?.get("wbNo") as? String ?: ""
|
||||
ARouter.getInstance()
|
||||
.build(ARouterConstants.ACTIVITY_URL_LOG_DETAIL)
|
||||
.withString(Constant.Key.KEY, wbNo)
|
||||
.withString(Constant.Key.AWB_TYPE, "IO")
|
||||
.navigation()
|
||||
}
|
||||
}
|
||||
toolbar.addView(logIcon)
|
||||
|
||||
// 加载详情数据
|
||||
viewModel.loadDetails()
|
||||
}
|
||||
|
||||
private val Int.dp: Int
|
||||
get() = (this * resources!!.displayMetrics.density).toInt()
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun start(context: Context, maWbId: Long?) {
|
||||
val starter = Intent(context, GjcQueryDetailsActivity::class.java)
|
||||
.putExtra(Constant.Key.ID, maWbId?.toString() ?: "")
|
||||
context.startActivity(starter)
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.lukouguoji.gjc.activity
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.Gravity
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.lukouguoji.gjc.R
|
||||
import com.lukouguoji.gjc.databinding.ActivityGjcQueryDetailsBinding
|
||||
import com.lukouguoji.gjc.viewModel.GjcQueryDetailsViewModel
|
||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||
import com.lukouguoji.module_base.base.CustomVP2Adapter
|
||||
import com.lukouguoji.module_base.common.Constant
|
||||
import com.lukouguoji.module_base.router.ARouterConstants
|
||||
import com.lukouguoji.module_base.util.DeviceUtil
|
||||
|
||||
/**
|
||||
* 国际出港查询详情页面
|
||||
*/
|
||||
@Route(path = ARouterConstants.ACTIVITY_URL_GJC_QUERY_DETAILS)
|
||||
class GjcQueryDetailsActivity :
|
||||
BaseBindingActivity<ActivityGjcQueryDetailsBinding, GjcQueryDetailsViewModel>() {
|
||||
|
||||
override fun layoutId() = R.layout.activity_gjc_query_details
|
||||
override fun viewModelClass() = GjcQueryDetailsViewModel::class.java
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow(if (DeviceUtil.isPhone()) "出港货物" else "国际出港查询详情")
|
||||
binding.viewModel = viewModel
|
||||
|
||||
// 初始化ViewModel(传入maWbId)
|
||||
viewModel.initOnCreated(intent)
|
||||
|
||||
// 配置ViewPager2
|
||||
binding.vp.adapter = CustomVP2Adapter(
|
||||
viewModel.fragmentList,
|
||||
supportFragmentManager,
|
||||
lifecycle
|
||||
)
|
||||
binding.vp.isUserInputEnabled = false // 禁用滑动
|
||||
binding.vp.offscreenPageLimit = 3 // 预加载3个Fragment
|
||||
|
||||
// 监听Tab索引变化,切换Fragment
|
||||
viewModel.currentTab.observe(this) {
|
||||
binding.vp.setCurrentItem(it, false) // false:无动画
|
||||
}
|
||||
|
||||
// 标题栏右侧添加日志查询图标
|
||||
val toolbar = findViewById<Toolbar>(com.lukouguoji.module_base.R.id.toolbar)
|
||||
val logIcon = ImageView(this).apply {
|
||||
setImageResource(com.lukouguoji.module_base.R.drawable.img_log)
|
||||
layoutParams = Toolbar.LayoutParams(
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
).apply {
|
||||
gravity = Gravity.END or Gravity.CENTER_VERTICAL
|
||||
marginEnd = 15
|
||||
width = 30.dp
|
||||
height = 30.dp
|
||||
}
|
||||
setOnClickListener {
|
||||
val wbNo = viewModel.maWbData.value?.get("wbNo") as? String ?: ""
|
||||
ARouter.getInstance()
|
||||
.build(ARouterConstants.ACTIVITY_URL_LOG_DETAIL)
|
||||
.withString(Constant.Key.KEY, wbNo)
|
||||
.withString(Constant.Key.AWB_TYPE, "IO")
|
||||
.navigation()
|
||||
}
|
||||
}
|
||||
toolbar.addView(logIcon)
|
||||
|
||||
// 加载详情数据
|
||||
viewModel.loadDetails()
|
||||
}
|
||||
|
||||
private val Int.dp: Int
|
||||
get() = (this * resources!!.displayMetrics.density).toInt()
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun start(context: Context, maWbId: Long?) {
|
||||
val starter = Intent(context, GjcQueryDetailsActivity::class.java)
|
||||
.putExtra(Constant.Key.ID, maWbId?.toString() ?: "")
|
||||
context.startActivity(starter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,105 +1,104 @@
|
||||
package com.lukouguoji.gjc.activity
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.databinding.ObservableBoolean
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.lukouguoji.gjc.R
|
||||
import com.lukouguoji.gjc.databinding.ActivityGjcWeighingListBinding
|
||||
import com.lukouguoji.gjc.viewModel.GjcWeighingViewModel
|
||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||
import com.lukouguoji.module_base.bean.GjcWeighingBean
|
||||
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.getLifecycleOwner
|
||||
import com.lukouguoji.module_base.router.ARouterConstants
|
||||
import com.lukouguoji.module_base.util.DeviceUtil
|
||||
|
||||
/**
|
||||
* 国际出港计重列表页
|
||||
*
|
||||
* 布局 id 不区分设备,平板/手机由资源限定符自动选择:
|
||||
* layout-sw600dp/activity_gjc_weighing_list.xml(平板)
|
||||
* layout/activity_gjc_weighing_list.xml(手机)
|
||||
*/
|
||||
@Route(path = ARouterConstants.ACTIVITY_URL_GJC_WEIGHING_LIST)
|
||||
class GjcWeighingListActivity :
|
||||
BaseBindingActivity<ActivityGjcWeighingListBinding, GjcWeighingViewModel>() {
|
||||
|
||||
override fun layoutId() = R.layout.activity_gjc_weighing_list
|
||||
|
||||
override fun viewModelClass() = GjcWeighingViewModel::class.java
|
||||
|
||||
/** 手机版筛选弹层显隐(仅 UI 状态,不涉及业务逻辑) */
|
||||
val filterPanelVisible = ObservableBoolean(false)
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow("国际出港待计重")
|
||||
|
||||
binding.viewModel = viewModel
|
||||
binding.activity = this
|
||||
|
||||
// 手机版专属数据:放开默认日期、加载筛选弹层字典、启用三格统计
|
||||
// 平板端不调用,查询链路与请求次数与改造前完全一致
|
||||
if (DeviceUtil.isPhone()) {
|
||||
viewModel.initPhoneExtras()
|
||||
}
|
||||
|
||||
// 初始化代理人列表(从API获取)
|
||||
viewModel.initAgentList()
|
||||
|
||||
// 初始化特码列表(从API获取)
|
||||
viewModel.initSpecialCodeList()
|
||||
|
||||
// 绑定分页逻辑
|
||||
viewModel.pageModel
|
||||
.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, getLifecycleOwner())
|
||||
|
||||
// 监听刷新事件
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_CHECK_CHANGED).observe(this) { viewModel.onItemCheckChanged() }
|
||||
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH)
|
||||
.observe(this) {
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
// 初始加载
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
// ==================== 手机版专用交互(纯 UI,复用既有 ViewModel 字段) ====================
|
||||
|
||||
/** 手机版筛选弹层显隐切换 */
|
||||
fun toggleFilterPanel() {
|
||||
filterPanelVisible.set(!filterPanelVisible.get())
|
||||
}
|
||||
|
||||
/** 手机版筛选:重置(只清弹层内条件,不影响顶部搜索框) */
|
||||
fun resetFilter() {
|
||||
viewModel.channelFilter.value = ""
|
||||
viewModel.carrierFilter.value = ""
|
||||
viewModel.awbTypeFilter.value = ""
|
||||
viewModel.agentCode.value = ""
|
||||
}
|
||||
|
||||
/** 手机版筛选:确认 */
|
||||
fun confirmFilter() {
|
||||
filterPanelVisible.set(false)
|
||||
viewModel.searchClick()
|
||||
}
|
||||
|
||||
/** 手机版卡片内「提前运抵」(单票,由 ViewHolder 调用) */
|
||||
fun preArriveClick(bean: GjcWeighingBean) {
|
||||
viewModel.arrivedAheadSingle(bean)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun start(context: Context) {
|
||||
val starter = Intent(context, GjcWeighingListActivity::class.java)
|
||||
context.startActivity(starter)
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.lukouguoji.gjc.activity
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.databinding.ObservableBoolean
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.lukouguoji.gjc.R
|
||||
import com.lukouguoji.gjc.databinding.ActivityGjcWeighingListBinding
|
||||
import com.lukouguoji.gjc.viewModel.GjcWeighingViewModel
|
||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||
import com.lukouguoji.module_base.bean.GjcWeighingBean
|
||||
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.getLifecycleOwner
|
||||
import com.lukouguoji.module_base.router.ARouterConstants
|
||||
import com.lukouguoji.module_base.util.DeviceUtil
|
||||
|
||||
/**
|
||||
* 国际出港计重列表页
|
||||
*
|
||||
* 布局 id 不区分设备,平板/手机由资源限定符自动选择:
|
||||
* layout-sw600dp/activity_gjc_weighing_list.xml(平板)
|
||||
* layout/activity_gjc_weighing_list.xml(手机)
|
||||
*/
|
||||
@Route(path = ARouterConstants.ACTIVITY_URL_GJC_WEIGHING_LIST)
|
||||
class GjcWeighingListActivity :
|
||||
BaseBindingActivity<ActivityGjcWeighingListBinding, GjcWeighingViewModel>() {
|
||||
|
||||
override fun layoutId() = R.layout.activity_gjc_weighing_list
|
||||
|
||||
override fun viewModelClass() = GjcWeighingViewModel::class.java
|
||||
|
||||
/** 手机版筛选弹层显隐(仅 UI 状态,不涉及业务逻辑) */
|
||||
val filterPanelVisible = ObservableBoolean(false)
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow(if (DeviceUtil.isPhone()) "出港待计重" else "国际出港待计重")
|
||||
|
||||
binding.viewModel = viewModel
|
||||
binding.activity = this
|
||||
|
||||
// 手机版专属数据:放开默认日期、加载筛选弹层字典、启用三格统计
|
||||
// 平板端不调用,查询链路与请求次数与改造前完全一致
|
||||
if (DeviceUtil.isPhone()) {
|
||||
viewModel.initPhoneExtras()
|
||||
}
|
||||
|
||||
// 初始化代理人列表(从API获取)
|
||||
viewModel.initAgentList()
|
||||
|
||||
// 初始化特码列表(从API获取)
|
||||
viewModel.initSpecialCodeList()
|
||||
|
||||
// 绑定分页逻辑
|
||||
viewModel.pageModel
|
||||
.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, getLifecycleOwner())
|
||||
|
||||
// 监听刷新事件
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_CHECK_CHANGED).observe(this) { viewModel.onItemCheckChanged() }
|
||||
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH)
|
||||
.observe(this) {
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
// 初始加载
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
// ==================== 手机版专用交互(纯 UI,复用既有 ViewModel 字段) ====================
|
||||
|
||||
/** 手机版筛选弹层显隐切换 */
|
||||
fun toggleFilterPanel() {
|
||||
filterPanelVisible.set(!filterPanelVisible.get())
|
||||
}
|
||||
|
||||
/** 手机版筛选:重置(只清弹层内条件,不影响顶部搜索框) */
|
||||
fun resetFilter() {
|
||||
viewModel.flightDate.value = ""
|
||||
viewModel.agentCode.value = ""
|
||||
viewModel.spCode.value = ""
|
||||
}
|
||||
|
||||
/** 手机版筛选:确认 */
|
||||
fun confirmFilter() {
|
||||
filterPanelVisible.set(false)
|
||||
viewModel.searchClick()
|
||||
}
|
||||
|
||||
/** 手机版卡片内「提前运抵」(单票,由 ViewHolder 调用) */
|
||||
fun preArriveClick(bean: GjcWeighingBean) {
|
||||
viewModel.arrivedAheadSingle(bean)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun start(context: Context) {
|
||||
val starter = Intent(context, GjcWeighingListActivity::class.java)
|
||||
context.startActivity(starter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,103 +1,104 @@
|
||||
package com.lukouguoji.gjc.activity
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.lukouguoji.gjc.R
|
||||
import com.lukouguoji.gjc.databinding.ActivityGjcWeighingRecordDetailsBinding
|
||||
import com.lukouguoji.gjc.holder.GjcCheckInRecordViewHolder
|
||||
import com.lukouguoji.gjc.viewModel.GjcWeighingRecordDetailsViewModel
|
||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||
import com.lukouguoji.module_base.base.CommonAdapter
|
||||
import com.lukouguoji.module_base.bean.GjcCheckInRecord
|
||||
import com.lukouguoji.module_base.bean.GjcWeighingRecordBean
|
||||
import com.lukouguoji.module_base.common.Constant
|
||||
import com.lukouguoji.module_base.router.ARouterConstants
|
||||
|
||||
/**
|
||||
* 国际出港计重明细页
|
||||
*
|
||||
* 布局 id 不区分设备,平板/手机由资源限定符自动选择:
|
||||
* layout-sw600dp/activity_gjc_weighing_record_details.xml(平板,列表内联编辑)
|
||||
* layout/activity_gjc_weighing_record_details.xml(手机,单条记录经全屏「修改记录」覆层编辑)
|
||||
*/
|
||||
@Route(path = ARouterConstants.ACTIVITY_URL_GJC_WEIGHING_RECORD_DETAILS)
|
||||
class GjcWeighingRecordDetailsActivity :
|
||||
BaseBindingActivity<ActivityGjcWeighingRecordDetailsBinding, GjcWeighingRecordDetailsViewModel>() {
|
||||
|
||||
private lateinit var adapter: CommonAdapter
|
||||
|
||||
// 当前编辑模式(供ViewHolder获取)
|
||||
var currentEditMode = false
|
||||
|
||||
override fun layoutId() = R.layout.activity_gjc_weighing_record_details
|
||||
|
||||
override fun viewModelClass() = GjcWeighingRecordDetailsViewModel::class.java
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow("国际出港计重明细")
|
||||
|
||||
binding.viewModel = viewModel
|
||||
|
||||
// 初始化RecyclerView
|
||||
val layoutManager = LinearLayoutManager(this)
|
||||
binding.recyclerView.layoutManager = layoutManager
|
||||
|
||||
// 添加分割线
|
||||
val divider = DividerItemDecoration(this, DividerItemDecoration.VERTICAL)
|
||||
binding.recyclerView.addItemDecoration(divider)
|
||||
|
||||
adapter = CommonAdapter(
|
||||
this,
|
||||
R.layout.item_gjc_check_in_record,
|
||||
GjcCheckInRecordViewHolder::class.java
|
||||
)
|
||||
binding.recyclerView.adapter = adapter
|
||||
|
||||
// 监听数据变化更新RecyclerView
|
||||
viewModel.recordList.observe(this) { records ->
|
||||
adapter.refresh(records)
|
||||
}
|
||||
|
||||
// 监听编辑模式变化,更新当前编辑模式并刷新列表
|
||||
viewModel.isEditMode.observe(this) { isEditMode ->
|
||||
// 更新当前编辑模式状态
|
||||
currentEditMode = isEditMode
|
||||
|
||||
// 刷新所有可见的 ViewHolder
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
// 初始化数据
|
||||
viewModel.initOnCreated(intent)
|
||||
}
|
||||
|
||||
// ==================== 手机版专用交互(纯 UI,复用既有 ViewModel 编辑链路) ====================
|
||||
|
||||
/**
|
||||
* 手机版:打开「修改记录」覆层编辑指定记录。
|
||||
* 复用 [GjcWeighingRecordDetailsViewModel.onModifyClick] 的备份/编辑态逻辑,
|
||||
* 覆层显隐由 isEditMode 驱动(平板端该状态驱动列表内联编辑,互不影响)。
|
||||
*/
|
||||
fun openPhoneEdit(record: GjcCheckInRecord) {
|
||||
viewModel.onModifyClick()
|
||||
binding.editRecord = record
|
||||
}
|
||||
|
||||
/** 手机版:取消编辑(恢复备份并收起覆层) */
|
||||
fun closePhoneEdit() {
|
||||
viewModel.onCancelClick()
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun start(context: Context, bean: GjcWeighingRecordBean) {
|
||||
val starter = Intent(context, GjcWeighingRecordDetailsActivity::class.java)
|
||||
.putExtra(Constant.Key.BEAN, bean)
|
||||
context.startActivity(starter)
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.lukouguoji.gjc.activity
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.lukouguoji.gjc.R
|
||||
import com.lukouguoji.gjc.databinding.ActivityGjcWeighingRecordDetailsBinding
|
||||
import com.lukouguoji.gjc.holder.GjcCheckInRecordViewHolder
|
||||
import com.lukouguoji.gjc.viewModel.GjcWeighingRecordDetailsViewModel
|
||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||
import com.lukouguoji.module_base.base.CommonAdapter
|
||||
import com.lukouguoji.module_base.bean.GjcCheckInRecord
|
||||
import com.lukouguoji.module_base.bean.GjcWeighingRecordBean
|
||||
import com.lukouguoji.module_base.common.Constant
|
||||
import com.lukouguoji.module_base.router.ARouterConstants
|
||||
import com.lukouguoji.module_base.util.DeviceUtil
|
||||
|
||||
/**
|
||||
* 国际出港计重明细页
|
||||
*
|
||||
* 布局 id 不区分设备,平板/手机由资源限定符自动选择:
|
||||
* layout-sw600dp/activity_gjc_weighing_record_details.xml(平板,列表内联编辑)
|
||||
* layout/activity_gjc_weighing_record_details.xml(手机,单条记录经全屏「修改记录」覆层编辑)
|
||||
*/
|
||||
@Route(path = ARouterConstants.ACTIVITY_URL_GJC_WEIGHING_RECORD_DETAILS)
|
||||
class GjcWeighingRecordDetailsActivity :
|
||||
BaseBindingActivity<ActivityGjcWeighingRecordDetailsBinding, GjcWeighingRecordDetailsViewModel>() {
|
||||
|
||||
private lateinit var adapter: CommonAdapter
|
||||
|
||||
// 当前编辑模式(供ViewHolder获取)
|
||||
var currentEditMode = false
|
||||
|
||||
override fun layoutId() = R.layout.activity_gjc_weighing_record_details
|
||||
|
||||
override fun viewModelClass() = GjcWeighingRecordDetailsViewModel::class.java
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow(if (DeviceUtil.isPhone()) "计重明细" else "国际出港计重明细")
|
||||
|
||||
binding.viewModel = viewModel
|
||||
|
||||
// 初始化RecyclerView
|
||||
val layoutManager = LinearLayoutManager(this)
|
||||
binding.recyclerView.layoutManager = layoutManager
|
||||
|
||||
// 添加分割线
|
||||
val divider = DividerItemDecoration(this, DividerItemDecoration.VERTICAL)
|
||||
binding.recyclerView.addItemDecoration(divider)
|
||||
|
||||
adapter = CommonAdapter(
|
||||
this,
|
||||
R.layout.item_gjc_check_in_record,
|
||||
GjcCheckInRecordViewHolder::class.java
|
||||
)
|
||||
binding.recyclerView.adapter = adapter
|
||||
|
||||
// 监听数据变化更新RecyclerView
|
||||
viewModel.recordList.observe(this) { records ->
|
||||
adapter.refresh(records)
|
||||
}
|
||||
|
||||
// 监听编辑模式变化,更新当前编辑模式并刷新列表
|
||||
viewModel.isEditMode.observe(this) { isEditMode ->
|
||||
// 更新当前编辑模式状态
|
||||
currentEditMode = isEditMode
|
||||
|
||||
// 刷新所有可见的 ViewHolder
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
// 初始化数据
|
||||
viewModel.initOnCreated(intent)
|
||||
}
|
||||
|
||||
// ==================== 手机版专用交互(纯 UI,复用既有 ViewModel 编辑链路) ====================
|
||||
|
||||
/**
|
||||
* 手机版:打开「修改记录」覆层编辑指定记录。
|
||||
* 复用 [GjcWeighingRecordDetailsViewModel.onModifyClick] 的备份/编辑态逻辑,
|
||||
* 覆层显隐由 isEditMode 驱动(平板端该状态驱动列表内联编辑,互不影响)。
|
||||
*/
|
||||
fun openPhoneEdit(record: GjcCheckInRecord) {
|
||||
viewModel.onModifyClick()
|
||||
binding.editRecord = record
|
||||
}
|
||||
|
||||
/** 手机版:取消编辑(恢复备份并收起覆层) */
|
||||
fun closePhoneEdit() {
|
||||
viewModel.onCancelClick()
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun start(context: Context, bean: GjcWeighingRecordBean) {
|
||||
val starter = Intent(context, GjcWeighingRecordDetailsActivity::class.java)
|
||||
.putExtra(Constant.Key.BEAN, bean)
|
||||
context.startActivity(starter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,99 +1,96 @@
|
||||
package com.lukouguoji.gjc.activity
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.databinding.ObservableBoolean
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.lukouguoji.gjc.R
|
||||
import com.lukouguoji.gjc.databinding.ActivityGjcWeighingRecordListBinding
|
||||
import com.lukouguoji.gjc.viewModel.GjcWeighingRecordViewModel
|
||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||
import com.lukouguoji.module_base.common.ConstantEvent
|
||||
import com.lukouguoji.module_base.impl.FlowBus
|
||||
import com.lukouguoji.module_base.impl.observe
|
||||
import com.lukouguoji.module_base.ktx.getLifecycleOwner
|
||||
import com.lukouguoji.module_base.router.ARouterConstants
|
||||
import com.lukouguoji.module_base.util.DeviceUtil
|
||||
|
||||
/**
|
||||
* 国际出港计重记录列表页
|
||||
*
|
||||
* 布局 id 不区分设备,平板/手机由资源限定符自动选择:
|
||||
* layout-sw600dp/activity_gjc_weighing_record_list.xml(平板)
|
||||
* layout/activity_gjc_weighing_record_list.xml(手机)
|
||||
*/
|
||||
@Route(path = ARouterConstants.ACTIVITY_URL_GJC_WEIGHING_RECORD_LIST)
|
||||
class GjcWeighingRecordListActivity :
|
||||
BaseBindingActivity<ActivityGjcWeighingRecordListBinding, GjcWeighingRecordViewModel>() {
|
||||
|
||||
override fun layoutId() = R.layout.activity_gjc_weighing_record_list
|
||||
|
||||
override fun viewModelClass() = GjcWeighingRecordViewModel::class.java
|
||||
|
||||
/** 手机版筛选弹层显隐(仅 UI 状态,不涉及业务逻辑) */
|
||||
val filterPanelVisible = ObservableBoolean(false)
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow("国际出港计重记录")
|
||||
|
||||
binding.viewModel = viewModel
|
||||
binding.activity = this
|
||||
|
||||
// 手机版专属数据:放开默认日期、加载计重人下拉
|
||||
// 平板端不调用,查询链路与请求次数与改造前完全一致
|
||||
if (DeviceUtil.isPhone()) {
|
||||
viewModel.initPhoneExtras()
|
||||
}
|
||||
|
||||
// 初始化代理人列表
|
||||
viewModel.initAgentList()
|
||||
|
||||
// 初始化特码列表
|
||||
viewModel.initSpecialCodeList()
|
||||
|
||||
// 绑定分页逻辑
|
||||
viewModel.pageModel
|
||||
.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, getLifecycleOwner())
|
||||
|
||||
// 监听刷新事件
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH)
|
||||
.observe(this) {
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
// 初始加载
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
// ==================== 手机版专用交互(纯 UI,复用既有 ViewModel 字段) ====================
|
||||
|
||||
/** 手机版筛选弹层显隐切换 */
|
||||
fun toggleFilterPanel() {
|
||||
filterPanelVisible.set(!filterPanelVisible.get())
|
||||
}
|
||||
|
||||
/** 手机版筛选:重置(只清弹层内条件,不影响顶部搜索框) */
|
||||
fun resetFilter() {
|
||||
viewModel.checkInDateStart.value = ""
|
||||
viewModel.checkInDateEnd.value = ""
|
||||
viewModel.agentCode.value = ""
|
||||
viewModel.spCode.value = ""
|
||||
viewModel.destFilter.value = ""
|
||||
viewModel.opUserFilter.value = ""
|
||||
}
|
||||
|
||||
/** 手机版筛选:确认 */
|
||||
fun confirmFilter() {
|
||||
filterPanelVisible.set(false)
|
||||
viewModel.searchClick()
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun start(context: Context) {
|
||||
val starter = Intent(context, GjcWeighingRecordListActivity::class.java)
|
||||
context.startActivity(starter)
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.lukouguoji.gjc.activity
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.databinding.ObservableBoolean
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.lukouguoji.gjc.R
|
||||
import com.lukouguoji.gjc.databinding.ActivityGjcWeighingRecordListBinding
|
||||
import com.lukouguoji.gjc.viewModel.GjcWeighingRecordViewModel
|
||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||
import com.lukouguoji.module_base.common.ConstantEvent
|
||||
import com.lukouguoji.module_base.impl.FlowBus
|
||||
import com.lukouguoji.module_base.impl.observe
|
||||
import com.lukouguoji.module_base.ktx.getLifecycleOwner
|
||||
import com.lukouguoji.module_base.router.ARouterConstants
|
||||
import com.lukouguoji.module_base.util.DeviceUtil
|
||||
|
||||
/**
|
||||
* 国际出港计重记录列表页
|
||||
*
|
||||
* 布局 id 不区分设备,平板/手机由资源限定符自动选择:
|
||||
* layout-sw600dp/activity_gjc_weighing_record_list.xml(平板)
|
||||
* layout/activity_gjc_weighing_record_list.xml(手机)
|
||||
*/
|
||||
@Route(path = ARouterConstants.ACTIVITY_URL_GJC_WEIGHING_RECORD_LIST)
|
||||
class GjcWeighingRecordListActivity :
|
||||
BaseBindingActivity<ActivityGjcWeighingRecordListBinding, GjcWeighingRecordViewModel>() {
|
||||
|
||||
override fun layoutId() = R.layout.activity_gjc_weighing_record_list
|
||||
|
||||
override fun viewModelClass() = GjcWeighingRecordViewModel::class.java
|
||||
|
||||
/** 手机版筛选弹层显隐(仅 UI 状态,不涉及业务逻辑) */
|
||||
val filterPanelVisible = ObservableBoolean(false)
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow(if (DeviceUtil.isPhone()) "计重记录" else "国际出港计重记录")
|
||||
|
||||
binding.viewModel = viewModel
|
||||
binding.activity = this
|
||||
|
||||
// 手机版专属数据:放开默认日期、加载计重人下拉
|
||||
// 平板端不调用,查询链路与请求次数与改造前完全一致
|
||||
if (DeviceUtil.isPhone()) {
|
||||
viewModel.initPhoneExtras()
|
||||
}
|
||||
|
||||
// 初始化代理人列表
|
||||
viewModel.initAgentList()
|
||||
|
||||
// 初始化特码列表
|
||||
viewModel.initSpecialCodeList()
|
||||
|
||||
// 绑定分页逻辑
|
||||
viewModel.pageModel
|
||||
.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, getLifecycleOwner())
|
||||
|
||||
// 监听刷新事件
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH)
|
||||
.observe(this) {
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
// 初始加载
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
// ==================== 手机版专用交互(纯 UI,复用既有 ViewModel 字段) ====================
|
||||
|
||||
/** 手机版筛选弹层显隐切换 */
|
||||
fun toggleFilterPanel() {
|
||||
filterPanelVisible.set(!filterPanelVisible.get())
|
||||
}
|
||||
|
||||
/** 手机版筛选:重置(只清弹层内条件,不影响顶部搜索框) */
|
||||
fun resetFilter() {
|
||||
viewModel.flightDate.value = ""
|
||||
viewModel.agentCode.value = ""
|
||||
viewModel.spCode.value = ""
|
||||
}
|
||||
|
||||
/** 手机版筛选:确认 */
|
||||
fun confirmFilter() {
|
||||
filterPanelVisible.set(false)
|
||||
viewModel.searchClick()
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun start(context: Context) {
|
||||
val starter = Intent(context, GjcWeighingRecordListActivity::class.java)
|
||||
context.startActivity(starter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,221 +1,221 @@
|
||||
package com.lukouguoji.gjc.activity
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.animation.AnimatorSet
|
||||
import android.animation.ObjectAnimator
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.lukouguoji.gjc.R
|
||||
import com.lukouguoji.gjc.databinding.ActivityGjcWeighingStartBinding
|
||||
import com.lukouguoji.gjc.viewModel.GjcWeighingStartViewModel
|
||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||
import com.lukouguoji.module_base.common.Constant
|
||||
import com.lukouguoji.module_base.router.ARouterConstants
|
||||
import com.lukouguoji.module_base.util.DeviceUtil
|
||||
|
||||
/**
|
||||
* 国际出港计重-开始计重页面
|
||||
*/
|
||||
@Route(path = ARouterConstants.ACTIVITY_URL_GJC_WEIGHING_START)
|
||||
class GjcWeighingStartActivity :
|
||||
BaseBindingActivity<ActivityGjcWeighingStartBinding, GjcWeighingStartViewModel>() {
|
||||
|
||||
private var isExpanded = false
|
||||
|
||||
override fun layoutId() = R.layout.activity_gjc_weighing_start
|
||||
|
||||
override fun viewModelClass() = GjcWeighingStartViewModel::class.java
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow("国际出港开始计重")
|
||||
binding.viewModel = viewModel
|
||||
|
||||
// 手机版专属:提交体携带托盘数量/托盘自重(平板不调用,请求体与改造前完全一致)
|
||||
if (DeviceUtil.isPhone()) {
|
||||
viewModel.initPhoneExtras()
|
||||
}
|
||||
|
||||
viewModel.initOnCreated(this, intent)
|
||||
|
||||
setupFloatButtons()
|
||||
}
|
||||
|
||||
private fun setupFloatButtons() {
|
||||
// 浮动按钮组仅平板布局存在(layout-sw600dp),手机布局无这些 id,直接跳过
|
||||
val mainFloatButton = binding.mainFloatButton ?: return
|
||||
val maskView = binding.maskView ?: return
|
||||
val subButton1 = binding.subButton1 ?: return
|
||||
val subButton2 = binding.subButton2 ?: return
|
||||
|
||||
// 主按钮点击事件
|
||||
mainFloatButton.setOnClickListener {
|
||||
if (!isExpanded) {
|
||||
expandButtons()
|
||||
}
|
||||
}
|
||||
|
||||
// 遮罩层点击事件
|
||||
maskView.setOnClickListener {
|
||||
collapseButtons()
|
||||
}
|
||||
|
||||
// 子按钮1点击事件 - 跳转到出港运抵页面
|
||||
subButton1.setOnClickListener {
|
||||
com.alibaba.android.arouter.launcher.ARouter.getInstance()
|
||||
.build(ARouterConstants.ACTIVITY_URL_INT_EXP_ARRIVE)
|
||||
.navigation()
|
||||
collapseButtons()
|
||||
}
|
||||
|
||||
// 子按钮2点击事件 - 跳转到计重记录
|
||||
subButton2.setOnClickListener {
|
||||
com.alibaba.android.arouter.launcher.ARouter.getInstance()
|
||||
.build(ARouterConstants.ACTIVITY_URL_GJC_WEIGHING_RECORD_LIST)
|
||||
.navigation()
|
||||
collapseButtons()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 展开子按钮(仅平板,手机布局无浮动按钮组)
|
||||
*/
|
||||
private fun expandButtons() {
|
||||
val mainFloatButton = binding.mainFloatButton ?: return
|
||||
val maskView = binding.maskView ?: return
|
||||
val subButton1 = binding.subButton1 ?: return
|
||||
val subButton2 = binding.subButton2 ?: return
|
||||
|
||||
isExpanded = true
|
||||
|
||||
// 显示遮罩层
|
||||
maskView.visibility = View.VISIBLE
|
||||
maskView.alpha = 0f
|
||||
maskView.animate().alpha(0.3f).setDuration(200).start()
|
||||
|
||||
// 显示子按钮
|
||||
subButton1.visibility = View.VISIBLE
|
||||
subButton2.visibility = View.VISIBLE
|
||||
|
||||
// 子按钮1动画(向左上方移动: 左移15dp, 上移55dp)
|
||||
val sub1TransX = ObjectAnimator.ofFloat(subButton1, "translationX", 0f, -5f)
|
||||
val sub1TransY = ObjectAnimator.ofFloat(subButton1, "translationY", 0f, -25f)
|
||||
val sub1Alpha = ObjectAnimator.ofFloat(subButton1, "alpha", 0f, 1f)
|
||||
val sub1Scale = ObjectAnimator.ofFloat(subButton1, "scaleX", 0f, 1f)
|
||||
val sub1ScaleY = ObjectAnimator.ofFloat(subButton1, "scaleY", 0f, 1f)
|
||||
|
||||
val animSet1 = AnimatorSet()
|
||||
animSet1.playTogether(sub1TransX, sub1TransY, sub1Alpha, sub1Scale, sub1ScaleY)
|
||||
animSet1.duration = 200
|
||||
|
||||
// 子按钮2动画(向左下方移动: 左移55dp, 下移15dp)
|
||||
val sub2TransX = ObjectAnimator.ofFloat(subButton2, "translationX", 0f, -25f)
|
||||
val sub2TransY = ObjectAnimator.ofFloat(subButton2, "translationY", 0f, -5f)
|
||||
val sub2Alpha = ObjectAnimator.ofFloat(subButton2, "alpha", 0f, 1f)
|
||||
val sub2Scale = ObjectAnimator.ofFloat(subButton2, "scaleX", 0f, 1f)
|
||||
val sub2ScaleY = ObjectAnimator.ofFloat(subButton2, "scaleY", 0f, 1f)
|
||||
|
||||
val animSet2 = AnimatorSet()
|
||||
animSet2.playTogether(sub2TransX, sub2TransY, sub2Alpha, sub2Scale, sub2ScaleY)
|
||||
animSet2.duration = 200
|
||||
animSet2.startDelay = 50
|
||||
|
||||
// 主按钮隐藏动画
|
||||
mainFloatButton.animate()
|
||||
.scaleX(0f)
|
||||
.scaleY(0f)
|
||||
.alpha(0f)
|
||||
.setDuration(150)
|
||||
.setListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
mainFloatButton.visibility = View.GONE
|
||||
}
|
||||
})
|
||||
.start()
|
||||
|
||||
animSet1.start()
|
||||
animSet2.start()
|
||||
}
|
||||
|
||||
/**
|
||||
* 收起子按钮(仅平板,手机布局无浮动按钮组)
|
||||
*/
|
||||
private fun collapseButtons() {
|
||||
val mainFloatButton = binding.mainFloatButton ?: return
|
||||
val maskView = binding.maskView ?: return
|
||||
val subButton1 = binding.subButton1 ?: return
|
||||
val subButton2 = binding.subButton2 ?: return
|
||||
|
||||
isExpanded = false
|
||||
|
||||
// 隐藏遮罩层
|
||||
maskView.animate().alpha(0f).setDuration(200).withEndAction {
|
||||
maskView.visibility = View.GONE
|
||||
}.start()
|
||||
|
||||
// 子按钮1动画(回到原位)
|
||||
val sub1TransX = ObjectAnimator.ofFloat(subButton1, "translationX", subButton1.translationX, 0f)
|
||||
val sub1TransY = ObjectAnimator.ofFloat(subButton1, "translationY", subButton1.translationY, 0f)
|
||||
val sub1Alpha = ObjectAnimator.ofFloat(subButton1, "alpha", 1f, 0f)
|
||||
val sub1Scale = ObjectAnimator.ofFloat(subButton1, "scaleX", 1f, 0f)
|
||||
val sub1ScaleY = ObjectAnimator.ofFloat(subButton1, "scaleY", 1f, 0f)
|
||||
|
||||
val animSet1 = AnimatorSet()
|
||||
animSet1.playTogether(sub1TransX, sub1TransY, sub1Alpha, sub1Scale, sub1ScaleY)
|
||||
animSet1.duration = 200
|
||||
|
||||
// 子按钮2动画(回到原位)
|
||||
val sub2TransX = ObjectAnimator.ofFloat(subButton2, "translationX", subButton2.translationX, 0f)
|
||||
val sub2TransY = ObjectAnimator.ofFloat(subButton2, "translationY", subButton2.translationY, 0f)
|
||||
val sub2Alpha = ObjectAnimator.ofFloat(subButton2, "alpha", 1f, 0f)
|
||||
val sub2Scale = ObjectAnimator.ofFloat(subButton2, "scaleX", 1f, 0f)
|
||||
val sub2ScaleY = ObjectAnimator.ofFloat(subButton2, "scaleY", 1f, 0f)
|
||||
|
||||
val animSet2 = AnimatorSet()
|
||||
animSet2.playTogether(sub2TransX, sub2TransY, sub2Alpha, sub2Scale, sub2ScaleY)
|
||||
animSet2.duration = 200
|
||||
|
||||
animSet1.addListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
subButton1.visibility = View.GONE
|
||||
}
|
||||
})
|
||||
|
||||
animSet2.addListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
subButton2.visibility = View.GONE
|
||||
}
|
||||
})
|
||||
|
||||
// 主按钮显示动画
|
||||
mainFloatButton.visibility = View.VISIBLE
|
||||
mainFloatButton.animate()
|
||||
.scaleX(1f)
|
||||
.scaleY(1f)
|
||||
.alpha(1f)
|
||||
.setDuration(200)
|
||||
.setStartDelay(100)
|
||||
.setListener(null)
|
||||
.start()
|
||||
|
||||
animSet1.start()
|
||||
animSet2.start()
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* 启动开始计重页面
|
||||
* @param context 上下文
|
||||
* @param maWbId 运单ID,默认为0(新增模式)
|
||||
*/
|
||||
@JvmStatic
|
||||
fun startForAdd(context: Context, maWbId: Long = 0) {
|
||||
val starter = Intent(context, GjcWeighingStartActivity::class.java)
|
||||
.putExtra(Constant.Key.MAWB_ID, maWbId)
|
||||
context.startActivity(starter)
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.lukouguoji.gjc.activity
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.animation.AnimatorSet
|
||||
import android.animation.ObjectAnimator
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.lukouguoji.gjc.R
|
||||
import com.lukouguoji.gjc.databinding.ActivityGjcWeighingStartBinding
|
||||
import com.lukouguoji.gjc.viewModel.GjcWeighingStartViewModel
|
||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||
import com.lukouguoji.module_base.common.Constant
|
||||
import com.lukouguoji.module_base.router.ARouterConstants
|
||||
import com.lukouguoji.module_base.util.DeviceUtil
|
||||
|
||||
/**
|
||||
* 国际出港计重-开始计重页面
|
||||
*/
|
||||
@Route(path = ARouterConstants.ACTIVITY_URL_GJC_WEIGHING_START)
|
||||
class GjcWeighingStartActivity :
|
||||
BaseBindingActivity<ActivityGjcWeighingStartBinding, GjcWeighingStartViewModel>() {
|
||||
|
||||
private var isExpanded = false
|
||||
|
||||
override fun layoutId() = R.layout.activity_gjc_weighing_start
|
||||
|
||||
override fun viewModelClass() = GjcWeighingStartViewModel::class.java
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow(if (DeviceUtil.isPhone()) "开始计重" else "国际出港开始计重")
|
||||
binding.viewModel = viewModel
|
||||
|
||||
// 手机版专属:提交体携带托盘数量/托盘自重(平板不调用,请求体与改造前完全一致)
|
||||
if (DeviceUtil.isPhone()) {
|
||||
viewModel.initPhoneExtras()
|
||||
}
|
||||
|
||||
viewModel.initOnCreated(this, intent)
|
||||
|
||||
setupFloatButtons()
|
||||
}
|
||||
|
||||
private fun setupFloatButtons() {
|
||||
// 浮动按钮组仅平板布局存在(layout-sw600dp),手机布局无这些 id,直接跳过
|
||||
val mainFloatButton = binding.mainFloatButton ?: return
|
||||
val maskView = binding.maskView ?: return
|
||||
val subButton1 = binding.subButton1 ?: return
|
||||
val subButton2 = binding.subButton2 ?: return
|
||||
|
||||
// 主按钮点击事件
|
||||
mainFloatButton.setOnClickListener {
|
||||
if (!isExpanded) {
|
||||
expandButtons()
|
||||
}
|
||||
}
|
||||
|
||||
// 遮罩层点击事件
|
||||
maskView.setOnClickListener {
|
||||
collapseButtons()
|
||||
}
|
||||
|
||||
// 子按钮1点击事件 - 跳转到出港运抵页面
|
||||
subButton1.setOnClickListener {
|
||||
com.alibaba.android.arouter.launcher.ARouter.getInstance()
|
||||
.build(ARouterConstants.ACTIVITY_URL_INT_EXP_ARRIVE)
|
||||
.navigation()
|
||||
collapseButtons()
|
||||
}
|
||||
|
||||
// 子按钮2点击事件 - 跳转到计重记录
|
||||
subButton2.setOnClickListener {
|
||||
com.alibaba.android.arouter.launcher.ARouter.getInstance()
|
||||
.build(ARouterConstants.ACTIVITY_URL_GJC_WEIGHING_RECORD_LIST)
|
||||
.navigation()
|
||||
collapseButtons()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 展开子按钮(仅平板,手机布局无浮动按钮组)
|
||||
*/
|
||||
private fun expandButtons() {
|
||||
val mainFloatButton = binding.mainFloatButton ?: return
|
||||
val maskView = binding.maskView ?: return
|
||||
val subButton1 = binding.subButton1 ?: return
|
||||
val subButton2 = binding.subButton2 ?: return
|
||||
|
||||
isExpanded = true
|
||||
|
||||
// 显示遮罩层
|
||||
maskView.visibility = View.VISIBLE
|
||||
maskView.alpha = 0f
|
||||
maskView.animate().alpha(0.3f).setDuration(200).start()
|
||||
|
||||
// 显示子按钮
|
||||
subButton1.visibility = View.VISIBLE
|
||||
subButton2.visibility = View.VISIBLE
|
||||
|
||||
// 子按钮1动画(向左上方移动: 左移15dp, 上移55dp)
|
||||
val sub1TransX = ObjectAnimator.ofFloat(subButton1, "translationX", 0f, -5f)
|
||||
val sub1TransY = ObjectAnimator.ofFloat(subButton1, "translationY", 0f, -25f)
|
||||
val sub1Alpha = ObjectAnimator.ofFloat(subButton1, "alpha", 0f, 1f)
|
||||
val sub1Scale = ObjectAnimator.ofFloat(subButton1, "scaleX", 0f, 1f)
|
||||
val sub1ScaleY = ObjectAnimator.ofFloat(subButton1, "scaleY", 0f, 1f)
|
||||
|
||||
val animSet1 = AnimatorSet()
|
||||
animSet1.playTogether(sub1TransX, sub1TransY, sub1Alpha, sub1Scale, sub1ScaleY)
|
||||
animSet1.duration = 200
|
||||
|
||||
// 子按钮2动画(向左下方移动: 左移55dp, 下移15dp)
|
||||
val sub2TransX = ObjectAnimator.ofFloat(subButton2, "translationX", 0f, -25f)
|
||||
val sub2TransY = ObjectAnimator.ofFloat(subButton2, "translationY", 0f, -5f)
|
||||
val sub2Alpha = ObjectAnimator.ofFloat(subButton2, "alpha", 0f, 1f)
|
||||
val sub2Scale = ObjectAnimator.ofFloat(subButton2, "scaleX", 0f, 1f)
|
||||
val sub2ScaleY = ObjectAnimator.ofFloat(subButton2, "scaleY", 0f, 1f)
|
||||
|
||||
val animSet2 = AnimatorSet()
|
||||
animSet2.playTogether(sub2TransX, sub2TransY, sub2Alpha, sub2Scale, sub2ScaleY)
|
||||
animSet2.duration = 200
|
||||
animSet2.startDelay = 50
|
||||
|
||||
// 主按钮隐藏动画
|
||||
mainFloatButton.animate()
|
||||
.scaleX(0f)
|
||||
.scaleY(0f)
|
||||
.alpha(0f)
|
||||
.setDuration(150)
|
||||
.setListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
mainFloatButton.visibility = View.GONE
|
||||
}
|
||||
})
|
||||
.start()
|
||||
|
||||
animSet1.start()
|
||||
animSet2.start()
|
||||
}
|
||||
|
||||
/**
|
||||
* 收起子按钮(仅平板,手机布局无浮动按钮组)
|
||||
*/
|
||||
private fun collapseButtons() {
|
||||
val mainFloatButton = binding.mainFloatButton ?: return
|
||||
val maskView = binding.maskView ?: return
|
||||
val subButton1 = binding.subButton1 ?: return
|
||||
val subButton2 = binding.subButton2 ?: return
|
||||
|
||||
isExpanded = false
|
||||
|
||||
// 隐藏遮罩层
|
||||
maskView.animate().alpha(0f).setDuration(200).withEndAction {
|
||||
maskView.visibility = View.GONE
|
||||
}.start()
|
||||
|
||||
// 子按钮1动画(回到原位)
|
||||
val sub1TransX = ObjectAnimator.ofFloat(subButton1, "translationX", subButton1.translationX, 0f)
|
||||
val sub1TransY = ObjectAnimator.ofFloat(subButton1, "translationY", subButton1.translationY, 0f)
|
||||
val sub1Alpha = ObjectAnimator.ofFloat(subButton1, "alpha", 1f, 0f)
|
||||
val sub1Scale = ObjectAnimator.ofFloat(subButton1, "scaleX", 1f, 0f)
|
||||
val sub1ScaleY = ObjectAnimator.ofFloat(subButton1, "scaleY", 1f, 0f)
|
||||
|
||||
val animSet1 = AnimatorSet()
|
||||
animSet1.playTogether(sub1TransX, sub1TransY, sub1Alpha, sub1Scale, sub1ScaleY)
|
||||
animSet1.duration = 200
|
||||
|
||||
// 子按钮2动画(回到原位)
|
||||
val sub2TransX = ObjectAnimator.ofFloat(subButton2, "translationX", subButton2.translationX, 0f)
|
||||
val sub2TransY = ObjectAnimator.ofFloat(subButton2, "translationY", subButton2.translationY, 0f)
|
||||
val sub2Alpha = ObjectAnimator.ofFloat(subButton2, "alpha", 1f, 0f)
|
||||
val sub2Scale = ObjectAnimator.ofFloat(subButton2, "scaleX", 1f, 0f)
|
||||
val sub2ScaleY = ObjectAnimator.ofFloat(subButton2, "scaleY", 1f, 0f)
|
||||
|
||||
val animSet2 = AnimatorSet()
|
||||
animSet2.playTogether(sub2TransX, sub2TransY, sub2Alpha, sub2Scale, sub2ScaleY)
|
||||
animSet2.duration = 200
|
||||
|
||||
animSet1.addListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
subButton1.visibility = View.GONE
|
||||
}
|
||||
})
|
||||
|
||||
animSet2.addListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
subButton2.visibility = View.GONE
|
||||
}
|
||||
})
|
||||
|
||||
// 主按钮显示动画
|
||||
mainFloatButton.visibility = View.VISIBLE
|
||||
mainFloatButton.animate()
|
||||
.scaleX(1f)
|
||||
.scaleY(1f)
|
||||
.alpha(1f)
|
||||
.setDuration(200)
|
||||
.setStartDelay(100)
|
||||
.setListener(null)
|
||||
.start()
|
||||
|
||||
animSet1.start()
|
||||
animSet2.start()
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* 启动开始计重页面
|
||||
* @param context 上下文
|
||||
* @param maWbId 运单ID,默认为0(新增模式)
|
||||
*/
|
||||
@JvmStatic
|
||||
fun startForAdd(context: Context, maWbId: Long = 0) {
|
||||
val starter = Intent(context, GjcWeighingStartActivity::class.java)
|
||||
.putExtra(Constant.Key.MAWB_ID, maWbId)
|
||||
context.startActivity(starter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,177 +1,170 @@
|
||||
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
|
||||
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 :
|
||||
BaseBindingActivity<ActivityIntExpArriveBinding, IntExpArriveViewModel>() {
|
||||
|
||||
@JvmField
|
||||
@Autowired
|
||||
var wbNoParam: String? = null
|
||||
|
||||
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()) {
|
||||
viewModel.waybillNo.value = wbNoParam
|
||||
viewModel.searchClick()
|
||||
}
|
||||
|
||||
// 绑定分页
|
||||
viewModel.pageModel.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, this)
|
||||
|
||||
// 设置item点击监听
|
||||
binding.rv.addOnItemClickListener(viewModel)
|
||||
|
||||
// 监听刷新事件
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_CHECK_CHANGED).observe(this) { viewModel.onItemCheckChanged() }
|
||||
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).observe(this) {
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
// 初始加载数据(如果没有传入运单号,才执行初始加载)
|
||||
if (wbNoParam.isNullOrEmpty()) {
|
||||
viewModel.refresh()
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 手机版专用交互(纯 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) {
|
||||
Constant.RequestCode.WAYBILL -> {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
viewModel.waybillNo.value = data?.getStringExtra(Constant.Result.CODED_CONTENT)
|
||||
viewModel.searchClick()
|
||||
}
|
||||
}
|
||||
Constant.RequestCode.CODE -> {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
viewModel.hno.value = data?.getStringExtra(Constant.Result.CODED_CONTENT)
|
||||
viewModel.searchClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
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 :
|
||||
BaseBindingActivity<ActivityIntExpArriveBinding, IntExpArriveViewModel>() {
|
||||
|
||||
@JvmField
|
||||
@Autowired
|
||||
var wbNoParam: String? = null
|
||||
|
||||
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(if (DeviceUtil.isPhone()) "出港运抵" else "国际出港运抵")
|
||||
binding.viewModel = viewModel
|
||||
binding.activity = this
|
||||
|
||||
// 手机版专属数据:加载「代理」筛选下拉
|
||||
// 平板端不调用,查询链路与请求次数与改造前完全一致
|
||||
if (DeviceUtil.isPhone()) {
|
||||
viewModel.initPhoneExtras()
|
||||
}
|
||||
|
||||
// 如果有传入运单号,自动填充并触发搜索
|
||||
if (!wbNoParam.isNullOrEmpty()) {
|
||||
viewModel.waybillNo.value = wbNoParam
|
||||
viewModel.searchClick()
|
||||
}
|
||||
|
||||
// 绑定分页
|
||||
viewModel.pageModel.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, this)
|
||||
|
||||
// 设置item点击监听
|
||||
binding.rv.addOnItemClickListener(viewModel)
|
||||
|
||||
// 监听刷新事件
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_CHECK_CHANGED).observe(this) { viewModel.onItemCheckChanged() }
|
||||
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).observe(this) {
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
// 初始加载数据(如果没有传入运单号,才执行初始加载)
|
||||
if (wbNoParam.isNullOrEmpty()) {
|
||||
viewModel.refresh()
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 手机版专用交互(纯 UI,复用既有 ViewModel 字段与数据) ====================
|
||||
|
||||
/**
|
||||
* 手机版 Tab 切换回调:PhoneStatusTab 已通过双向绑定写入 viewModel.currentTab,
|
||||
* 这里触发 ViewModel 把适配器数据集替换为过滤后的子集(不发起新请求)。
|
||||
*/
|
||||
fun onArriveTabChanged() {
|
||||
viewModel.onTabChangedPhone()
|
||||
}
|
||||
|
||||
/**
|
||||
* 卡片长按:展开操作浮层(View.OnLongClickListener 要求返回 Boolean)。
|
||||
* 仅已运抵 Tab 有操作(重置 / 回执);待运抵 Tab 的「补充信息」页后端确认暂不需要,已移除。
|
||||
*/
|
||||
fun showCardActionPhone(bean: GjcMaWb): Boolean {
|
||||
if (viewModel.currentTab.value != "shipped") return false
|
||||
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 = ""
|
||||
}
|
||||
|
||||
/** 手机版筛选:确认 */
|
||||
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)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
when (requestCode) {
|
||||
Constant.RequestCode.WAYBILL -> {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
viewModel.waybillNo.value = data?.getStringExtra(Constant.Result.CODED_CONTENT)
|
||||
viewModel.searchClick()
|
||||
}
|
||||
}
|
||||
Constant.RequestCode.CODE -> {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
viewModel.hno.value = data?.getStringExtra(Constant.Result.CODED_CONTENT)
|
||||
viewModel.searchClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +67,12 @@ class IntExpArriveSubOrderActivity :
|
||||
viewModel.resetSingleClick(bean)
|
||||
}
|
||||
|
||||
/** 长按菜单「回执」(单条):复用回执只读页,仅传当前分单 */
|
||||
fun openReceipt(bean: GjcHaWb) {
|
||||
bean.actionMenuVisible.set(false)
|
||||
IntExpArriveReceiptActivity.start(this, viewModel.wbNo, arrayListOf(bean))
|
||||
}
|
||||
|
||||
fun toggleFilterPanel() {
|
||||
filterPanelVisible.set(!filterPanelVisible.get())
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@ class IntExpOutHandoverActivity :
|
||||
val filterPanelVisible = ObservableBoolean(false)
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow("国际出港出库交接")
|
||||
setBackArrow(if (DeviceUtil.isPhone()) "出库交接" else "国际出港出库交接")
|
||||
binding.viewModel = viewModel
|
||||
binding.activity = this
|
||||
|
||||
@@ -72,12 +72,12 @@ class IntExpOutHandoverActivity :
|
||||
/**
|
||||
* 手机版筛选:重置
|
||||
*
|
||||
* 只清空弹层内的三个条件(航班日期 / 航班号 / 交接人),不影响 Tab 与顶部搜索框。
|
||||
* 只清空弹层内的三个条件(航班日期 / 航班号 / 目的站),不影响 Tab 与顶部搜索框。
|
||||
*/
|
||||
fun resetFilter() {
|
||||
viewModel.flightDate.value = ""
|
||||
viewModel.flightNo.value = ""
|
||||
viewModel.hoId.value = ""
|
||||
viewModel.fdest.value = ""
|
||||
}
|
||||
|
||||
/** 手机版筛选:确认 */
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.lukouguoji.gjc.activity
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.lukouguoji.gjc.R
|
||||
import com.lukouguoji.gjc.databinding.ActivityIntExpStorageUseBinding
|
||||
@@ -18,7 +17,9 @@ import com.lukouguoji.module_base.impl.FlowBus
|
||||
import com.lukouguoji.module_base.impl.observe
|
||||
import com.lukouguoji.module_base.ktx.commonAdapter
|
||||
import com.lukouguoji.module_base.ktx.showToast
|
||||
import com.lukouguoji.module_base.model.ConfirmDialogModel
|
||||
import com.lukouguoji.module_base.router.ARouterConstants
|
||||
import com.lukouguoji.module_base.util.DeviceUtil
|
||||
|
||||
/**
|
||||
* 国际出港-仓库
|
||||
@@ -31,10 +32,13 @@ class IntExpStorageUseActivity :
|
||||
override fun viewModelClass() = IntExpStorageUseViewModel::class.java
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow("国际出港仓库")
|
||||
setBackArrow(if (DeviceUtil.isPhone()) "出港仓库" else "国际出港仓库")
|
||||
binding.viewModel = viewModel
|
||||
binding.activity = this
|
||||
|
||||
// 手机形态专属:筛选字典 + 未清仓/已清仓分项统计(平板不调用,行为零变化)
|
||||
if (DeviceUtil.isPhone()) viewModel.initPhoneExtras()
|
||||
|
||||
// 绑定分页
|
||||
viewModel.pageModel.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, this)
|
||||
|
||||
@@ -139,15 +143,60 @@ class IntExpStorageUseActivity :
|
||||
}
|
||||
|
||||
// 显示二次确认对话框
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle("出库确认")
|
||||
.setMessage("确定要将选中的 ${selectedStorageUseList.size} 个库位执行出库操作吗?")
|
||||
.setPositiveButton("确定") { _, _ ->
|
||||
// 用户确认后,执行出库操作
|
||||
viewModel.performOutStorage(selectedStorageUseList)
|
||||
}
|
||||
.setNegativeButton("取消", null)
|
||||
.show()
|
||||
ConfirmDialogModel(
|
||||
message = "确定要将选中的 ${selectedStorageUseList.size} 个库位执行出库操作吗?",
|
||||
title = "出库确认"
|
||||
) {
|
||||
// 用户确认后,执行出库操作
|
||||
viewModel.performOutStorage(selectedStorageUseList)
|
||||
}.show(this)
|
||||
}
|
||||
|
||||
// ==================== 5.5寸手机版:卡片级操作 ====================
|
||||
// 语义等价于「勾选该主单 + 其全部库位」再执行平板的批量操作,复用 performXxx 请求链路。
|
||||
|
||||
/** 卡片「清仓」(已清仓的卡片按钮置灰,ViewHolder 已拦截) */
|
||||
fun cardClear(bean: com.lukouguoji.module_base.bean.GjcMaWb) {
|
||||
val maWbListForClear = listOf(bean.copy(storageUseList = bean.storageUseList ?: emptyList()))
|
||||
IntExpMoveClearDialogModel { dialog ->
|
||||
viewModel.performClear(dialog.clearNormal.value ?: "", maWbListForClear)
|
||||
}.show(this)
|
||||
}
|
||||
|
||||
/** 卡片「修改库位」:弹层内先单选原库位(单库位时默认选中)再选新库位 */
|
||||
fun cardModifyStorage(bean: com.lukouguoji.module_base.bean.GjcMaWb) {
|
||||
val storageList = bean.storageUseList ?: emptyList()
|
||||
if (storageList.isEmpty()) {
|
||||
showToast("该运单暂无库位")
|
||||
return
|
||||
}
|
||||
IntExpModifyStorageDialogModel(sourceStorageList = storageList) { dialog ->
|
||||
val sourceStorage = dialog.selectedSourceStorage ?: return@IntExpModifyStorageDialogModel
|
||||
viewModel.performModifyStorage(dialog.locationName, dialog.locationId, sourceStorage)
|
||||
}.show(this)
|
||||
}
|
||||
|
||||
/** 卡片「出库」:该运单全部库位出库(与平板勾选主单后出库同语义) */
|
||||
fun cardOutStorage(bean: com.lukouguoji.module_base.bean.GjcMaWb) {
|
||||
val storageList = bean.storageUseList ?: emptyList()
|
||||
if (storageList.isEmpty()) {
|
||||
showToast("该运单暂无库位")
|
||||
return
|
||||
}
|
||||
ConfirmDialogModel(
|
||||
message = "确定要将运单 ${bean.wbNo} 的 ${storageList.size} 个库位执行出库操作吗?",
|
||||
title = "出库确认"
|
||||
) {
|
||||
viewModel.performOutStorage(storageList)
|
||||
}.show(this)
|
||||
}
|
||||
|
||||
/** 卡片「入库」:弹层选库位后整票入库 */
|
||||
fun cardInStorage(bean: com.lukouguoji.module_base.bean.GjcMaWb) {
|
||||
val maWbListForInStorage = listOf(bean.copy(storageUseList = bean.storageUseList ?: emptyList()))
|
||||
IntExpInStorageDialogModel { dialog ->
|
||||
viewModel.performInStorage(dialog.locationName, dialog.locationId, maWbListForInStorage)
|
||||
}.show(this)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,14 +6,20 @@ import com.lukouguoji.gjc.R
|
||||
import com.lukouguoji.gjc.databinding.DialogIntExpArriveResetBinding
|
||||
import com.lukouguoji.module_base.base.BaseDialogModel
|
||||
import com.lukouguoji.module_base.ktx.verifyNullOrEmpty
|
||||
import com.lukouguoji.module_base.util.DeviceUtil
|
||||
import dev.utils.app.info.KeyValue
|
||||
|
||||
/**
|
||||
* 国际出港运抵 - 状态重置对话框
|
||||
*
|
||||
* 布局按资源限定符自动切换:手机 layout/(底部弹层)、平板 layout-sw600dp/(居中弹框),
|
||||
* 弹出位置随形态选择 BOTTOM/CENTER。
|
||||
*/
|
||||
class IntExpArriveResetDialogModel(
|
||||
private val callback: (IntExpArriveResetDialogModel) -> Unit
|
||||
) : BaseDialogModel<DialogIntExpArriveResetBinding>(DIALOG_TYPE_CENTER) {
|
||||
) : BaseDialogModel<DialogIntExpArriveResetBinding>(
|
||||
if (DeviceUtil.isPhone()) DIALOG_TYPE_BOTTOM else DIALOG_TYPE_CENTER
|
||||
) {
|
||||
|
||||
// 重置状态列表
|
||||
val resetStatusList = MutableLiveData<List<KeyValue>>()
|
||||
|
||||
@@ -9,14 +9,18 @@ import com.lukouguoji.module_base.http.net.NetApply
|
||||
import com.lukouguoji.module_base.ktx.launchCollect
|
||||
import com.lukouguoji.module_base.ktx.showToast
|
||||
import com.lukouguoji.module_base.ktx.verifyNullOrEmpty
|
||||
import com.lukouguoji.module_base.util.DeviceUtil
|
||||
import dev.utils.app.info.KeyValue
|
||||
|
||||
/**
|
||||
* 国际出港仓库 - 入库操作对话框
|
||||
* 手机为底部弹层(layout/ 变体),平板为居中弹框(layout-sw600dp/ 变体)
|
||||
*/
|
||||
class IntExpInStorageDialogModel(
|
||||
private val callback: (IntExpInStorageDialogModel) -> Unit
|
||||
) : BaseDialogModel<DialogIntExpInStorageBinding>(DIALOG_TYPE_CENTER) {
|
||||
) : BaseDialogModel<DialogIntExpInStorageBinding>(
|
||||
if (DeviceUtil.isPhone()) DIALOG_TYPE_BOTTOM else DIALOG_TYPE_CENTER
|
||||
) {
|
||||
|
||||
// 库位列表
|
||||
val locationList = MutableLiveData<List<KeyValue>>()
|
||||
|
||||
@@ -8,15 +8,24 @@ import com.lukouguoji.module_base.base.BaseDialogModel
|
||||
import com.lukouguoji.module_base.http.net.NetApply
|
||||
import com.lukouguoji.module_base.ktx.launchCollect
|
||||
import com.lukouguoji.module_base.ktx.showToast
|
||||
import com.lukouguoji.module_base.bean.GjcStorageUse
|
||||
import com.lukouguoji.module_base.ktx.verifyNullOrEmpty
|
||||
import com.lukouguoji.module_base.util.DeviceUtil
|
||||
import dev.utils.app.info.KeyValue
|
||||
|
||||
/**
|
||||
* 国际出港 - 修改库位对话框
|
||||
* 手机为底部弹层(layout/ 变体),平板为居中弹框(layout-sw600dp/ 变体)。
|
||||
*
|
||||
* 平板:列表勾选唯一库位后打开,弹框内只选新库位(sourceStorageList 传 null,原库位项不存在于平板布局)。
|
||||
* 手机:卡片级操作,运单可能有多个库位——传入该运单库位列表,弹层内先单选「原库位」再选新库位。
|
||||
*/
|
||||
class IntExpModifyStorageDialogModel(
|
||||
private val sourceStorageList: List<GjcStorageUse>? = null,
|
||||
private val callback: (IntExpModifyStorageDialogModel) -> Unit
|
||||
) : BaseDialogModel<DialogIntExpModifyStorageBinding>(DIALOG_TYPE_CENTER) {
|
||||
) : BaseDialogModel<DialogIntExpModifyStorageBinding>(
|
||||
if (DeviceUtil.isPhone()) DIALOG_TYPE_BOTTOM else DIALOG_TYPE_CENTER
|
||||
) {
|
||||
|
||||
// 库位列表
|
||||
val locationList = MutableLiveData<List<KeyValue>>()
|
||||
@@ -30,6 +39,13 @@ class IntExpModifyStorageDialogModel(
|
||||
// 库位名称 (后端需要的name)
|
||||
var locationName: String = ""
|
||||
|
||||
// ========== 手机卡片级操作专属:原库位单选 ==========
|
||||
val sourceList = MutableLiveData<List<KeyValue>>(emptyList())
|
||||
val selectedSourceId = MutableLiveData("")
|
||||
|
||||
// 选中的原库位对象(保存后由调用方取用)
|
||||
var selectedSourceStorage: GjcStorageUse? = null
|
||||
|
||||
override fun layoutId(): Int {
|
||||
return R.layout.dialog_int_exp_modify_storage
|
||||
}
|
||||
@@ -44,6 +60,19 @@ class IntExpModifyStorageDialogModel(
|
||||
locationId = selectedItem?.value ?: ""
|
||||
locationName = selectedItem?.key ?: ""
|
||||
}
|
||||
|
||||
// 手机版:初始化原库位列表,单库位时默认选中
|
||||
if (sourceStorageList != null) {
|
||||
sourceList.value = sourceStorageList.map {
|
||||
KeyValue(it.location ?: "", it.id?.toString() ?: "")
|
||||
}
|
||||
selectedSourceId.observeForever { id ->
|
||||
selectedSourceStorage = sourceStorageList.find { it.id?.toString() == id }
|
||||
}
|
||||
if (sourceStorageList.size == 1) {
|
||||
selectedSourceId.value = sourceStorageList[0].id?.toString() ?: ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,6 +94,10 @@ class IntExpModifyStorageDialogModel(
|
||||
* 保存按钮点击
|
||||
*/
|
||||
fun onSaveClick() {
|
||||
if (sourceStorageList != null && selectedSourceStorage == null) {
|
||||
showToast("请选择原库位")
|
||||
return
|
||||
}
|
||||
if (selectedLocationCode.value.verifyNullOrEmpty("请选择库位")) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -6,14 +6,18 @@ import com.lukouguoji.gjc.R
|
||||
import com.lukouguoji.gjc.databinding.DialogIntExpMoveClearBinding
|
||||
import com.lukouguoji.module_base.base.BaseDialogModel
|
||||
import com.lukouguoji.module_base.ktx.verifyNullOrEmpty
|
||||
import com.lukouguoji.module_base.util.DeviceUtil
|
||||
import dev.utils.app.info.KeyValue
|
||||
|
||||
/**
|
||||
* 国际出港移库 - 清仓操作对话框
|
||||
* 手机为底部弹层(layout/ 变体),平板为居中弹框(layout-sw600dp/ 变体)
|
||||
*/
|
||||
class IntExpMoveClearDialogModel(
|
||||
private val callback: (IntExpMoveClearDialogModel) -> Unit
|
||||
) : BaseDialogModel<DialogIntExpMoveClearBinding>(DIALOG_TYPE_CENTER) {
|
||||
) : BaseDialogModel<DialogIntExpMoveClearBinding>(
|
||||
if (DeviceUtil.isPhone()) DIALOG_TYPE_BOTTOM else DIALOG_TYPE_CENTER
|
||||
) {
|
||||
|
||||
// 清仓正常(存储的是 code:"0" 或 "1")
|
||||
val clearNormal = MutableLiveData("")
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.lukouguoji.gjc.holder
|
||||
|
||||
import android.view.View
|
||||
import com.lukouguoji.gjc.R
|
||||
import com.lukouguoji.gjc.activity.GjcQueryDetailsActivity
|
||||
import com.lukouguoji.gjc.activity.IntExpStorageUseActivity
|
||||
import com.lukouguoji.gjc.databinding.ItemIntExpStorageUseBinding
|
||||
import com.lukouguoji.module_base.adapter.setCommonAdapter
|
||||
import com.lukouguoji.module_base.base.BaseViewHolder
|
||||
@@ -12,6 +14,10 @@ import com.lukouguoji.module_base.ktx.refresh
|
||||
|
||||
/**
|
||||
* 国际出港-仓库 ViewHolder
|
||||
*
|
||||
* 双形态布局:平板变体含 iv_icon/iv_show/rv_sub(多选 + 库位子列表),手机变体含
|
||||
* ll/btn_clear/btn_modify/btn_out/btn_in(整卡进详情 + 卡片级四操作按钮)。
|
||||
* 单侧独有的 id 在 Binding 基类中为 @Nullable,必须判空访问。
|
||||
*/
|
||||
class IntExpStorageUseViewHolder(view: View) :
|
||||
BaseViewHolder<GjcMaWb, ItemIntExpStorageUseBinding>(view) {
|
||||
@@ -22,8 +28,10 @@ class IntExpStorageUseViewHolder(view: View) :
|
||||
binding.position = position
|
||||
binding.executePendingBindings()
|
||||
|
||||
// ==================== 平板:多选 + 子列表 ====================
|
||||
|
||||
// 图标点击切换选择状态(联动子列表)
|
||||
binding.ivIcon.setOnClickListener {
|
||||
binding.ivIcon?.setOnClickListener {
|
||||
// 切换主列表项的选择状态
|
||||
val newCheckedState = !bean.checked.get()
|
||||
bean.checked.set(newCheckedState)
|
||||
@@ -37,25 +45,45 @@ class IntExpStorageUseViewHolder(view: View) :
|
||||
|
||||
// 刷新UI
|
||||
binding.executePendingBindings()
|
||||
binding.rvSub.adapter?.notifyDataSetChanged()
|
||||
binding.rvSub?.adapter?.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
// 展开按钮点击事件
|
||||
binding.ivShow.setOnClickListener {
|
||||
binding.ivShow?.setOnClickListener {
|
||||
bean.showMore.set(!bean.showMore.get())
|
||||
}
|
||||
|
||||
// 初始化库位明细子列表 RecyclerView
|
||||
setCommonAdapter(
|
||||
binding.rvSub,
|
||||
IntExpStorageUseSubViewHolder::class.java,
|
||||
R.layout.item_int_exp_storage_use_sub
|
||||
)
|
||||
binding.rvSub?.let { rvSub ->
|
||||
setCommonAdapter(
|
||||
rvSub,
|
||||
IntExpStorageUseSubViewHolder::class.java,
|
||||
R.layout.item_int_exp_storage_use_sub
|
||||
)
|
||||
|
||||
// 刷新库位明细数据(传递父Bean引用)
|
||||
val storageUseList = bean.storageUseList ?: emptyList()
|
||||
// 为每个子列表项设置父Bean引用(通过tag传递)
|
||||
binding.rvSub.tag = bean
|
||||
binding.rvSub.refresh(storageUseList)
|
||||
// 刷新库位明细数据(传递父Bean引用)
|
||||
val storageUseList = bean.storageUseList ?: emptyList()
|
||||
// 为每个子列表项设置父Bean引用(通过tag传递)
|
||||
rvSub.tag = bean
|
||||
rvSub.refresh(storageUseList)
|
||||
}
|
||||
|
||||
// ==================== 手机:整卡进详情 + 卡片级操作 ====================
|
||||
|
||||
val activity = itemView.context as? IntExpStorageUseActivity
|
||||
|
||||
// 整卡点击进详情(复用出港查询详情页,3 Tab 运单/仓库/库位信息)
|
||||
binding.ll?.setOnClickListener {
|
||||
GjcQueryDetailsActivity.start(itemView.context, bean.maWbId)
|
||||
}
|
||||
|
||||
// 清仓(已清仓时置灰不可点,样式由 XML 按 bean.isCleared 切换)
|
||||
binding.btnClear?.setOnClickListener {
|
||||
if (!bean.isCleared) activity?.cardClear(bean)
|
||||
}
|
||||
|
||||
binding.btnModify?.setOnClickListener { activity?.cardModifyStorage(bean) }
|
||||
binding.btnOut?.setOnClickListener { activity?.cardOutStorage(bean) }
|
||||
binding.btnIn?.setOnClickListener { activity?.cardInStorage(bean) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,171 +1,171 @@
|
||||
package com.lukouguoji.gjc.page.move
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.databinding.ObservableBoolean
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.lukouguoji.gjc.R
|
||||
import com.lukouguoji.gjc.databinding.ActivityIntExpMoveBinding
|
||||
import com.lukouguoji.gjc.viewModel.IntExpMoveViewModel
|
||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||
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.showToast
|
||||
import com.lukouguoji.module_base.model.ConfirmDialogModel
|
||||
import com.lukouguoji.module_base.model.ScanModel
|
||||
import com.lukouguoji.module_base.router.ARouterConstants
|
||||
import com.lukouguoji.module_base.util.DeviceUtil
|
||||
|
||||
/**
|
||||
* 国际出港-出港移库
|
||||
*/
|
||||
@Route(path = ARouterConstants.ACTIVITY_URL_INT_EXP_MOVE)
|
||||
class IntExpMoveActivity : BaseBindingActivity<ActivityIntExpMoveBinding, IntExpMoveViewModel>() {
|
||||
|
||||
// 布局 id 不区分设备,平板/手机由资源限定符自动选择:
|
||||
// layout-sw600dp/activity_int_exp_move.xml(平板) / layout/activity_int_exp_move.xml(手机)
|
||||
override fun layoutId() = R.layout.activity_int_exp_move
|
||||
|
||||
override fun viewModelClass() = IntExpMoveViewModel::class.java
|
||||
|
||||
/** 手机版筛选弹层显隐(仅 UI 状态,不涉及业务逻辑) */
|
||||
val filterPanelVisible = ObservableBoolean(false)
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow("国际出港移库")
|
||||
binding.viewModel = viewModel
|
||||
binding.activity = this
|
||||
|
||||
// 手机版专属数据:默认「待移库」Tab、Tab 角标计数、特码下拉
|
||||
// 平板端不调用,查询链路与请求次数与改造前完全一致
|
||||
if (DeviceUtil.isPhone()) {
|
||||
viewModel.initPhoneExtras()
|
||||
}
|
||||
|
||||
initRecyclerView()
|
||||
initListeners()
|
||||
observeData()
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化RecyclerView
|
||||
*/
|
||||
private fun initRecyclerView() {
|
||||
viewModel.pageModel.bindSmartRefreshLayout(
|
||||
binding.srl,
|
||||
binding.rv,
|
||||
viewModel,
|
||||
this
|
||||
)
|
||||
binding.rv.addOnItemClickListener(viewModel)
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化监听器
|
||||
*/
|
||||
private fun initListeners() {
|
||||
// 移库按钮:btnMove 只存在于平板变体(手机版底部条走 setOnActionClick),故判空
|
||||
binding.btnMove?.setOnClickListener {
|
||||
showMoveConfirmDialog()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 观察数据变化
|
||||
*/
|
||||
private fun observeData() {
|
||||
// 监听item选择变化事件,更新全选状态
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_CHECK_CHANGED).observe(this) {
|
||||
viewModel.onItemCheckChanged()
|
||||
}
|
||||
|
||||
// 监听刷新事件
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).observe(this) {
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
// 初始加载数据
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫码运单号
|
||||
*/
|
||||
fun scanWaybill() {
|
||||
ScanModel.startScan(this, Constant.RequestCode.WAYBILL)
|
||||
}
|
||||
|
||||
// ==================== 手机版专用交互(复用既有 ViewModel 字段,无新增业务逻辑) ====================
|
||||
|
||||
/**
|
||||
* 手机版筛选弹层显隐切换
|
||||
*/
|
||||
fun toggleFilterPanel() {
|
||||
filterPanelVisible.set(!filterPanelVisible.get())
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机版筛选:重置
|
||||
*
|
||||
* 只清空弹层内的三个条件(承运人 / 运单类型 / 特码),不影响 Tab 与顶部搜索框。
|
||||
*/
|
||||
fun resetFilter() {
|
||||
viewModel.by1.value = ""
|
||||
viewModel.awbType.value = ""
|
||||
viewModel.spCode.value = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机版筛选:确定
|
||||
*/
|
||||
fun confirmFilter() {
|
||||
filterPanelVisible.set(false)
|
||||
viewModel.searchClick()
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示移库确认对话框
|
||||
*
|
||||
* 手机版底部操作条通过 XML 的 setOnActionClick 调用,故为 public。
|
||||
*/
|
||||
fun showMoveConfirmDialog() {
|
||||
val selectedItems = viewModel.getSelectedItems()
|
||||
|
||||
if (selectedItems.isEmpty()) {
|
||||
showToast("请至少选择一条运单")
|
||||
return
|
||||
}
|
||||
|
||||
ConfirmDialogModel(
|
||||
message = "确定要移库选中的 ${selectedItems.size} 条运单吗?",
|
||||
title = "移库确认"
|
||||
) {
|
||||
viewModel.submitMove()
|
||||
}.show()
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫码回调
|
||||
*/
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == Constant.RequestCode.WAYBILL && resultCode == Activity.RESULT_OK) {
|
||||
val code = data?.getStringExtra(Constant.Result.CODED_CONTENT)
|
||||
viewModel.waybillNo.value = code
|
||||
viewModel.searchClick()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun start(context: Context) {
|
||||
val starter = Intent(context, IntExpMoveActivity::class.java)
|
||||
context.startActivity(starter)
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.lukouguoji.gjc.page.move
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.databinding.ObservableBoolean
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.lukouguoji.gjc.R
|
||||
import com.lukouguoji.gjc.databinding.ActivityIntExpMoveBinding
|
||||
import com.lukouguoji.gjc.viewModel.IntExpMoveViewModel
|
||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||
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.showToast
|
||||
import com.lukouguoji.module_base.model.ConfirmDialogModel
|
||||
import com.lukouguoji.module_base.model.ScanModel
|
||||
import com.lukouguoji.module_base.router.ARouterConstants
|
||||
import com.lukouguoji.module_base.util.DeviceUtil
|
||||
|
||||
/**
|
||||
* 国际出港-出港移库
|
||||
*/
|
||||
@Route(path = ARouterConstants.ACTIVITY_URL_INT_EXP_MOVE)
|
||||
class IntExpMoveActivity : BaseBindingActivity<ActivityIntExpMoveBinding, IntExpMoveViewModel>() {
|
||||
|
||||
// 布局 id 不区分设备,平板/手机由资源限定符自动选择:
|
||||
// layout-sw600dp/activity_int_exp_move.xml(平板) / layout/activity_int_exp_move.xml(手机)
|
||||
override fun layoutId() = R.layout.activity_int_exp_move
|
||||
|
||||
override fun viewModelClass() = IntExpMoveViewModel::class.java
|
||||
|
||||
/** 手机版筛选弹层显隐(仅 UI 状态,不涉及业务逻辑) */
|
||||
val filterPanelVisible = ObservableBoolean(false)
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow(if (DeviceUtil.isPhone()) "出港移库" else "国际出港移库")
|
||||
binding.viewModel = viewModel
|
||||
binding.activity = this
|
||||
|
||||
// 手机版专属数据:默认「待移库」Tab、Tab 角标计数、特码下拉
|
||||
// 平板端不调用,查询链路与请求次数与改造前完全一致
|
||||
if (DeviceUtil.isPhone()) {
|
||||
viewModel.initPhoneExtras()
|
||||
}
|
||||
|
||||
initRecyclerView()
|
||||
initListeners()
|
||||
observeData()
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化RecyclerView
|
||||
*/
|
||||
private fun initRecyclerView() {
|
||||
viewModel.pageModel.bindSmartRefreshLayout(
|
||||
binding.srl,
|
||||
binding.rv,
|
||||
viewModel,
|
||||
this
|
||||
)
|
||||
binding.rv.addOnItemClickListener(viewModel)
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化监听器
|
||||
*/
|
||||
private fun initListeners() {
|
||||
// 移库按钮:btnMove 只存在于平板变体(手机版底部条走 setOnActionClick),故判空
|
||||
binding.btnMove?.setOnClickListener {
|
||||
showMoveConfirmDialog()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 观察数据变化
|
||||
*/
|
||||
private fun observeData() {
|
||||
// 监听item选择变化事件,更新全选状态
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_CHECK_CHANGED).observe(this) {
|
||||
viewModel.onItemCheckChanged()
|
||||
}
|
||||
|
||||
// 监听刷新事件
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).observe(this) {
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
// 初始加载数据
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫码运单号
|
||||
*/
|
||||
fun scanWaybill() {
|
||||
ScanModel.startScan(this, Constant.RequestCode.WAYBILL)
|
||||
}
|
||||
|
||||
// ==================== 手机版专用交互(复用既有 ViewModel 字段,无新增业务逻辑) ====================
|
||||
|
||||
/**
|
||||
* 手机版筛选弹层显隐切换
|
||||
*/
|
||||
fun toggleFilterPanel() {
|
||||
filterPanelVisible.set(!filterPanelVisible.get())
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机版筛选:重置
|
||||
*
|
||||
* 只清空弹层内的三个条件(承运人 / 运单类型 / 特码),不影响 Tab 与顶部搜索框。
|
||||
*/
|
||||
fun resetFilter() {
|
||||
viewModel.by1.value = ""
|
||||
viewModel.awbType.value = ""
|
||||
viewModel.spCode.value = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机版筛选:确定
|
||||
*/
|
||||
fun confirmFilter() {
|
||||
filterPanelVisible.set(false)
|
||||
viewModel.searchClick()
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示移库确认对话框
|
||||
*
|
||||
* 手机版底部操作条通过 XML 的 setOnActionClick 调用,故为 public。
|
||||
*/
|
||||
fun showMoveConfirmDialog() {
|
||||
val selectedItems = viewModel.getSelectedItems()
|
||||
|
||||
if (selectedItems.isEmpty()) {
|
||||
showToast("请至少选择一条运单")
|
||||
return
|
||||
}
|
||||
|
||||
ConfirmDialogModel(
|
||||
message = "确定要移库选中的 ${selectedItems.size} 条运单吗?",
|
||||
title = "移库确认"
|
||||
) {
|
||||
viewModel.submitMove()
|
||||
}.show()
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫码回调
|
||||
*/
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == Constant.RequestCode.WAYBILL && resultCode == Activity.RESULT_OK) {
|
||||
val code = data?.getStringExtra(Constant.Result.CODED_CONTENT)
|
||||
viewModel.waybillNo.value = code
|
||||
viewModel.searchClick()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun start(context: Context) {
|
||||
val starter = Intent(context, IntExpMoveActivity::class.java)
|
||||
context.startActivity(starter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,11 @@ class GjcQueryDetailsViewModel : BaseViewModel() {
|
||||
// 库位列表 (storageUseList)
|
||||
val storageUseList = MutableLiveData<List<Map<String, Any>>>(emptyList())
|
||||
|
||||
// ==================== 5.5寸手机版专属(展示用,平板布局不绑定) ====================
|
||||
// 入库件数/入库重量 = warehouseList 各批次求和(设计稿「件重信息」区块)
|
||||
val inPcTotal = MutableLiveData("--")
|
||||
val inWeightTotal = MutableLiveData("--")
|
||||
|
||||
// ==================== Fragment列表 ====================
|
||||
val fragmentList by lazy {
|
||||
listOf(
|
||||
@@ -59,6 +64,40 @@ class GjcQueryDetailsViewModel : BaseViewModel() {
|
||||
currentTab.value = index
|
||||
}
|
||||
|
||||
// ==================== 5.5寸手机版取值帮助方法(布局绑定用) ====================
|
||||
// 表达式里必须把 map(maWbData)作为参数传入,DataBinding 才能追踪依赖并在数据到达后刷新
|
||||
|
||||
/**
|
||||
* 从详情 Map 取字符串展示值;数字自动去掉无意义的 .0;空值兜底 "--"
|
||||
*/
|
||||
fun str(map: Map<String, Any>?, key: String): String {
|
||||
val v = map?.get(key) ?: return "--"
|
||||
val s = when (v) {
|
||||
is Double -> if (v % 1.0 == 0.0) v.toLong().toString() else v.toString()
|
||||
else -> v.toString()
|
||||
}
|
||||
return s.ifBlank { "--" }
|
||||
}
|
||||
|
||||
/**
|
||||
* 依次取第一个非空 key 的展示值(如 agentName 优先于 agentCode)
|
||||
*/
|
||||
fun strOr(map: Map<String, Any>?, key: String, fallbackKey: String): String {
|
||||
val first = str(map, key)
|
||||
return if (first != "--") first else str(map, fallbackKey)
|
||||
}
|
||||
|
||||
/**
|
||||
* 取重量类数值(保留小数形式),空值兜底 "--"
|
||||
*/
|
||||
fun dec(map: Map<String, Any>?, key: String): String {
|
||||
val v = map?.get(key) ?: return "--"
|
||||
return when (v) {
|
||||
is Double -> v.toString()
|
||||
else -> v.toString().ifBlank { "--" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载详情数据
|
||||
*/
|
||||
@@ -111,6 +150,17 @@ class GjcQueryDetailsViewModel : BaseViewModel() {
|
||||
val whList = data["warehouseList"] as? List<Map<String, Any>> ?: emptyList()
|
||||
warehouseList.value = whList
|
||||
|
||||
// 手机版「入库件数/入库重量」= 各批次求和(Gson 反序列化数字均为 Double)
|
||||
if (whList.isNotEmpty()) {
|
||||
val pcSum = whList.sumOf { (it["pc"] as? Double) ?: 0.0 }
|
||||
val weightSum = whList.sumOf { (it["weight"] as? Double) ?: 0.0 }
|
||||
inPcTotal.value = pcSum.toLong().toString()
|
||||
inWeightTotal.value = weightSum.toString()
|
||||
} else {
|
||||
inPcTotal.value = "--"
|
||||
inWeightTotal.value = "--"
|
||||
}
|
||||
|
||||
// 解析 storageUseList 列表
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val suList = data["storageUseList"] as? List<Map<String, Any>> ?: emptyList()
|
||||
|
||||
@@ -76,6 +76,34 @@ class GjcQueryViewModel : BasePageViewModel() {
|
||||
val businessType = MutableLiveData("") // 业务类型
|
||||
val goodsCn = MutableLiveData("") // 品名(中)
|
||||
|
||||
// ==================== 5.5寸手机版专属 ====================
|
||||
// 特码下拉列表(设计稿筛选弹层为下拉;平板筛选为文本输入,不加载)
|
||||
val specialCodeList = MutableLiveData<List<KeyValue>>(emptyList())
|
||||
|
||||
// 三格统计:总票数 / 已入库 / 已离港,均取 pageQueryTotal 出参(wbNumber / storedNumber / departedNumber),
|
||||
// 与列表同条件、服务端全量口径
|
||||
val storedCount = MutableLiveData("0")
|
||||
val departedCount = MutableLiveData("0")
|
||||
|
||||
// 日期类型(0:入库,1:离港),与主干平板端一致。后端 beginDate/endDate 仅在携带 dateState 时生效
|
||||
// (内网实测:不带 dateState 时起止日期被忽略)。平板布局(本分支)不绑定,phoneExtras 关闭时不进请求
|
||||
val dateState = MutableLiveData("0")
|
||||
val dateStateList = MutableLiveData(listOf(KeyValue("入库", "0"), KeyValue("离港", "1")))
|
||||
|
||||
private var phoneExtrasEnabled = false
|
||||
|
||||
/**
|
||||
* 手机形态专属初始化(Activity 在 DeviceUtil.isPhone() 时调用)。
|
||||
* 平板端不调用,请求次数与行为零变化。
|
||||
*/
|
||||
fun initPhoneExtras() {
|
||||
phoneExtrasEnabled = true
|
||||
// flag=1 国际;ieFlag 必须留空——传 "E" 后端返回空数组(与既有国际出港页面口径一致)
|
||||
DictUtils.getSpecialCodeList(addAll = false, flag = 1, ieFlag = "") { list ->
|
||||
specialCodeList.postValue(listOf(KeyValue("全部", "")) + list)
|
||||
}
|
||||
}
|
||||
|
||||
// 是否有筛选条件(任意一个非空则为 true,用于筛选按钮红点)
|
||||
val hasFilter: MediatorLiveData<Boolean> = MediatorLiveData<Boolean>().apply {
|
||||
val update = { _: Any? ->
|
||||
@@ -160,10 +188,15 @@ class GjcQueryViewModel : BasePageViewModel() {
|
||||
* 核心方法:调用API获取数据并转换PageInfo为BaseListBean
|
||||
*/
|
||||
override fun getData() {
|
||||
// 手机版:日期类型,仅在有起止日期时携带(平板 phoneExtrasEnabled 恒 false → null 不进请求)
|
||||
val hasDate = !flightDateStart.value.isNullOrEmpty() || !flightDateEnd.value.isNullOrEmpty()
|
||||
val dateStateParam = if (phoneExtrasEnabled && hasDate) dateState.value?.toIntOrNull() else null
|
||||
|
||||
// 构建查询参数(列表接口)
|
||||
val listParams = mapOf(
|
||||
"pageNum" to pageModel.page,
|
||||
"pageSize" to pageModel.limit,
|
||||
"dateState" to dateStateParam,
|
||||
"beginDate" to flightDateStart.value!!.ifEmpty { null },
|
||||
"endDate" to flightDateEnd.value!!.ifEmpty { null },
|
||||
"agentCode" to agentId.value!!.ifEmpty { null },
|
||||
@@ -180,6 +213,7 @@ class GjcQueryViewModel : BasePageViewModel() {
|
||||
|
||||
// 构建查询参数(统计接口 - 使用相同的搜索条件)
|
||||
val totalParams = mapOf(
|
||||
"dateState" to dateStateParam,
|
||||
"beginDate" to flightDateStart.value!!.ifEmpty { null },
|
||||
"endDate" to flightDateEnd.value!!.ifEmpty { null },
|
||||
"agentCode" to agentId.value!!.ifEmpty { null },
|
||||
@@ -213,6 +247,9 @@ class GjcQueryViewModel : BasePageViewModel() {
|
||||
totalCount.value = (data?.wbNumber ?: 0).toString()
|
||||
totalPc.value = (data?.totalPc ?: 0).toString()
|
||||
totalWeight.value = (data?.totalWeight ?: 0.0).toString()
|
||||
// 手机三格统计分项(平板布局不绑定,无影响)
|
||||
storedCount.value = (data?.storedNumber ?: 0).toString()
|
||||
departedCount.value = (data?.departedNumber ?: 0).toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ class GjcWeighingRecordDetailsViewModel : BaseViewModel() {
|
||||
totalWeight.value = String.format("%.2f", sumWeight)
|
||||
|
||||
// 计算托盘总重(手机版顶部卡片)
|
||||
val sumCarWeight = records.sumOf { it.carWeight.toDoubleOrNull() ?: 0.0 }
|
||||
val sumCarWeight = records.sumOf { it.trayTotalWeight }
|
||||
totalCarWeight.value = String.format("%.2f", sumCarWeight)
|
||||
|
||||
// 计算重量误差百分比
|
||||
|
||||
@@ -48,28 +48,19 @@ class GjcWeighingRecordViewModel : BasePageViewModel() {
|
||||
|
||||
// ========== 5.5寸手机版专属字段(平板不调用 initPhoneExtras,行为零变化) ==========
|
||||
|
||||
/** 目的站(后端支持入参 dest) */
|
||||
val destFilter = MutableLiveData("")
|
||||
|
||||
/** 计重人(后端支持入参 opId,下拉复用仓库用户列表) */
|
||||
val opUserFilter = MutableLiveData("")
|
||||
val whsUserList = MutableLiveData<List<KeyValue>>(emptyList())
|
||||
|
||||
/** 入库日期起/止(后端暂无对应入参,传 opDateStart/opDateEnd 预留参数,见接口问题清单) */
|
||||
val checkInDateStart = MutableLiveData("")
|
||||
val checkInDateEnd = MutableLiveData("")
|
||||
// 手机版筛选弹层与平板端查询参数保持一致(后端确认):航班日期 / 代理人 / 特码,
|
||||
// 运单号走顶部搜索框;dest / opId / 收运时间范围后端均不支持(dest、opId 内网实测被忽略)
|
||||
|
||||
/** 由手机形态的 Activity 置 true,平板保持 false(不产生任何额外请求与参数) */
|
||||
private var phoneExtrasEnabled = false
|
||||
|
||||
/**
|
||||
* 开启手机版专属数据:放开「今天」默认日期(设计稿筛选无航班日期)、加载计重人下拉。
|
||||
* 开启手机版专属数据:放开「今天」默认日期(手机默认查全量,航班日期在筛选弹层可选)。
|
||||
* 仅由手机形态的 Activity 调用。
|
||||
*/
|
||||
fun initPhoneExtras() {
|
||||
phoneExtrasEnabled = true
|
||||
flightDate.value = ""
|
||||
DictUtils.getWHSUserList { whsUserList.postValue(it) }
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@@ -173,11 +164,6 @@ class GjcWeighingRecordViewModel : BasePageViewModel() {
|
||||
baseParams["wbNo"] = null
|
||||
baseParams["likeNo"] = key
|
||||
}
|
||||
baseParams["dest"] = destFilter.value?.ifEmpty { null }
|
||||
baseParams["opId"] = opUserFilter.value?.ifEmpty { null }
|
||||
// 入库日期起/止为后端预留参数(暂无对应入参,静默忽略,见接口问题清单)
|
||||
baseParams["opDateStart"] = checkInDateStart.value?.ifEmpty { null }
|
||||
baseParams["opDateEnd"] = checkInDateEnd.value?.ifEmpty { null }
|
||||
}
|
||||
|
||||
// 构建查询参数(列表接口)
|
||||
|
||||
@@ -72,17 +72,28 @@ class GjcWeighingStartViewModel : BaseViewModel() {
|
||||
val spCodeList = MutableLiveData<List<KeyValue>>() // 特码列表
|
||||
val businessTypeList = MutableLiveData<List<KeyValue>>() // 业务类型列表
|
||||
|
||||
// 托盘车自重(平板:托盘车号查询回填只读;手机:手输,见下方 initPhoneExtras)
|
||||
// 托盘车自重(平板:托盘车号查询回填只读)
|
||||
val carWeight = MutableLiveData("0")
|
||||
|
||||
// ========== 5.5寸手机版专属(平板不调用 initPhoneExtras,行为零变化) ==========
|
||||
|
||||
/** 托盘数量(设计稿字段,后端暂无对应入参,提交时传 palletNumber 预留参数,见接口问题清单) */
|
||||
val palletNumber = MutableLiveData("")
|
||||
// 托盘信息(与平板端一致:托盘重量 trayTotalWeight = 托盘数量 × 托盘自重,自重默认 18kg 可编辑)
|
||||
/** 托盘数量 → 入参 trayNumber */
|
||||
val trayNumber = MutableLiveData("")
|
||||
|
||||
/** 手机形态标记:为 true 时提交体额外携带 palletNumber / carWeight(后端静默忽略) */
|
||||
/** 单个托盘自重(默认 18kg)→ 与数量相乘得入参 trayTotalWeight */
|
||||
val trayWeight = MutableLiveData("18")
|
||||
|
||||
/** 手机形态标记:为 true 时提交体携带 trayNumber / trayTotalWeight(平板保持原托盘车号链路) */
|
||||
private var phoneMode = false
|
||||
|
||||
/** 托盘重量 = 托盘数量 × 托盘自重 */
|
||||
private fun getTrayTotalWeight(): Double {
|
||||
val num = trayNumber.value?.toIntOrNull() ?: 0
|
||||
val weight = trayWeight.value?.toDoubleOrNull() ?: 0.0
|
||||
return num * weight
|
||||
}
|
||||
|
||||
/** 仅由手机形态的 Activity 调用 */
|
||||
fun initPhoneExtras() {
|
||||
phoneMode = true
|
||||
@@ -406,10 +417,10 @@ class GjcWeighingStartViewModel : BaseViewModel() {
|
||||
|
||||
remark = pageRemark.value
|
||||
|
||||
// 手机版专属:托盘数量/托盘自重(后端暂无对应入参,静默忽略;平板 phoneMode 恒 false,字段为 null 不进请求体)
|
||||
// 手机版:托盘数量/托盘重量(平板 phoneMode 恒 false,字段为 null 不进请求体)
|
||||
if (this@GjcWeighingStartViewModel.phoneMode) {
|
||||
palletNumber = this@GjcWeighingStartViewModel.palletNumber.value?.ifEmpty { null }
|
||||
carWeight = this@GjcWeighingStartViewModel.carWeight.value?.ifEmpty { null }
|
||||
trayNumber = this@GjcWeighingStartViewModel.trayNumber.value?.toIntOrNull()
|
||||
trayTotalWeight = getTrayTotalWeight()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,10 +453,12 @@ class GjcWeighingStartViewModel : BaseViewModel() {
|
||||
maWbBean.value = maWbBean.value?.apply {
|
||||
carId = null
|
||||
remark = null
|
||||
palletNumber = null
|
||||
trayNumber = null
|
||||
trayTotalWeight = null
|
||||
}
|
||||
carWeight.value = "0"
|
||||
this@GjcWeighingStartViewModel.palletNumber.value = ""
|
||||
this@GjcWeighingStartViewModel.trayNumber.value = ""
|
||||
trayWeight.value = "18"
|
||||
} else {
|
||||
showToast(result.msg.noNull("分托计重失败"))
|
||||
}
|
||||
@@ -524,9 +537,9 @@ class GjcWeighingStartViewModel : BaseViewModel() {
|
||||
"checkIn" to "1", // 收运状态设置为已收运
|
||||
"passageWayId" to channel.value, // 通道号参数
|
||||
"passageWay" to (channelList.value?.firstOrNull{ it.value == channel.value }?.key ?: ""),
|
||||
// 手机版专属预留参数(平板 phoneMode 恒 false → null → removeEmptyOrNull 移除,请求体不变)
|
||||
"palletNumber" to (if (phoneMode) palletNumber.value?.ifEmpty { null } else null),
|
||||
"carWeight" to (if (phoneMode) carWeight.value?.ifEmpty { null } else null)
|
||||
// 手机版托盘信息(平板 phoneMode 恒 false → null → removeEmptyOrNull 移除,请求体不变)
|
||||
"trayNumber" to (if (phoneMode) trayNumber.value?.toIntOrNull() else null),
|
||||
"trayTotalWeight" to (if (phoneMode) getTrayTotalWeight() else null)
|
||||
).toRequestBody(removeEmptyOrNull = true)
|
||||
|
||||
launchLoadingCollect({
|
||||
|
||||
@@ -61,33 +61,23 @@ class GjcWeighingViewModel : BasePageViewModel() {
|
||||
/** 手机版顶部搜索关键字(运单号/航班号混输,getData 内分流:含字母→fno,纯数字→likeNo 模糊) */
|
||||
val searchKey = MutableLiveData("")
|
||||
|
||||
/** 主页三格统计:待计重(checkIn=0)/ 计重中(checkIn=2)数量 */
|
||||
/** 主页三格统计:待计重 / 计重中数量(取 pageQueryTotal 出参 waitCheckInNumber / checkingNumber) */
|
||||
val pendingCount = MutableLiveData("0")
|
||||
val weighingCount = MutableLiveData("0")
|
||||
|
||||
/** 手机版筛选弹层字段。通道号/承运人/运单类型后端暂无查询入参(见接口问题清单),传预留参数名 */
|
||||
val channelFilter = MutableLiveData("") // 通道号 → passageWayId
|
||||
val carrierFilter = MutableLiveData("") // 承运人 → by0
|
||||
val awbTypeFilter = MutableLiveData("") // 运单类型 → awbType
|
||||
val channelList = MutableLiveData<List<KeyValue>>(emptyList())
|
||||
val awbTypeList = MutableLiveData<List<KeyValue>>(emptyList())
|
||||
// 手机版筛选弹层与平板端查询参数保持一致(后端确认):航班日期 / 代理人 / 特码,
|
||||
// 运单号与航班号走顶部搜索框,均复用上方既有字段
|
||||
|
||||
/** 由手机形态的 Activity 置 true,平板保持 false(不产生任何额外请求与参数) */
|
||||
private var phoneExtrasEnabled = false
|
||||
|
||||
/**
|
||||
* 开启手机版专属数据:放开「今天」默认日期(设计稿主页无日期筛选)、加载筛选弹层字典。
|
||||
* 开启手机版专属数据:放开「今天」默认日期(设计稿主页默认查全量,日期在筛选弹层可选)。
|
||||
* 仅由手机形态的 Activity 调用。
|
||||
*/
|
||||
fun initPhoneExtras() {
|
||||
phoneExtrasEnabled = true
|
||||
flightDate.value = ""
|
||||
DictUtils.getGjcChannelList { list ->
|
||||
channelList.postValue(listOf(KeyValue("全部", "")) + list)
|
||||
}
|
||||
DictUtils.getWaybillTypeList2(ieFlag = "E", type = "IO") {
|
||||
awbTypeList.postValue(it)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -271,10 +261,6 @@ class GjcWeighingViewModel : BasePageViewModel() {
|
||||
else -> baseParams["likeNo"] = key
|
||||
}
|
||||
}
|
||||
// 以下三个为后端预留参数(暂无对应入参,后端静默忽略,见接口问题清单)
|
||||
baseParams["passageWayId"] = channelFilter.value?.ifEmpty { null }
|
||||
baseParams["by0"] = carrierFilter.value?.ifEmpty { null }
|
||||
baseParams["awbType"] = awbTypeFilter.value?.ifEmpty { null }
|
||||
}
|
||||
|
||||
// 构建查询参数(列表接口)
|
||||
@@ -304,21 +290,9 @@ class GjcWeighingViewModel : BasePageViewModel() {
|
||||
totalCount.value = (data?.wbNumber ?: 0).toString()
|
||||
totalPc.value = (data?.totalPc ?: 0).toString()
|
||||
totalWeight.value = (data?.totalWeight ?: 0.0).toString()
|
||||
}
|
||||
}
|
||||
|
||||
// 手机版三格统计:待计重 / 计重中(各带一次 checkIn 条件的统计请求,仅手机调用)
|
||||
if (phoneExtrasEnabled) {
|
||||
listOf("0" to pendingCount, "2" to weighingCount).forEach { (state, liveData) ->
|
||||
launchCollect({
|
||||
NetApply.api.getGjcWeighingStatistics(
|
||||
(baseParams + mapOf("checkIn" to state)).toRequestBody()
|
||||
)
|
||||
}) {
|
||||
onSuccess = { result ->
|
||||
liveData.value = (result.data?.wbNumber ?: 0).toString()
|
||||
}
|
||||
}
|
||||
// 手机版三格统计:后端统计出参直接给出分项计数,无需额外请求
|
||||
pendingCount.value = (data?.waitCheckInNumber ?: 0).toString()
|
||||
weighingCount.value = (data?.checkingNumber ?: 0).toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
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<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(后端接口暂未支持,见接口问题清单)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,7 @@ class IntExpArriveViewModel : BasePageViewModel() {
|
||||
|
||||
// ========== 5.5寸手机版专属(平板布局不引用,零影响) ==========
|
||||
|
||||
/** 当前 Tab:"pending"(待运抵) / "shipped"(已运抵)。接口无申报状态查询参数,Tab 由客户端对已加载数据拆分 */
|
||||
/** 当前 Tab:"pending"(待运抵) / "shipped"(已运抵)。查询时映射为入参 arrivalStatus=0/1(与平板端运抵状态筛选一致) */
|
||||
val currentTab = MutableLiveData("pending")
|
||||
|
||||
/** Tab 配置 */
|
||||
@@ -64,8 +64,12 @@ class IntExpArriveViewModel : BasePageViewModel() {
|
||||
listOf(KeyValue("待运抵", "pending"), KeyValue("已运抵", "shipped"))
|
||||
)
|
||||
|
||||
/** 两个 Tab 的角标计数(当前已加载数据的客户端统计,非全量,见接口问题清单) */
|
||||
val arriveTabCounts = MutableLiveData(listOf("", ""))
|
||||
/** 两个 Tab 的角标计数(同条件 + arrivalStatus=0/1 各调一次 pageQueryTotal 取 wbNumber,全量口径) */
|
||||
val arriveTabCounts = MutableLiveData(listOf("0", "0"))
|
||||
|
||||
/** 手机版空态(当前 Tab 过滤后无数据时显示,对应设计稿 empty-pending) */
|
||||
val emptyVisiblePhone = MutableLiveData(false)
|
||||
val emptyTextPhone = MutableLiveData("暂无待运抵的运单")
|
||||
|
||||
/** 手机版全选状态(仅统计待运抵 Tab 内的项,与 Pad 端 [isAllChecked] 统计口径不同) */
|
||||
val isAllCheckedPhone = MutableLiveData(false)
|
||||
@@ -73,59 +77,51 @@ class IntExpArriveViewModel : BasePageViewModel() {
|
||||
/** 手机版已选数量(底部操作条「已选 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 调用。
|
||||
* 开启手机版专属数据:Tab(arrivalStatus)与角标统计。仅由手机形态的 Activity 调用。
|
||||
* 筛选弹层与平板端查询参数一致(航班日期/航班号),agentCode 内网实测被后端忽略,已移除「代理」。
|
||||
*/
|
||||
fun initPhoneExtras() {
|
||||
phoneExtrasEnabled = true
|
||||
launchCollect({ NetApply.api.getIntExpAgentList() }) {
|
||||
onSuccess = { result ->
|
||||
agentListPhone.postValue(
|
||||
listOf(KeyValue("全部", "")) + (result.data ?: emptyList()).map { KeyValue(it.name ?: "", it.code ?: "") }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机版 Tab 切换:将适配器数据集替换为过滤后的子集(不重新请求)。
|
||||
* 手机版 Tab 切换:按 arrivalStatus 重新查询(服务端过滤,分页与角标均为全量口径)。
|
||||
* 由 Activity 在 [com.lukouguoji.module_base.ui.weight.phone.PhoneStatusTab] 的
|
||||
* 双向绑定写入 currentTab 后调用。
|
||||
*/
|
||||
fun onTabChangedPhone() {
|
||||
applyTabFilterPhone()
|
||||
refresh()
|
||||
}
|
||||
|
||||
private fun applyTabFilterPhone() {
|
||||
val isPendingTab = currentTab.value == "pending"
|
||||
val filtered = allLoadedList.filter { it.isPending == isPendingTab }
|
||||
pageModel.rv?.commonAdapter()?.refresh(filtered)
|
||||
updateCheckAllStatusPhone()
|
||||
/** 当前 Tab 对应的运抵状态入参:待运抵=0 / 已运抵=1 */
|
||||
private fun currentArrivalStatus(): String =
|
||||
if (currentTab.value == "shipped") "1" else "0"
|
||||
|
||||
/** 列表加载完成后刷新空态文案(服务端已按 Tab 过滤,adapter 即当前 Tab 数据) */
|
||||
private fun updateEmptyStatePhone() {
|
||||
val isPendingTab = currentTab.value != "shipped"
|
||||
emptyVisiblePhone.value = pageModel.rv?.commonAdapter()?.items.isNullOrEmpty()
|
||||
emptyTextPhone.value = if (isPendingTab) "暂无待运抵的运单" else "暂无已运抵的运单"
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据完整已加载列表重新计算 Tab 角标计数(每次数据变化后调用)。
|
||||
* 加载 Tab 角标:同条件 + arrivalStatus=0/1 各调一次 pageQueryTotal,取 wbNumber。
|
||||
*/
|
||||
private fun updatePhoneTabCounts() {
|
||||
val pending = allLoadedList.count { it.isPending }.toString()
|
||||
val shipped = allLoadedList.count { !it.isPending }.toString()
|
||||
arriveTabCounts.value = listOf(pending, shipped)
|
||||
private fun loadPhoneTabCounts(filterParams: Map<String, Any?>) {
|
||||
listOf("0", "1").forEachIndexed { index, status ->
|
||||
launchCollect({
|
||||
NetApply.api.getIntExpArriveTotal((filterParams + mapOf("arrivalStatus" to status)).toRequestBody())
|
||||
}) {
|
||||
onSuccess = { result ->
|
||||
val current = arriveTabCounts.value?.toMutableList() ?: mutableListOf("0", "0")
|
||||
current[index] = (result.data?.wbNumber ?: 0).toString()
|
||||
arriveTabCounts.value = current
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -433,33 +429,30 @@ class IntExpArriveViewModel : BasePageViewModel() {
|
||||
filterParams["wbNo"] = null
|
||||
filterParams["likeNo"] = key
|
||||
}
|
||||
filterParams["agentCode"] = agentCodePhone.value?.ifEmpty { null }
|
||||
}
|
||||
|
||||
// 手机版 Tab 维度(运抵状态),角标需在不含该条件的基础上分别统计
|
||||
val tabParams = if (phoneExtrasEnabled) {
|
||||
filterParams + mapOf("arrivalStatus" to currentArrivalStatus())
|
||||
} else filterParams
|
||||
|
||||
// 列表参数 (含分页)
|
||||
val listParams = (filterParams + mapOf(
|
||||
val listParams = (tabParams + mapOf(
|
||||
"pageNum" to pageModel.page,
|
||||
"pageSize" to pageModel.limit
|
||||
)).toRequestBody()
|
||||
|
||||
// 统计参数 (无分页)
|
||||
val totalParams = filterParams.toRequestBody()
|
||||
val totalParams = tabParams.toRequestBody()
|
||||
|
||||
// 获取列表 (带Loading)
|
||||
launchLoadingCollect({ NetApply.api.getIntExpArriveList(listParams) }) {
|
||||
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()
|
||||
updateEmptyStatePhone()
|
||||
updateCheckAllStatusPhone()
|
||||
}
|
||||
}
|
||||
// 数据加载完成后,重置全局展开状态为收起
|
||||
@@ -476,5 +469,10 @@ class IntExpArriveViewModel : BasePageViewModel() {
|
||||
totalWeight.value = (data?.totalWeight ?: 0.0).toString()
|
||||
}
|
||||
}
|
||||
|
||||
// 手机版 Tab 角标(平板不触发)
|
||||
if (phoneExtrasEnabled) {
|
||||
loadPhoneTabCounts(filterParams)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ 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 com.lukouguoji.module_base.util.DictUtils
|
||||
import dev.utils.app.info.KeyValue
|
||||
import dev.utils.common.DateUtils
|
||||
import com.lukouguoji.module_base.ktx.formatDate
|
||||
@@ -36,12 +35,8 @@ class IntExpOutHandoverViewModel : BasePageViewModel() {
|
||||
val uldNo = MutableLiveData("") // ULD编号
|
||||
|
||||
// ========== 手机版(5.5 寸手持端)专用筛选条件 ==========
|
||||
// 平板布局不含对应控件,两者保持空值 → 不会进入请求参数,平板查询行为与改造前完全一致
|
||||
// 平板布局不含对应控件,保持空值 → 不会进入请求参数,平板查询行为与改造前完全一致
|
||||
val handoverState = MutableLiveData("") // 交接状态:"" 全部 / "0" 待交接 / "1" 已交接
|
||||
val hoId = MutableLiveData("") // 交接人(仓管编码)
|
||||
|
||||
/** 交接人下拉数据(仅手机版筛选弹层使用,由 [initPhoneExtras] 触发加载) */
|
||||
val hoUserList = MutableLiveData<List<KeyValue>>(emptyList())
|
||||
|
||||
/** 手机版状态 Tab 配置 */
|
||||
val handoverStateTabs = MutableLiveData(
|
||||
@@ -52,7 +47,7 @@ class IntExpOutHandoverViewModel : BasePageViewModel() {
|
||||
val handoverStateCounts = MutableLiveData(listOf("", ""))
|
||||
|
||||
/**
|
||||
* 是否启用手机版专属数据(Tab 角标计数、交接人下拉)。
|
||||
* 是否启用手机版专属数据(Tab 角标计数)。
|
||||
*
|
||||
* 由 Activity 在手机形态下置 true。平板端保持 false,
|
||||
* 因此不会产生任何额外接口请求,平板行为零变化。
|
||||
@@ -70,15 +65,12 @@ class IntExpOutHandoverViewModel : BasePageViewModel() {
|
||||
val selectedCount = MutableLiveData("0")
|
||||
|
||||
/**
|
||||
* 开启手机版专属数据:默认停留「待交接」Tab、加载交接人下拉、启用 Tab 角标计数。
|
||||
* 开启手机版专属数据:默认停留「待交接」Tab、启用 Tab 角标计数。
|
||||
* 仅由手机形态的 Activity 调用。
|
||||
*/
|
||||
fun initPhoneExtras() {
|
||||
phoneExtrasEnabled = true
|
||||
handoverState.value = "0"
|
||||
DictUtils.getWHSUserList(addAll = false) { list ->
|
||||
hoUserList.postValue(list)
|
||||
}
|
||||
}
|
||||
|
||||
fun onItemCheckChanged() {
|
||||
@@ -218,11 +210,10 @@ class IntExpOutHandoverViewModel : BasePageViewModel() {
|
||||
"fno" to flightNo.value?.ifEmpty { null },
|
||||
"fdest" to fdest.value?.ifEmpty { null },
|
||||
"uld" to uldNo.value?.ifEmpty { null },
|
||||
// 以下两项为手机版新增筛选维度,平板端保持空值故不参与查询
|
||||
// 手机版 Tab 维度,平板端保持空值故不参与查询
|
||||
// 参数名以 api-doc 为准:交接状态为 handoverState(integer,0 未交接 / 1 已交接)。
|
||||
// hoId(交接人)后端查询入参暂不支持,已记录到 documents/后端接口对接问题清单.xlsx
|
||||
"handoverState" to handoverState.value?.ifEmpty { null },
|
||||
"hoId" to hoId.value?.ifEmpty { null }
|
||||
// 其余筛选与平板端口径一致(fdate/fno/fdest/uld),后端不提供交接人查询入参
|
||||
"handoverState" to handoverState.value?.ifEmpty { null }
|
||||
)
|
||||
|
||||
// 列表参数 (含分页)
|
||||
@@ -257,15 +248,15 @@ class IntExpOutHandoverViewModel : BasePageViewModel() {
|
||||
/**
|
||||
* 加载「待交接 / 已交接」Tab 角标数量。
|
||||
*
|
||||
* 复用统计接口,分别以 handoverState=0 / 1 各查一次,且沿用当前其余筛选条件,
|
||||
* 保证角标与列表口径一致。仅手机版调用。
|
||||
* 复用统计接口,分别以 handoverState=0 / 1 各查一次,且沿用当前其余筛选条件;
|
||||
* 角标取 uldNumber(板箱数,与列表 pageQuery 的 total 同口径)。仅手机版调用。
|
||||
*/
|
||||
private fun loadTabCounts(filterParams: Map<String, Any?>) {
|
||||
listOf("0", "1").forEachIndexed { index, state ->
|
||||
val params = (filterParams + mapOf("handoverState" to state)).toRequestBody()
|
||||
launchCollect({ NetApply.api.getIntExpOutHandoverTotal(params) }) {
|
||||
onSuccess = { result ->
|
||||
val count = (result.data?.wbNumber ?: 0).toString()
|
||||
val count = (result.data?.uldNumber ?: 0).toString()
|
||||
val current = handoverStateCounts.value?.toMutableList()
|
||||
?: mutableListOf("", "")
|
||||
if (index < current.size) {
|
||||
|
||||
@@ -38,6 +38,52 @@ class IntExpStorageUseViewModel : BasePageViewModel() {
|
||||
val totalPc = MutableLiveData("0") // 总件数
|
||||
val totalWeight = MutableLiveData("0") // 总重量
|
||||
|
||||
// ========== 5.5寸手机版专属 ==========
|
||||
// 筛选弹层显隐
|
||||
val filterVisible = MutableLiveData(false)
|
||||
|
||||
// 筛选弹层与平板端查询参数保持一致(后端确认):航班日期 / 航班号 / 库位 / 清仓结果,运单号走顶部搜索框。
|
||||
// 代理/特码/目的站/运单类型/业务类型/品名 后端均不支持(内网实测 agentCode/spCode/dest 亦被忽略),已移除
|
||||
|
||||
// 三格统计:未清仓 / 已清仓(总票数复用 totalWbNumber),直接取 pageQueryTotal 出参
|
||||
// notClearNumber / clearNumber(与总票数同一次请求、同条件)
|
||||
val unclearedCount = MutableLiveData("0")
|
||||
val clearedCount = MutableLiveData("0")
|
||||
|
||||
private var phoneExtrasEnabled = false
|
||||
|
||||
/**
|
||||
* 手机形态专属初始化(Activity 在 DeviceUtil.isPhone() 时调用)。
|
||||
* 平板端不调用,请求次数与行为零变化。
|
||||
*/
|
||||
fun initPhoneExtras() {
|
||||
phoneExtrasEnabled = true
|
||||
}
|
||||
|
||||
/** 筛选按钮点击 - 打开筛选面板 */
|
||||
fun filterClick() {
|
||||
filterVisible.value = true
|
||||
}
|
||||
|
||||
/** 关闭筛选面板 */
|
||||
fun closeFilter() {
|
||||
filterVisible.value = false
|
||||
}
|
||||
|
||||
/** 重置筛选条件 */
|
||||
fun resetFilter() {
|
||||
flightDate.value = ""
|
||||
flightNo.value = ""
|
||||
location.value = ""
|
||||
clearResult.value = ""
|
||||
}
|
||||
|
||||
/** 确认筛选 - 关闭面板并刷新 */
|
||||
fun confirmFilter() {
|
||||
filterVisible.value = false
|
||||
refresh()
|
||||
}
|
||||
|
||||
// ========== 全选状态 ==========
|
||||
val isAllChecked = MutableLiveData(false)
|
||||
|
||||
@@ -301,7 +347,7 @@ class IntExpStorageUseViewModel : BasePageViewModel() {
|
||||
* 获取数据 (重写BasePageViewModel)
|
||||
*/
|
||||
override fun getData() {
|
||||
// 构建搜索条件
|
||||
// 构建搜索条件(与平板端一致)
|
||||
val filterParams = mapOf(
|
||||
"fdate" to flightDate.value?.ifEmpty { null },
|
||||
"fno" to flightNo.value?.ifEmpty { null },
|
||||
@@ -337,6 +383,9 @@ class IntExpStorageUseViewModel : BasePageViewModel() {
|
||||
totalWbNumber.value = (data?.wbNumber ?: 0).toString()
|
||||
totalPc.value = (data?.totalPc ?: 0).toString()
|
||||
totalWeight.value = (data?.totalWeight ?: 0.0).toString()
|
||||
// 手机三格统计分项(平板布局不绑定,无影响)
|
||||
unclearedCount.value = (data?.notClearNumber ?: 0).toString()
|
||||
clearedCount.value = (data?.clearNumber ?: 0).toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
237
module_gjc/src/main/res/layout-sw600dp/activity_gjc_query.xml
Normal file
237
module_gjc/src/main/res/layout-sw600dp/activity_gjc_query.xml
Normal file
@@ -0,0 +1,237 @@
|
||||
<?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="android.view.View" />
|
||||
<import type="com.lukouguoji.module_base.ui.weight.search.layout.SearchLayoutType" />
|
||||
|
||||
<variable
|
||||
name="viewModel"
|
||||
type="com.lukouguoji.gjc.viewModel.GjcQueryViewModel" />
|
||||
</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" />
|
||||
|
||||
<!-- 内容区域(FrameLayout 包裹,筛选面板和遮罩只在此区域内) -->
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<!-- 原有内容 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- 搜索区域 -->
|
||||
<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
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
hint='@{"请选择开始日期"}'
|
||||
icon="@{@drawable/img_date}"
|
||||
type="@{SearchLayoutType.DATE}"
|
||||
value="@={viewModel.flightDateStart}" />
|
||||
|
||||
<!-- 航班日期止 -->
|
||||
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
hint='@{"请选择结束日期"}'
|
||||
icon="@{@drawable/img_date}"
|
||||
type="@{SearchLayoutType.DATE}"
|
||||
value="@={viewModel.flightDateEnd}" />
|
||||
|
||||
<!-- 代理人 -->
|
||||
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
hint='@{"请选择代理"}'
|
||||
list="@{viewModel.agentList}"
|
||||
type="@{SearchLayoutType.SPINNER}"
|
||||
value="@={viewModel.agentId}" />
|
||||
|
||||
<!-- 出库状态 -->
|
||||
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
hint='@{"请选择出库状态"}'
|
||||
list="@{viewModel.outStatusList}"
|
||||
type="@{SearchLayoutType.SPINNER}"
|
||||
value="@={viewModel.outStatus}" />
|
||||
|
||||
<!-- 运单号 -->
|
||||
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
hint='@{"请输入运单号"}'
|
||||
icon="@{@drawable/img_scan}"
|
||||
setOnIconClickListener="@{()-> viewModel.waybillScanClick()}"
|
||||
type="@{SearchLayoutType.INPUT}"
|
||||
value="@={viewModel.waybillNo}"
|
||||
autoQueryEnabled="@{true}"
|
||||
autoQueryUrl="@{`/IntExpSearch/queryWbNoList`}"
|
||||
autoQueryParamKey="@{`wbNo`}"
|
||||
autoQueryMinLength="@{4}"
|
||||
autoQueryMaxLength="@{8}"
|
||||
autoQueryTitle="@{`选择运单号`}" />
|
||||
|
||||
<!-- 搜索和筛选按钮 -->
|
||||
<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" />
|
||||
|
||||
<!-- 筛选按钮(含红点) -->
|
||||
<FrameLayout
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginLeft="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:onClick="@{()-> viewModel.filterClick()}"
|
||||
android:padding="5dp"
|
||||
android:src="@drawable/img_filter" />
|
||||
|
||||
<View
|
||||
android:layout_width="8dp"
|
||||
android:layout_height="8dp"
|
||||
android:layout_gravity="top|end"
|
||||
android:background="@drawable/bg_red_dot"
|
||||
android:visibility="@{viewModel.hasFilter ? View.VISIBLE : View.GONE}" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 列表区域 -->
|
||||
<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"
|
||||
itemLayoutId="@{viewModel.itemLayoutId}"
|
||||
viewHolder="@{viewModel.itemViewHolder}"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:listitem="@layout/item_gjc_query" />
|
||||
|
||||
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
|
||||
|
||||
<!-- 底部统计信息 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:background="@color/white"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingHorizontal="15dp">
|
||||
|
||||
<!-- 统计信息 -->
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
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="16sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="合计:3票" />
|
||||
|
||||
<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="16sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="总件数:100" />
|
||||
|
||||
<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="16sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="总重量:100" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 遮罩层(只覆盖内容区域) -->
|
||||
<View
|
||||
android:id="@+id/filter_overlay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#80000000"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:onClick="@{()-> viewModel.closeFilter()}"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- 筛选面板(从右侧滑入,只在内容区域内) -->
|
||||
<include
|
||||
android:id="@+id/filter_panel"
|
||||
layout="@layout/layout_gjc_query_filter"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end"
|
||||
android:visibility="gone"
|
||||
app:viewModel="@{viewModel}" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</layout>
|
||||
@@ -0,0 +1,125 @@
|
||||
<?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="viewModel"
|
||||
type="com.lukouguoji.gjc.viewModel.GjcQueryDetailsViewModel" />
|
||||
</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" />
|
||||
|
||||
<!-- Tab栏 (自定义,文字Tab + 底线) -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginHorizontal="15dp"
|
||||
android:layout_marginTop="15dp"
|
||||
android:background="@drawable/bg_white_radius_top_8"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<!-- Tab1: 运单信息 -->
|
||||
<LinearLayout
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:onClick="@{()->viewModel.onTabClick(0)}"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:text="运单信息"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@{viewModel.currentTab == 0 ? @color/colorPrimary : @color/text_gray}"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<!-- 选中底线 -->
|
||||
<View
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="3dp"
|
||||
android:background="@{viewModel.currentTab == 0 ? @color/colorPrimary : @color/transparent}"
|
||||
android:visibility="@{viewModel.currentTab == 0 ? View.VISIBLE : View.INVISIBLE}" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Tab2: 仓库信息 -->
|
||||
<LinearLayout
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:onClick="@{()->viewModel.onTabClick(1)}"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:textStyle="bold"
|
||||
android:text="仓库信息"
|
||||
android:textColor="@{viewModel.currentTab == 1 ? @color/colorPrimary : @color/text_gray}"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<View
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="3dp"
|
||||
android:background="@{viewModel.currentTab == 1 ? @color/colorPrimary : @color/transparent}"
|
||||
android:visibility="@{viewModel.currentTab == 1 ? View.VISIBLE : View.INVISIBLE}" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Tab3: 库位信息 -->
|
||||
<LinearLayout
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:onClick="@{()->viewModel.onTabClick(2)}"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:textStyle="bold"
|
||||
android:text="库位信息"
|
||||
android:textColor="@{viewModel.currentTab == 2 ? @color/colorPrimary : @color/text_gray}"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<View
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="3dp"
|
||||
android:background="@{viewModel.currentTab == 2 ? @color/colorPrimary : @color/transparent}"
|
||||
android:visibility="@{viewModel.currentTab == 2 ? View.VISIBLE : View.INVISIBLE}" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginStart="15dp"
|
||||
android:layout_marginEnd="23dp"
|
||||
android:background="@color/color_f2" />
|
||||
|
||||
<!-- ViewPager2 -->
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/vp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
</LinearLayout>
|
||||
</layout>
|
||||
@@ -0,0 +1,253 @@
|
||||
<?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.gjc.R" />
|
||||
|
||||
<variable
|
||||
name="viewModel"
|
||||
type="com.lukouguoji.gjc.viewModel.IntExpStorageUseViewModel" />
|
||||
|
||||
<variable
|
||||
name="activity"
|
||||
type="com.lukouguoji.gjc.activity.IntExpStorageUseActivity" />
|
||||
</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='@{"请输入航班号"}'
|
||||
setUpperCaseAlphanumeric="@{true}"
|
||||
type="@{SearchLayoutType.INPUT}"
|
||||
value="@={viewModel.flightNo}"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<!-- 清仓综合结果 -->
|
||||
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
||||
hint='@{"请选择清仓结果"}'
|
||||
list="@{viewModel.clearResultList}"
|
||||
type="@{SearchLayoutType.SPINNER}"
|
||||
value="@={viewModel.clearResult}"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<!-- 运单号 -->
|
||||
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
||||
autoQueryEnabled="@{true}"
|
||||
autoQueryMaxLength="@{8}"
|
||||
autoQueryMinLength="@{4}"
|
||||
autoQueryParamKey="@{`wbNo`}"
|
||||
autoQueryTitle="@{`选择运单号`}"
|
||||
autoQueryUrl="@{`/IntExpStorageUse/queryWbNoList`}"
|
||||
hint='@{"请输入运单号"}'
|
||||
icon="@{@drawable/img_scan}"
|
||||
setOnIconClickListener="@{(v)-> viewModel.scanWbNo()}"
|
||||
type="@{SearchLayoutType.INPUT}"
|
||||
value="@={viewModel.wbNo}"
|
||||
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.location}"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<!-- 搜索按钮 -->
|
||||
<LinearLayout
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="10dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:onClick="@{()-> viewModel.searchClick()}"
|
||||
android:padding="2dp"
|
||||
android:src="@drawable/img_search" />
|
||||
|
||||
<!-- 全局展开/收起按钮 -->
|
||||
<ImageView
|
||||
loadImage="@{viewModel.isAllExpanded ? R.drawable.ic_new_expand_1 : R.drawable.ic_new_expand_1}"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:contentDescription="展开/收起全部子列表"
|
||||
android:onClick="@{()-> viewModel.toggleAllExpand()}"
|
||||
android:padding="2dp"
|
||||
android:scaleType="fitCenter" />
|
||||
|
||||
</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_storage_use" />
|
||||
|
||||
</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.totalWbNumber+"票"}'
|
||||
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:onClick="@{()-> activity.showClearDialog()}"
|
||||
android:text="清 仓" />
|
||||
|
||||
<!-- 修改库位按钮 -->
|
||||
<TextView
|
||||
style="@style/tv_bottom_btn"
|
||||
android:onClick="@{()-> activity.showModifyStorageDialog()}"
|
||||
android:text="修改库位" />
|
||||
|
||||
<!-- 出库按钮 -->
|
||||
<TextView
|
||||
style="@style/tv_bottom_btn"
|
||||
android:onClick="@{()-> activity.showOutStorageDialog()}"
|
||||
android:text="出 库" />
|
||||
|
||||
<!-- 入库按钮 -->
|
||||
<TextView
|
||||
style="@style/tv_bottom_btn"
|
||||
android:onClick="@{()-> activity.showInStorageDialog()}"
|
||||
android:text="入 库" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</layout>
|
||||
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<data>
|
||||
<import type="com.lukouguoji.module_base.ui.weight.search.layout.SearchLayoutType"/>
|
||||
|
||||
<variable
|
||||
name="model"
|
||||
type="com.lukouguoji.gjc.dialog.IntExpArriveResetDialogModel" />
|
||||
|
||||
</data>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="480dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_dialog_f2_radius_10"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- 标题栏 -->
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:background="@drawable/bg_primary_radius_top_10"
|
||||
android:gravity="center"
|
||||
android:text="状态重置"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<!-- 表单内容 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="30dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- 重置状态 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
completeSpace="@{5}"
|
||||
android:text="重置状态:"
|
||||
android:textColor="@color/text_normal"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
type="@{SearchLayoutType.SPINNER}"
|
||||
hint='@{"请选择重置状态"}'
|
||||
list="@{model.resetStatusList}"
|
||||
value="@={model.selectedResetStatus}" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 底部按钮 -->
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="40dp"
|
||||
android:layout_marginBottom="20dp">
|
||||
|
||||
<TextView
|
||||
style="@style/tv_bottom_btn"
|
||||
android:onClick="@{()->model.dismiss()}"
|
||||
android:text="取消" />
|
||||
|
||||
<TextView
|
||||
style="@style/tv_bottom_btn"
|
||||
android:onClick="@{()->model.onSaveClick()}"
|
||||
android:text="确定" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</layout>
|
||||
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<data>
|
||||
<import type="com.lukouguoji.module_base.ui.weight.search.layout.SearchLayoutType"/>
|
||||
|
||||
<variable
|
||||
name="model"
|
||||
type="com.lukouguoji.gjc.dialog.IntExpInStorageDialogModel" />
|
||||
|
||||
</data>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="480dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_dialog_f2_radius_10"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- 标题栏 -->
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:background="@drawable/bg_primary_radius_top_10"
|
||||
android:gravity="center"
|
||||
android:text="入库操作"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<!-- 表单内容 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="30dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- 库位号 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
completeSpace="@{5}"
|
||||
android:text="库位号:"
|
||||
android:textColor="@color/text_normal"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
type="@{SearchLayoutType.SPINNER}"
|
||||
hint='@{"请选择库位"}'
|
||||
list="@{model.locationList}"
|
||||
value="@={model.selectedLocationCode}" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 底部按钮 -->
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="40dp"
|
||||
android:layout_marginBottom="20dp">
|
||||
|
||||
<TextView
|
||||
style="@style/tv_bottom_btn"
|
||||
android:onClick="@{()->model.dismiss()}"
|
||||
android:text="取消" />
|
||||
|
||||
<TextView
|
||||
style="@style/tv_bottom_btn"
|
||||
android:onClick="@{()->model.onSaveClick()}"
|
||||
android:text="确定" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</layout>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user