From a33776d959bcc2454b3df718faedb4c41fc5e3d3 Mon Sep 17 00:00:00 2001 From: YANG JIANKUAN Date: Fri, 31 Jul 2026 22:35:56 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=E8=BF=9B=E6=B8=AF?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E4=B8=8E=E8=BF=9B=E6=B8=AF=E7=A7=BB=E5=BA=93?= =?UTF-8?q?=E9=A1=B5=E9=9D=A25.5=E5=AF=B8=E6=89=8B=E6=9C=BA=E7=AB=AF?= =?UTF-8?q?=E9=80=82=E9=85=8D=EF=BC=88=E8=AE=BE=E8=AE=A1=E7=A8=BF11?= =?UTF-8?q?=E9=A1=B5=E5=85=A8=E9=83=A8=E5=AE=8C=E6=88=90=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 进港查询(10,06出港查询的进港镜像): - IntImpQueryActivity 手机布局:搜索行 + 三格统计(总票数/已入库/已出库客户端计数) + 状态标签卡片(dlvTime/inDate 前端推断)+ 筛选弹层9项(入参全部经api-doc核对存在) - 详情页与运单追踪复用08/06已适配页零新增;平板侧滑筛选面板判空守卫,Pad端零变化 - 修复代理人空值兜底:转换器将JSON null归一为空串致DataBinding `??` 失效, 改用Bean计算属性 agentDisplay(06出港查询同步修正) 进港移库(11,首个后端整模块缺失的设计稿页): - 全新手机专属3页:列表(双Tab+角标/筛选4项/多选批量移库/卡片长按拍照浮层) + 运单详情(三卡片,Intent传bean零请求)+ 拍照上传(复用ImageSelectNewViewHolder, pic/originalPic/picNumber三字段规范) - 后端无IntImpMove模块(api-doc核对),按IntExpMove同名约定预接四接口 + 预定义权限串AppIntImpMove,后端交付后前端零改动生效(缺口#31) 其他:手机首页国际Tab新增进港查询/进港移库入口;新增资源bg_phone_btn_green/ bg_phone_card_header_orange/bg_phone_photo_add/phone_amber;问题清单登记#30~#31; 双端模拟器验证零崩溃(手机Map Local mock全交互链路,平板回归零变化) Co-Authored-By: Claude Fable 5 --- .../skills/phone-adapt/references/api-doc.md | 10 + CHANGELOG.md | 35 ++ CLAUDE.md | 21 + app/src/debug/AndroidManifest.xml | 12 + app/src/main/AndroidManifest.xml | 21 + documents/后端接口对接问题清单.xlsx | Bin 22454 -> 23282 bytes .../lukouguoji/module_base/bean/GjcMaWb.kt | 7 + .../module_base/bean/IntImpMoveBean.kt | 78 +++ .../module_base/bean/IntImpQueryBean.kt | 24 +- .../lukouguoji/module_base/common/Constant.kt | 3 + .../lukouguoji/module_base/http/net/Api.kt | 33 ++ .../module_base/router/ARouterConstants.kt | 1 + .../main/res/drawable/bg_phone_btn_green.xml | 16 + .../drawable/bg_phone_card_header_orange.xml | 9 + .../main/res/drawable/bg_phone_photo_add.xml | 12 + module_base/src/main/res/values/colors.xml | 1 + .../src/main/res/layout/item_gjc_query.xml | 2 +- .../gjj/activity/IntImpMoveActivity.kt | 147 ++++++ .../gjj/activity/IntImpMoveDetailActivity.kt | 46 ++ .../gjj/activity/IntImpMovePhotoActivity.kt | 45 ++ .../gjj/activity/IntImpQueryActivity.kt | 36 +- .../gjj/holder/IntImpMoveViewHolder.kt | 48 ++ .../gjj/holder/IntImpQueryViewHolder.kt | 6 +- .../viewModel/IntImpMoveDetailViewModel.kt | 26 + .../gjj/viewModel/IntImpMovePhotoViewModel.kt | 152 ++++++ .../gjj/viewModel/IntImpMoveViewModel.kt | 187 +++++++ .../gjj/viewModel/IntImpQueryViewModel.kt | 36 ++ .../layout-sw600dp/activity_int_imp_query.xml | 234 +++++++++ .../res/layout-sw600dp/item_int_imp_query.xml | 325 ++++++++++++ .../main/res/layout/activity_int_imp_move.xml | 166 ++++++ .../layout/activity_int_imp_move_detail.xml | 334 ++++++++++++ .../layout/activity_int_imp_move_photo.xml | 123 +++++ .../res/layout/activity_int_imp_query.xml | 437 ++++++++++------ .../src/main/res/layout/item_int_imp_move.xml | 230 +++++++++ .../main/res/layout/item_int_imp_query.xml | 483 +++++++----------- .../sixin/module_p/ui/enter/gj/GjViewModel.kt | 14 + .../res/drawable-xxhdpi/gjj_query_icon.png | Bin 0 -> 32431 bytes 37 files changed, 2884 insertions(+), 476 deletions(-) create mode 100644 module_base/src/main/java/com/lukouguoji/module_base/bean/IntImpMoveBean.kt create mode 100644 module_base/src/main/res/drawable/bg_phone_btn_green.xml create mode 100644 module_base/src/main/res/drawable/bg_phone_card_header_orange.xml create mode 100644 module_base/src/main/res/drawable/bg_phone_photo_add.xml create mode 100644 module_gjj/src/main/java/com/lukouguoji/gjj/activity/IntImpMoveActivity.kt create mode 100644 module_gjj/src/main/java/com/lukouguoji/gjj/activity/IntImpMoveDetailActivity.kt create mode 100644 module_gjj/src/main/java/com/lukouguoji/gjj/activity/IntImpMovePhotoActivity.kt create mode 100644 module_gjj/src/main/java/com/lukouguoji/gjj/holder/IntImpMoveViewHolder.kt create mode 100644 module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpMoveDetailViewModel.kt create mode 100644 module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpMovePhotoViewModel.kt create mode 100644 module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpMoveViewModel.kt create mode 100644 module_gjj/src/main/res/layout-sw600dp/activity_int_imp_query.xml create mode 100644 module_gjj/src/main/res/layout-sw600dp/item_int_imp_query.xml create mode 100644 module_gjj/src/main/res/layout/activity_int_imp_move.xml create mode 100644 module_gjj/src/main/res/layout/activity_int_imp_move_detail.xml create mode 100644 module_gjj/src/main/res/layout/activity_int_imp_move_photo.xml create mode 100644 module_gjj/src/main/res/layout/item_int_imp_move.xml create mode 100644 module_p/src/main/res/drawable-xxhdpi/gjj_query_icon.png diff --git a/.claude/skills/phone-adapt/references/api-doc.md b/.claude/skills/phone-adapt/references/api-doc.md index 93a3cb5..eb54f1b 100644 --- a/.claude/skills/phone-adapt/references/api-doc.md +++ b/.claude/skills/phone-adapt/references/api-doc.md @@ -109,6 +109,16 @@ curl -s -X POST "$URL" -H "$AUTH" -H "Content-Type: application/json" \ 运单号筛选参数名是 **`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 +- `IntImpMove`(进港移库,2026-07-31 文档核对):**后端整个模块不存在**(api-doc 仅有国内进港 + `DomImpMove` 与国际出港 `IntExpMove`),权限串也没有对应 key(缺口 #31)。前端按 IntExpMove + 同名约定预接 `pageQuery`/`pageQueryTotal`/`move`/`uploadPic` 四接口 + 预定义权限串 + `AppIntImpMove`,后端交付后前端零改动生效 - `IntExpCheckIn`(出港计重,2026-07-29 内网实测):`likeNo` **并非任意模糊**——按 8 位 `no` 匹配(11 位 wbNo 或部分号均 0 条),11 位全号必须走 `wbNo`;`checkIn`/`checkInList` 文档有定义但 `pageQuery`/`pageQueryTotal` **均静默忽略**(缺口 #12,待计重/计重中计数依赖); diff --git a/CHANGELOG.md b/CHANGELOG.md index 94db5db..a358d34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,41 @@ ## [Unreleased] ### 新增 (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) +- 出港查询/进港查询卡片「代理人」空值兜底失效:转换器把 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,抓包证实携带)+ diff --git a/CLAUDE.md b/CLAUDE.md index 64be4e6..fdefd92 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1066,6 +1066,8 @@ DataBinding 适配器统一放在 `PhoneWidgetKtx.kt`(同名属性按控件类 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)。 @@ -1141,6 +1143,22 @@ override fun dispatchRestoreInstanceState(container: SparseArray) = 缺口 #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 出港查询同步修正)) + - 「进港移库」`IntImpMoveActivity` + `IntImpMoveDetailActivity` + `IntImpMovePhotoActivity` + (module_gjj,**首个后端整模块缺失的设计稿页**:api-doc 确认无 IntImpMove 模块、权限串无 + 对应 key(缺口 #31)。前端按设计稿完整实现、按 IntExpMove 同名约定预接 + pageQuery/pageQueryTotal/move/uploadPic + 预定义权限串 `AppIntImpMove`,后端交付后零改动 + 生效;权限串下发前手机首页无入口,debug 直启验证。结构镜像 05 出港移库(Tab/批量移库/筛选 + 4 项),新增交互:卡片长按浮层「拍照」(复用 04 运抵的 actionMenuVisible 模式)→ 拍照上传页 + (图片网格复用 module_base `ImageSelectNewViewHolder`,提交走 pic/originalPic/picNumber + 三字段规范);详情页三卡片:基本信息/移库信息(仅已移库)/异常照片。手机专属新页无平板变体, + 布局只放 `res/layout/`;UI 与交互已用 Proxyman Map Local mock 全量验证) - 「进港仓库」`IntImpStorageUseActivity`(module_gjj,07 出港仓库的进港镜像;**首页菜单实际跳转页, 旧版 `GjjWareHouseActivity` 路由已注释弃用**。差异:卡片/筛选用始发站(fdep 入参)替代目的站; 搜索框「运单号/航班号」分流(含字母→fno、其余→wbNo,抓包证实);筛选 5 项无入参(缺口 #25, @@ -1165,8 +1183,10 @@ override fun dispatchRestoreInstanceState(container: SparseArray) = 双变体首例:手机竖排时间线由 Activity `buildVerticalSteps` 动态构建,平板横向步骤条不动; 手机标题按形态切「运单追踪」)。平板侧滑筛选面板代码已判空守卫(手机变体无 filter_panel include,Binding 字段为 @Nullable) +- ✅ **设计稿 11 个入口(01~11)已于 2026-07-31 全部适配完成** - ⏳ **待办**: - `PhoneSearchBar` 接入 AutoQuery 联想(`AutoQueryManager` 目前只对接了 Pad 系组件) + - 进港移库待后端交付 IntImpMove 模块(四接口 + 权限串 AppIntImpMove,缺口 #31)后联调 - 出库交接 Tab 角标恒 0:`IntExpOutHandover/pageQueryTotal` 出参恒 0(后端缺陷,问题清单 #6), 后端修复后角标自动恢复(`handoverState` 过滤本身已于 2026-07-29 实机验证通过)生效 - 📋 **接口对接**:适配中发现的后端接口缺口统一记录在 `documents/后端接口对接问题清单.xlsx` @@ -1261,6 +1281,7 @@ adb shell am start -n com.lukouguoji.aerologic/com.lukouguoji.gjc.activity.IntEx | 通过 `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`(平板布局不绑定该字段,无影响) | +| XML 里 `bean.a ?? bean.b` 兜底不生效,字段明明有值却显示占位符 | 网络层转换器把 JSON null 归一成空串 `""`,DataBinding 的 `??` 只判 null 不判空串,永远取到左侧的空串 | 在 Bean 上加计算属性做 `isNullOrEmpty` 双兜底(如 `agentDisplay`),XML 绑计算属性(进港查询/出港查询代理人已踩过) | --- diff --git a/app/src/debug/AndroidManifest.xml b/app/src/debug/AndroidManifest.xml index 543f109..8717d8c 100644 --- a/app/src/debug/AndroidManifest.xml +++ b/app/src/debug/AndroidManifest.xml @@ -152,5 +152,17 @@ android:exported="true" tools:replace="android:exported" /> + + + + + + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 00d91a6..2a9b492 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -565,6 +565,27 @@ android:exported="false" android:screenOrientation="unspecified" /> + + + + + + + + + ZkbVOUz3}sdl!OG3mpF!foR{&m7JqGn|3Wp@c!x=ATSP_F%x`cD+~ypr>HJbRa&$|G$%XH^?-|X?%s`|A6{$AX}25lg5k?5K_31;Cwbb zaDpZ*a29w3CLBq+@P5N4-i?G`LFwqMMD?)ejFyhU;A^6FRlK6R2Ser9y44Lqm_vw1 zKQHxmG{jd`62fVp_@G35Mtb@-K0f}UnYR_7=Pc~t9ATRN8q{jw$TH*P-T7R56W|{x zus+oa=x?DiJWX`o9XRzA8}nS;oV{9QY+Ysp=V^R&(cHb+ELzrEL4)u2b~k4{ClMQN z^#n$a4QGQJ8v!?u7lUrEN7q$?UqoKquim^y-V%Z5sn?g+OTXprcA&X%%k3^Ddw8R6 zm3gt!fupNa&|fX+)qL1_Tl-~e_|n$?MZjF$x6=qPF|Ki9o{8qT|GkhH7!=rRaG4HR zcHX@v40djK54y>c$V@jp-Z@>l`be_;CF$HeTl7Bl=AYaMkbb{)YJ9se9p2(&g!5w} zp6qt7_lXRk&EDJI^y^jpIzi2@t_V9NU$Svh7rlk$zK zktVU?C{Xzi^Icd4%SV5)g{iF7hp@6SHcrL47~M&Nd))=ae&LuR=0N3_pleK7NrWri z<{p~2#2ia)&%Mx@mg*Jj6`(oix`esgJb?Qy%41S-tf$p*<1z1#Am2&L@nh8yO}6KP zhv#tq`b^|Sl=c`+8th?w^pB*txLe1S>zRtXA6JssQ7=m0+ov23{0BsmJ?yQRj3+vn z|E#u1E*bQl3Ms#^@lms%Jf2z^Y8TM#c{ElK%MZn$#azZyy%>h|#sIeG30rAfdn8lD zwno25kkL6W?CLpUdUml+hKy?E_>F`CF}{mAZSBg9hu*DT1Ayr5bggG>iOX^#v!pso zNAJhwOam<+=7P``f8CUwYuwM{!%fj0^z$?sPQF)QX^ZDe|sJv;Hqq!x!8+p%4> zgFSEpGA`zWHcxo6J%5N&j2zmRqVlJm<8p92vH);17S^IcL3NvbR`+Nd#M4)Rca%wA zL;#XE|51P9<(%FtG|Pa?U}|AbP0g+7N08iE|50IH?^6eVu1*@x=*D?1kMk0%Prj5q zI|l}toqxQM`2ZdLZGx39Wb?QjtHIn)kT&EKmbxeVFcyuJ0UPMt6H7f;OQE?qgT5r= zm<6cJNUjw~Gy9?6Q@M)@KoC7_helJ$R#364G)15 za0!NjWl?IPTg8KhlIGl%FB{{2^Y9ymaDJN`!o~@08Fh6Ifi&NO3?CO9!YuDBq~+bs z;Q3>Kr#QF@l^H5G4ZMzuub$GilYZyab6ehm6?j`-U0K3L>tZLbMz9-r5_KqBd7$&b z9dE(@waah<94*NIBPNW#T+X+Iabu7k@44YcODzNO&sVa8HUw9suwBx;GC_dR87zbL z2~rtsjm8E9wf5j&KMbBP9oDYMo=MvxO53Ta-DDXN&HKrco4jX*k&F3TN9*@dQOJ;4 zoj3^Kyj~`w*c|Z<@kiA5pd~8mr9s%p=u0d#@5CvxEJMYqv*Cjz7B4)&nt4+YHDMLm zvb*jK0eR#1bC|Vxfpa;hKKRDjZ68oKPHZlv3^a;QRSM*K9W+g zGct`qQq@_kMa{LWC#g<-<4nrGqByZlpKuRTw14`Oc)zqeR&J)A7Z^($Kp^z0P+oXa zgOdkP9w`(8=_4k)FQet^Uq;F=4V9P0+`RXw9G)Ad+OX^=ViZ)#I8>nc{l0`ih!DcC zUDuuC2^kxzFMof(V@QX;T`Ox95nAsqeG;0fIm~{rfBYiPvx~*>8eEWchOYA^T`r~< zV^kgEi8=Y`*<`5T=*XJk#k&MMI9sK^Vz?M^r!RAJ8hmwt{fvkY8koK_V64N#AhD2P z>H4{P+h@qH&+q?AB9bKqs-RQkRb7e;DN$(H#<%N95|mF(|LpU-$qA$sV!3R+{%eiq zre~c)ID7pz?VQ~FZDNVhP0a+IjJoYk5&T6?EM9fM#XSb<%_^!L&w`*V@H;c zuW?tHesA%cswc(uHrWCipBy4K-^zgmG0O)7o(j!9-4X7mHd2u8Ua4zF>1c9h*Q&0O zS!VkBP&bCQS$@>ik0|tz>(9^1?cOE8>x6Kc4J2~Wvbka_L|DJ!X$k&bO&>KhDatQq z1bI3wXMIeZ%<0x?>GE70Nh3eoM>vUWjo8@tW`<6nP71xcy-Sj8`Z9;^C1KWPh#W-3mxFLNVx5D40KfPg zs)QbbH_vo+C|^;(7gy2q-HQ-)jw5SOGp-740r8+MtNjW=@G<(WZ#|vWwkav_8F>baUP>z0QXu5j+!ww@YwN zn`OYmuk$_j`3>?GS5?`HpqQ5iH%Q{Qjg52WGA7phZX-+6r5pS@D=y4yT-Pud?Id5 zg?uGTnvs)L>G-m%iVI0SYg!CpNR5{EXfhJ@=W^^Q?^n|_x~E3+!5BIK-ny2Ah-FsZ zFpvUOX89EE3B;VVwCk6e2%{Z7l1y*&>qQJ|g1gg~79md-|BadN@I~2>BG;B0pBMHw zd`ObGVQ6NDS>;fax!^E0dM5gKFgaQ)PK3ff@7Z?WFS!Z#%&0;x0*Syn)6m;9=A3=^ z7Nf5ZNO+eX8s#uG8PZ8Wf;K+RBLg35QaATh%*t4SM^4C&3cp7!G)@P)Nuhh6SVW(g zw?Q2mu%6Thg)qsDR+Tud!K)k34}n@N1kAz3L6BX+J@$?4S@NR)iA>nF*rpif9{062 z4Iud~BTNUwUm{653_U)^Pz*n$%XIj4DHDHo_Z!6sA&AJW&%gu7WRm`*W}F3&X(VHb zl@x)+8@ePxB(7c(khea8<8QfkH+bN8IdpMS+{v_J3M7zG!6DVsYuB)9 zhG8r_Wh9c&5!uoa@qM{~X6;je!^KO=p)k%uEuFt45gwg&NCtXL)-;wi(@!>bTO0zoYK1`yRxT^kvJUvH z=NAa{BSlL9^QwZ}{Cmp6vW3w2hlmadab2X!g|QS3fSn54xU?<#-<_nx!2thMJ0;Ii zHYOFaG<1iNO!e6e%0lp$gvS=kiL>B@w`3sSY08BCKG{vnFC$bSK>lnWUON@U?$$gg zN;hAAi`P4*A4Tz|qYu4-G(qN5p^$7?PI}^Sz=YGCWFTs9^d~9&)|0#P@+z|*V`KOo z9h{F#0Vx0;#03+PrJrL}F!p1+8sc=VXj<*#S!#8RBWXv}*YJgd-S8N&8*d5L<|2ru z4p&Hp9WEz&Utj9{>A?+n^yqy1Dbs(P(Rldai{`SCjt#zo&+w?Q4(SCXB33`cRHxk5 zC5$)3ScMprf~oOYKN6*eU)fDuTY!!5S)pnl!HM{|Fj-B;H{eQqR>lAtoXG_J`)d6% z*pG4*5T16(!%Aqm_}6nN`k#_m^&XGcby+5KxVC=dzp8-Y2&AB9q`=AqGLX#R41!3& z`rUI1vk#~8LEX*Ybx-&u{@R5o0@^}THU)3|Dvn{?y)_;$R9v?Gy-3ioesHLP27)cu(v!ybooxbgZUKmoM#ZGw z=pe&(I)o+^s+V5;Spwt4E1S>u0UO@|jXu#QRdZkEiNY2rkCGUqxdzy4Fg?)4p$IT$-0YN)Vx@^D?(X-0L!%oBN)))q+ zbV9*wK+hEI;pQx@;i~p##tM{#hK-pjnb-a2d;z>vn=knMwnX!8D`kk2n`!`%{~nYr zWr%tj^{pY7+E$f{!`xL(PF{pDOHtP3lvU@7&W2f=aQ&HEkNh(PN(;J6$^=qa4XtpM zJEe0NVbra%a43aEgC8~qx-4vb?+4xfk(@hq8!2QlE4!PiMzv{*eqiGe_VoA{dkLio zRk)>X2^V-mc$z_)B@?Hmm|8u6S_&^GD{3LGpm_HOrm_>ITxdls%D~fZf7z9!2qfv% z?(VjgC1nl5V7W#4*p&h zgf?Q?7psA698JHiOEADy+fk0-N2T|~&j0+)P+|LMbHq)Y8gV1oy}PRe$fDi<{X(u> z4V0X&Jup-fJvEX2-ThzR{a>#4ceAr;DP>WFoyOsj-XfzA0gcI!MuCK2zWeGnekgY$ zHMfNjbmjva&I6a2iZtZ!L=jql)}h@`^~F8)HZDeG=aMN#T%$ISIv>sOB`HQqZ!I`? z7XIuqlzs4Q*N#i5jmbI&tdfE>Wa4PrD3?X)`nclbzrRw{*-oipm%aw;kQXF}7cb*} zC`ovXZ#E4*6CW1A&b?KG55#9vENNT7s{cIeRTiA4$z=@temZjcy>hFMamh5n>fT+XamL601^P1(twTE?K9Rp21DVTybpP|>MXDbNaG8^w^A z7O~j0F1|sm=lrvgFp^QmTHERS-K(n%fj7V2SlG8{)!(NmxvHj}e4EqkKiTfK!CIea z0QWW{XQ#Kf$0hw*D@9e0P^(GX;Vt+JpDP>+T4H-knrUv~rEv}ddoSSCVOgUcUu6x(1DBWx5TG+OIvB#lMFWbhBc`*K42bo;?dvrGdT0W>w|ci zkHW8Za0p2(v{6bK7>yJkG9FA%$_adu`%~u?mpr1Xj*?Kt5oRsp3797p2PX1Rq$xp6ZEwYw#8d9w(@O-VBXP85wo=ozrV@0EJ4zlX$ z5E3t155;^V(7}`P3LFU|vd#cO^Km)xCtK6ozl#&HA4Zz8U}-sMYbeNwVfUZcq>#F+91wxl`2&G)zL-^9 zR+A)(HQ{yj08gGOFI5Y_bxBr8nzmuKsjpzM zXh)T7VhaAYl(?SUpRs_kETRrHXBq~M{%5<38``$iveF7Wmd~2g7q|(|i%aWL)}W=V zE+|xACEf405+0V$AQZDd23iBBEc&M9o9K~EUdZlUtDj~=TBw*e3jN2{E)5qo3OG7D zI)R4euAEw&i|{ig;*q*acnw3%p(+q5OE)Y7`8I>RO#H_$5)gsx!*%E7gyG0uzB`Dn~aasFA4Ip$H##6FgF(^?)e< zSv#{+I8wek;Jk|Y__XYf`PuZf?z+7wuMEsdK@QBkoe-3S*rkGgep#<3Kj$=ODJ@&? zwOTq^@VW|W-h81-eg|VAlTl9{}AME7iSVqyFZ?yRKz?f?A*Wt(!Edmiwb2q zODu3QGEDA|DqqH6k*(ua4bv4-YWre#3DE>8mW*)GS>deLUSEx)+y5G6NEo>U<6NFQ z0)>40_r8xeZyazqJ3GBx#aqH1i*)G;tsglnJ2`O=dND*#n|;xhaio0cXpb~FZ4jA; z0rw9w$ywbHlEp>dZYNrp3Z6hnBX|Z=H~~VYp(pTQ3$i(LlI1&XAfDg z?7)eDAaN!{e51kFKMH52xp--ZM0+ze10o;570DiW&SlCX^cF%PO}e0HgiHi-?vS+@ z^wje&%%$w{TDl@B6#nFg%do*ZYigLdqeUYA1pDe>btes*_>YeTT-S$8Zh{k)M`O<%hkcjwJK?RXi;2pt+LPAMh#sEa-njG^| zdToPanmyX>chWkk+t#^c7m*Yt(R2zMf}4#{Z>H|5N$k(G(bgy)REF#;nA2vvC>jp* z63~gHVNO~w*fTfmoE*P7YhcW(5R~S84G>>W3)!ZxQOPaaAjWC8~_wBQaUAJn^DHHdb-tb0EWLmwsL-oFKh)<7UY>t6Rz}j z;N-8CBj4M;xM|4D{&w81HIKJ*wtH?_Ks2v^{pHubnbrQr3tAm}9npb6Iw$`u;UG>0 zl5Z700KZ(U`1Vmceh=Ci7>@2MMzlP(@HRCO_vC@`g2ga6=SCH`vH{%Dv>EisUM-$toUHau-E!9yeCQPKG9%`We6UNVx-4rd>d&DdbtU|F<+|@~ypPIP| zr|z>}t(!Krx zdDyHk-ZKat2tuxvvzP{;&5nbK9PD_*u+8akz(Hq8x9I4mH-5=(eB>f=a z3a_g#C}71qYC{qooyAHy4uC>a7N*Aw-zn=*cS8z0HJ$%IPoZyw$Gh19D;r8U?yb_$M3(+R?Gc7 zGoerktoh_HEiIAML2^l|(q#GgGbmv^-kk;91ohPq(?v5_Br&$7ntbgu>ytU}6PjUY zavQ*7X=Ppb*b?fr88t>lYKM)D@J}4MDUTd#>5W-iW2cFrXg!?8|*whbA}R1 z&6?q8foZ$|HcY`Gil2vXBXXNHYISDbv7Mma#7uzRW|o>pCW+A{cTHRsDPvuDfc&;mzSaW(ze>l0Dy6@B^O{r=WGfWaiB||zpzV*soI%htA)ngV$x;6Ko z8MJcJq0MspvXA9D=^b-N-)p3X_cZV4&SQMgzyiqh;0rT{E04o|L}`p{r!%YxVA;AJ zg4$lKGGh+z5f~P6X*FP*kNz@In-S|-Gazv!t9NI4f_#r~pQAjOT)rbfSA#yHY$Hb! zhpbUeTw3232mNfGLIGP+oEWW+yp-Tmu%Cy5j8*<{r4higQ?3;0^L>FEl{C-7(Y?q% z8&jgSg|EMPYOJui?Ll1dIgRJtOzDTK4DCK8s3}e9DdP{c!bSO=IF>$fm(qOQ0xc<5 z5A!2uPD&1ggYaI7Tr0bh@Y8Q_EIlVA3%H-Y5E2z^&JY50KsW6~)WB(viKNxnJTr0S z(-sJ3co=`z;c39=G2+TEoqn*#3yNn+&gYyzGo%EHGEvz33+=L@S^P7VtJyn~YA=BG z$q{l4J#jW-s{;WN-QXjQ@a{EiL`RbISE(-V7{WCx8q7@nBk4F2fz)ld37jINwQmhX zkPJ43$kD*SBpyiR=quziKD;TCmQ>Ghy~#2M+=?$RZq4(SlQ&F|NZ&cHCMFdKVKwx9 z>)c1Kv)C62TbefYS}&TEm}aq+3WV?Tts?~aLFuv#7mk~z$u8cW2E7k7=7k~A3MO?D zfDc`hO)P&!jt@qBaHP2!R><1D+`;9v{nRBx!wT5OpCYp%t5DN)^a^o2+CU(xswB-R zn_s=7ad(x+axeaVaJJgM8ECUe4+j8wooKSINV^Iok&5yY-f+6w9p?la2!f?W@`B%B zN2W+8d(rh49GKQ-QuSw+HrU>r3`goU3bwTfujW1qUc*T*ySv{)Hq~RVo@T2c)_!VqB6%le){akB$?75 z{2laCV1g)%b&ua{Ru<-juIu5lDX8=Hi7RHGjiy_eO+=7MUsUj5(CIk1C})^A$U!? zN$!aGd~u0{H#3YbbYFC#M-x6p(p}yVR?%Rr+QPh8WfN*>6!G0RCvvk*3_iXu4asv} zgGB@~`gFC>XqH`*4Ayd>XYMloafAd}gziabPxD5)I-B$(H#GmC4i)T7X*KmTEAU5; zq&tyQ2*re8X@U|WBe`24^4wBv-H00Ift^fU-;P&K>uw^+hPVY}N$1<#_I7#jc641# zB2K)zLFqKMm+GlnR0&eMzNE%Ou6f#0Yl<|>ooD`H{(NbcpR^%6xgYC|BtJcV!I!O9 zPkxt{$DsT2omOSiqK0vM=nI&pw_phqdy1duc*D7m7LUeCEk}#B;p?}m z+mEn!N7jlC*J2EKw$h~4f(8@ekmk?c#m}#rn`tDzA@Wa;$6nn#?`<8b01Pg6%jK;3 z@G|OS=;*kU^;gU?|aZMbUd3X84i*+o2e;B-1>HNj|1}b_6w-Z>JC;RM+L^kvA z9T{`NgNdU14e$AlVA;0<p>_)Ql?W3+9zZs5Ks5@Uo1tOh#@(bYfF7*CyAb zbk$5sD^*|xMWg0jKg+KV09ob^r_q$_s{_P<RcD>v{@lvBBk9i^r`C}dYU|K*6@_aBB=N{2@`*Sb<hc+-k2vs!jx1?2bA}9LmeYYsnBT#7Nyw& z8cyyJ2t3~3zH+0uh+TY>Sy+c3J>KV^m1219L8}Rs32`yXL?50Lj zjf3zcG!8^tbkq2E^nfY3o{gm@mPYNcPd}lRdu?d*=+3vq$R1|8Wi>Y^em6wcd?ABY zYUAyaEn(D?8LZpR<9Z#W<&+aR!bp*3#t+0v4kteGt2~K*gkGMuY_;CIB{+ni62f(f z@DGZ2+-pX|t@J2&pJ+el^%5(VnT?mjQf11WZRM+zE1@SppO$0ye?&95z;= zP_~gpHz7kZg(g!tFkw9FXjM(-V@Sy@`Ijh(^2jyQG*w)eKm?rt<21@N~g z4FE}MhQoHhRYlr2nS`0W@+Bj|!_7q}wt7_Ray>a))*>~vM~@oeW2?VvzJcpbNhce8 zEpZq|bBuzX^qqNAi&Yl2gERYAkRMJcvYngPB{k8zuGvO2=c8_4Q91_5HOpuSJy}R{ ziU?KkDz>0_H3|ffTTbpZZ8N{D-&ECSI|JdZs289KBR@<~Z!q83BSvhTSCDFMoxivl zmEvvx$Jt6g!(KL?+y<_A4WxSF8i{oOBC83pf2utUkQ0|WIy;t{I z^~E0%=ZMFtI#b-)t*z=Mfj`OfhrnM?)}?pA^E<@<+QQDqf66pwu*D-nAvZPB3e|o1 z7gxpkKmLn23jWZ4BN(iF_zwoCOhf*I3TpTNpoF^4e_)=5;Qw{mfp;``{*@4FilF?j z(F|;($xHe#^-s|R5ds2(1_A=_uTk&6FF0g?6Wpgs{jdGECJ~g*=f4OWOsIwaFT<=w z1ce~|pUk^BtgMPWBor3(e|>)M2J%ZqM{0jf5wDmK5Xk>!{2PNIrIaBcd>mNZJ$xN3 z-I;wH9sai!T>F=JPz^k#h5sL6Eh3RB_5XBuJG2+BhX9HUM3VN&~F-TwjP>;$F& delta 9535 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

w+8?%v+MQHn=2~&kY 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 + /** + * 国际进港移库-分页查询 + * 接口路径: /IntImpMove/pageQuery + * ⚠️ 后端暂无该模块(2026-07-31 api-doc 核对),按 IntExpMove 命名约定预接,已登记问题清单 + */ + @POST("IntImpMove/pageQuery") + suspend fun getIntImpMoveList(@Body data: RequestBody): BaseListBean + + /** + * 国际进港移库-分页合计 + * 接口路径: /IntImpMove/pageQueryTotal + * ⚠️ 后端暂无该模块,同上 + */ + @POST("IntImpMove/pageQueryTotal") + suspend fun getIntImpMoveTotal(@Body data: RequestBody): BaseResultBean + + /** + * 国际进港移库-批量移库 + * 接口路径: /IntImpMove/move + * ⚠️ 后端暂无该模块,同上 + */ + @POST("IntImpMove/move") + suspend fun submitIntImpMove(@Body data: RequestBody): BaseResultBean + + /** + * 国际进港移库-异常照片上传(pic/originalPic/picNumber 三字段规范) + * 接口路径: /IntImpMove/uploadPic + * ⚠️ 后端暂无该模块,同上 + */ + @POST("IntImpMove/uploadPic") + suspend fun submitIntImpMovePic(@Body data: RequestBody): BaseResultBean + /** * 国际出港库位操作-清仓 * 接口路径: /IntExpStorageUse/updateClear diff --git a/module_base/src/main/java/com/lukouguoji/module_base/router/ARouterConstants.kt b/module_base/src/main/java/com/lukouguoji/module_base/router/ARouterConstants.kt index 700b17f..1a87ea1 100644 --- a/module_base/src/main/java/com/lukouguoji/module_base/router/ARouterConstants.kt +++ b/module_base/src/main/java/com/lukouguoji/module_base/router/ARouterConstants.kt @@ -182,6 +182,7 @@ object ARouterConstants { const val ACTIVITY_URL_INT_IMP_LOADING_LIST = "/gjj/IntImpLoadingListActivity" //国际进港 装机单(分拣理货) const val ACTIVITY_URL_INT_IMP_TALLY = "/gjj/IntImpTallyActivity" //国际进港 理货报告 const val ACTIVITY_URL_INT_IMP_PICK_UP_DLV = "/gjj/IntImpPickUpDLVActivity" //国际进港 提取出库 + const val ACTIVITY_URL_INT_IMP_MOVE = "/gjj/IntImpMoveActivity" //国际进港 进港移库(5.5寸手机端专属页) const val ACTIVITY_URL_INT_IMP_ACCIDENT_VISA = "/gjj/IntImpAccidentVisaActivity" //国际进港 事故签证 ///////////////// 航班查询模块 diff --git a/module_base/src/main/res/drawable/bg_phone_btn_green.xml b/module_base/src/main/res/drawable/bg_phone_btn_green.xml new file mode 100644 index 0000000..d868fee --- /dev/null +++ b/module_base/src/main/res/drawable/bg_phone_btn_green.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/module_base/src/main/res/drawable/bg_phone_card_header_orange.xml b/module_base/src/main/res/drawable/bg_phone_card_header_orange.xml new file mode 100644 index 0000000..d9abdd0 --- /dev/null +++ b/module_base/src/main/res/drawable/bg_phone_card_header_orange.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/module_base/src/main/res/drawable/bg_phone_photo_add.xml b/module_base/src/main/res/drawable/bg_phone_photo_add.xml new file mode 100644 index 0000000..a8ff1e7 --- /dev/null +++ b/module_base/src/main/res/drawable/bg_phone_photo_add.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/module_base/src/main/res/values/colors.xml b/module_base/src/main/res/values/colors.xml index 074da37..a369cd7 100644 --- a/module_base/src/main/res/values/colors.xml +++ b/module_base/src/main/res/values/colors.xml @@ -79,5 +79,6 @@ #6366F1 #FEF3C7 #D97706 + #F59E0B \ No newline at end of file diff --git a/module_gjc/src/main/res/layout/item_gjc_query.xml b/module_gjc/src/main/res/layout/item_gjc_query.xml index def293b..f41cdc7 100644 --- a/module_gjc/src/main/res/layout/item_gjc_query.xml +++ b/module_gjc/src/main/res/layout/item_gjc_query.xml @@ -189,7 +189,7 @@ android:layout_weight="1" android:ellipsize="end" android:maxLines="1" - android:text='@{"代理人:" + bean.orDash(bean.agentName ?? bean.agentCode)}' + android:text='@{"代理人:" + bean.orDash(bean.agentDisplay)}' android:textColor="@color/phone_text_body" android:textSize="13sp" tools:text="代理人:中外运" /> diff --git a/module_gjj/src/main/java/com/lukouguoji/gjj/activity/IntImpMoveActivity.kt b/module_gjj/src/main/java/com/lukouguoji/gjj/activity/IntImpMoveActivity.kt new file mode 100644 index 0000000..6642ad0 --- /dev/null +++ b/module_gjj/src/main/java/com/lukouguoji/gjj/activity/IntImpMoveActivity.kt @@ -0,0 +1,147 @@ +package com.lukouguoji.gjj.activity + +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.gjj.R +import com.lukouguoji.gjj.databinding.ActivityIntImpMoveBinding +import com.lukouguoji.gjj.viewModel.IntImpMoveViewModel +import com.lukouguoji.module_base.base.BaseBindingActivity +import com.lukouguoji.module_base.bean.IntImpMoveBean +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 + +/** + * 国际进港-进港移库(5.5 寸手持端专属页面,无平板版本) + * + * 结构镜像 IntExpMoveActivity(国际出港移库),另有卡片长按「拍照」浮层(设计稿新增交互)。 + * ⚠️ 后端目前没有 IntImpMove 模块,接口按同名约定预接(问题清单已登记)。 + */ +@Route(path = ARouterConstants.ACTIVITY_URL_INT_IMP_MOVE) +class IntImpMoveActivity : BaseBindingActivity() { + + override fun layoutId() = R.layout.activity_int_imp_move + + override fun viewModelClass() = IntImpMoveViewModel::class.java + + /** 筛选弹层显隐(仅 UI 状态,不涉及业务逻辑) */ + val filterPanelVisible = ObservableBoolean(false) + + override fun initOnCreate(savedInstanceState: Bundle?) { + setBackArrow("进港移库") + binding.viewModel = viewModel + binding.activity = this + + viewModel.initDictLists() + + viewModel.pageModel.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, this) + binding.rv.addOnItemClickListener(viewModel) + + // 监听item选择变化事件,更新全选状态 + FlowBus.with(ConstantEvent.EVENT_CHECK_CHANGED).observe(this) { + viewModel.onItemCheckChanged() + } + + // 监听刷新事件 + FlowBus.with(ConstantEvent.EVENT_REFRESH).observe(this) { + viewModel.refresh() + } + + viewModel.refresh() + } + + /** + * 扫码运单号 + */ + fun scanWaybill() { + ScanModel.startScan(this, Constant.RequestCode.WAYBILL) + } + + // ==================== 筛选弹层 ==================== + + fun toggleFilterPanel() { + filterPanelVisible.set(!filterPanelVisible.get()) + } + + /** + * 筛选:重置(只清空弹层内条件,不影响 Tab 与顶部搜索框) + */ + fun resetFilter() { + viewModel.flightDate.value = "" + viewModel.flightNo.value = "" + viewModel.spCode.value = "" + viewModel.awbType.value = "" + } + + fun confirmFilter() { + filterPanelVisible.set(false) + viewModel.searchClick() + } + + // ==================== 卡片长按「拍照」浮层 ==================== + + /** 卡片长按:展开操作浮层(View.OnLongClickListener 要求返回 Boolean) */ + fun showCardActionPhone(bean: IntImpMoveBean): Boolean { + bean.actionMenuVisible.set(true) + return true + } + + /** 点浮层空白处关闭 */ + fun hideCardActionPhone(bean: IntImpMoveBean) { + bean.actionMenuVisible.set(false) + } + + /** 浮层「拍照」→ 拍照上传页 */ + fun openPhoto(bean: IntImpMoveBean) { + bean.actionMenuVisible.set(false) + IntImpMovePhotoActivity.start(this, bean) + } + + /** + * 显示移库确认对话框(底部操作条 setOnActionClick 调用) + */ + 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) { + context.startActivity(Intent(context, IntImpMoveActivity::class.java)) + } + } +} diff --git a/module_gjj/src/main/java/com/lukouguoji/gjj/activity/IntImpMoveDetailActivity.kt b/module_gjj/src/main/java/com/lukouguoji/gjj/activity/IntImpMoveDetailActivity.kt new file mode 100644 index 0000000..183ac90 --- /dev/null +++ b/module_gjj/src/main/java/com/lukouguoji/gjj/activity/IntImpMoveDetailActivity.kt @@ -0,0 +1,46 @@ +package com.lukouguoji.gjj.activity + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import com.google.gson.Gson +import com.lukouguoji.gjj.R +import com.lukouguoji.gjj.databinding.ActivityIntImpMoveDetailBinding +import com.lukouguoji.gjj.viewModel.IntImpMoveDetailViewModel +import com.lukouguoji.module_base.base.BaseBindingActivity +import com.lukouguoji.module_base.bean.IntImpMoveBean +import com.lukouguoji.module_base.common.Constant + +/** + * 国际进港移库「运单详情」(5.5 寸手持端专属页面) + * + * 由列表卡片的「查看详情」进入;「异常照片」卡片的加号槽位跳拍照上传页。 + */ +class IntImpMoveDetailActivity : + BaseBindingActivity() { + + override fun layoutId() = R.layout.activity_int_imp_move_detail + override fun viewModelClass() = IntImpMoveDetailViewModel::class.java + + override fun initOnCreate(savedInstanceState: Bundle?) { + setBackArrow("运单详情") + binding.viewModel = viewModel + binding.activity = this + viewModel.initOnCreated(intent) + } + + /** 「异常照片」加号槽位 → 拍照上传页 */ + fun openPhoto() { + viewModel.dataBean.value?.let { IntImpMovePhotoActivity.start(this, it) } + } + + companion object { + @JvmStatic + fun start(context: Context, bean: IntImpMoveBean) { + context.startActivity( + Intent(context, IntImpMoveDetailActivity::class.java) + .putExtra(Constant.Key.DATA, Gson().toJson(bean)) + ) + } + } +} diff --git a/module_gjj/src/main/java/com/lukouguoji/gjj/activity/IntImpMovePhotoActivity.kt b/module_gjj/src/main/java/com/lukouguoji/gjj/activity/IntImpMovePhotoActivity.kt new file mode 100644 index 0000000..40aba03 --- /dev/null +++ b/module_gjj/src/main/java/com/lukouguoji/gjj/activity/IntImpMovePhotoActivity.kt @@ -0,0 +1,45 @@ +package com.lukouguoji.gjj.activity + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import com.google.gson.Gson +import com.lukouguoji.gjj.R +import com.lukouguoji.gjj.databinding.ActivityIntImpMovePhotoBinding +import com.lukouguoji.gjj.viewModel.IntImpMovePhotoViewModel +import com.lukouguoji.module_base.base.BaseBindingActivity +import com.lukouguoji.module_base.bean.IntImpMoveBean +import com.lukouguoji.module_base.common.Constant +import com.lukouguoji.module_base.ktx.addOnItemClickListener + +/** + * 国际进港移库「拍照上传」(5.5 寸手持端专属页面) + * + * 由列表卡片长按浮层「拍照」或运单详情「异常照片」加号槽位进入。 + */ +class IntImpMovePhotoActivity : + BaseBindingActivity() { + + override fun layoutId() = R.layout.activity_int_imp_move_photo + override fun viewModelClass() = IntImpMovePhotoViewModel::class.java + + override fun initOnCreate(savedInstanceState: Bundle?) { + setBackArrow("拍照上传") + binding.viewModel = viewModel + + viewModel.rv = binding.rv + binding.rv.addOnItemClickListener(viewModel) + + viewModel.initOnCreated(intent) + } + + companion object { + @JvmStatic + fun start(context: Context, bean: IntImpMoveBean) { + context.startActivity( + Intent(context, IntImpMovePhotoActivity::class.java) + .putExtra(Constant.Key.DATA, Gson().toJson(bean)) + ) + } + } +} diff --git a/module_gjj/src/main/java/com/lukouguoji/gjj/activity/IntImpQueryActivity.kt b/module_gjj/src/main/java/com/lukouguoji/gjj/activity/IntImpQueryActivity.kt index f10c084..5d5a28f 100644 --- a/module_gjj/src/main/java/com/lukouguoji/gjj/activity/IntImpQueryActivity.kt +++ b/module_gjj/src/main/java/com/lukouguoji/gjj/activity/IntImpQueryActivity.kt @@ -19,6 +19,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 /** * 国际进港查询列表页 @@ -50,22 +51,35 @@ class IntImpQueryActivity : viewModel.initSpecialCodeList() 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.filterOrigin.et.setUpperCaseLetterFilter() + } else { + // 手机变体:PhoneFilterPanel 的显隐由 XML 直接绑定 viewModel.filterVisible,无需动画代码 + binding.phoneFilterFlightNo?.et?.setUpperCaseAlphanumericFilter() + binding.phoneFilterOrigin?.et?.setUpperCaseLetterFilter() } - // 航班号:大写字母+数字 - binding.filterPanel.filterFlightNo.et.setUpperCaseAlphanumericFilter() - // 始发港:仅大写字母 - binding.filterPanel.filterOrigin.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 { @@ -87,8 +101,8 @@ class IntImpQueryActivity : } 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 diff --git a/module_gjj/src/main/java/com/lukouguoji/gjj/holder/IntImpMoveViewHolder.kt b/module_gjj/src/main/java/com/lukouguoji/gjj/holder/IntImpMoveViewHolder.kt new file mode 100644 index 0000000..20aa602 --- /dev/null +++ b/module_gjj/src/main/java/com/lukouguoji/gjj/holder/IntImpMoveViewHolder.kt @@ -0,0 +1,48 @@ +package com.lukouguoji.gjj.holder + +import android.view.View +import com.lukouguoji.gjj.activity.IntImpMoveActivity +import com.lukouguoji.gjj.activity.IntImpMoveDetailActivity +import com.lukouguoji.gjj.databinding.ItemIntImpMoveBinding +import com.lukouguoji.module_base.base.BaseViewHolder +import com.lukouguoji.module_base.bean.IntImpMoveBean +import com.lukouguoji.module_base.common.ConstantEvent +import com.lukouguoji.module_base.impl.FlowBus +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch + +/** + * 国际进港移库列表项 ViewHolder(5.5 寸手持端专属页面) + * + * 卡片交互: + * · 勾选框点击 → 切换选中并通知 Activity 更新全选/已选计数 + * · 「查看详情」→ 运单详情页 + * · 卡片长按 → 「拍照」操作浮层(XML 绑定 activity 回调) + */ +class IntImpMoveViewHolder(view: View) : + BaseViewHolder(view) { + + override fun onBind(item: Any?, position: Int) { + val bean = getItemBean(item) ?: return + binding.bean = bean + binding.position = position + binding.activity = itemView.context as? IntImpMoveActivity + + // 「查看详情」→ 运单详情页 + binding.llDetail.setOnClickListener { + IntImpMoveDetailActivity.start(itemView.context, bean) + } + + // 勾选框点击 - 切换选择状态 + binding.ivIcon.setOnClickListener { + bean.checked.set(!bean.checked.get()) + binding.executePendingBindings() + + GlobalScope.launch { + FlowBus.with(ConstantEvent.EVENT_CHECK_CHANGED).emit("check_changed") + } + } + + binding.executePendingBindings() + } +} diff --git a/module_gjj/src/main/java/com/lukouguoji/gjj/holder/IntImpQueryViewHolder.kt b/module_gjj/src/main/java/com/lukouguoji/gjj/holder/IntImpQueryViewHolder.kt index 5c618c7..67bd5dc 100644 --- a/module_gjj/src/main/java/com/lukouguoji/gjj/holder/IntImpQueryViewHolder.kt +++ b/module_gjj/src/main/java/com/lukouguoji/gjj/holder/IntImpQueryViewHolder.kt @@ -19,9 +19,9 @@ class IntImpQueryViewHolder(view: View) : // 注册整行点击事件 notifyItemClick(position, binding.ll) - // 侧滑菜单 - 修改按钮 - binding.btnEdit.setOnClickListener { - binding.swipeMenu.quickClose() + // 侧滑菜单 - 修改按钮(平板变体独有;手机变体无侧滑编辑入口,字段为 null) + binding.btnEdit?.setOnClickListener { + binding.swipeMenu?.quickClose() clickListener?.onItemClick(position, 2000) // type=2000表示修改操作 } } diff --git a/module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpMoveDetailViewModel.kt b/module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpMoveDetailViewModel.kt new file mode 100644 index 0000000..9154f69 --- /dev/null +++ b/module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpMoveDetailViewModel.kt @@ -0,0 +1,26 @@ +package com.lukouguoji.gjj.viewModel + +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.IntImpMoveBean +import com.lukouguoji.module_base.common.Constant + +/** + * 国际进港移库「运单详情」ViewModel(5.5 寸手持端专属页面) + * + * 列表项数据已包含详情页所需全部字段,故直接由列表带入,不额外请求接口 + * (后端暂无 IntImpMove 模块,也没有 detail 接口可查,问题清单已登记)。 + */ +class IntImpMoveDetailViewModel : BaseViewModel() { + + val dataBean = MutableLiveData(IntImpMoveBean()) + + fun initOnCreated(intent: Intent) { + val json = intent.getStringExtra(Constant.Key.DATA).orEmpty() + if (json.isNotEmpty()) { + dataBean.value = Gson().fromJson(json, IntImpMoveBean::class.java) + } + } +} diff --git a/module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpMovePhotoViewModel.kt b/module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpMovePhotoViewModel.kt new file mode 100644 index 0000000..98a4cdd --- /dev/null +++ b/module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpMovePhotoViewModel.kt @@ -0,0 +1,152 @@ +package com.lukouguoji.gjj.viewModel + +import android.content.Intent +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.viewModelScope +import androidx.recyclerview.widget.RecyclerView +import com.google.gson.Gson +import com.lukouguoji.gjj.R +import com.lukouguoji.module_base.base.BaseViewModel +import com.lukouguoji.module_base.bean.FileBean +import com.lukouguoji.module_base.bean.IntImpMoveBean +import com.lukouguoji.module_base.common.Constant +import com.lukouguoji.module_base.http.net.NetApply +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.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 + +/** + * 国际进港移库「拍照上传」ViewModel(5.5 寸手持端专属页面) + * + * 图片选择/预览/删除复用 module_base 的 ImageSelectNewViewHolder(末位加号槽位)。 + * 提交走三字段规范(pic 缩略图 / originalPic 原图 / picNumber 数量)。 + * ⚠️ 后端暂无 IntImpMove 模块,提交接口按约定预接(问题清单已登记)。 + */ +class IntImpMovePhotoViewModel : BaseViewModel(), IOnItemClickListener { + + val dataBean = MutableLiveData(IntImpMoveBean()) + + // 图片网格适配器配置(复用公共图片选择组件) + 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) { + val json = intent.getStringExtra(Constant.Key.DATA).orEmpty() + if (json.isNotEmpty()) { + dataBean.value = Gson().fromJson(json, IntImpMoveBean::class.java) + } + + // 已有照片回填(pic 缩略图 + originalPic 原图),末位补加号槽位 + val bean = dataBean.value ?: IntImpMoveBean() + val picList = bean.pic.split(",").filter { it.isNotEmpty() } + val originalList = bean.originalPic.split(",").filter { it.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()) + } + } + + /** + * 确认提交:先补传未上传的本地图片,再按三字段规范提交 + */ + fun submitClick() { + (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() + .filter { it.path.isNotEmpty() } + val bean = dataBean.value!! + bean.picNumber = list.size.toString() + bean.pic = list.joinToString(",") { MediaUtil.removeUrl(it.url) } + bean.originalPic = list.joinToString(",") { MediaUtil.removeUrl(it.originalPic) } + + NetApply.api.submitIntImpMovePic(bean.toRequestBody()) + }) { + onSuccess = { + showToast("提交成功") + 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 -> {} + } + } +} diff --git a/module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpMoveViewModel.kt b/module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpMoveViewModel.kt new file mode 100644 index 0000000..e9bb2de --- /dev/null +++ b/module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpMoveViewModel.kt @@ -0,0 +1,187 @@ +package com.lukouguoji.gjj.viewModel + +import androidx.lifecycle.MutableLiveData +import com.lukouguoji.gjj.R +import com.lukouguoji.gjj.holder.IntImpMoveViewHolder +import com.lukouguoji.module_base.base.BasePageViewModel +import com.lukouguoji.module_base.bean.IntImpMoveBean +import com.lukouguoji.module_base.http.net.NetApply +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.CheckUtil +import com.lukouguoji.module_base.util.DictUtils +import dev.utils.app.info.KeyValue + +/** + * 国际进港移库 ViewModel(5.5 寸手持端专属页面,无平板版本) + * + * 结构镜像 IntExpMoveViewModel(国际出港移库)。 + * ⚠️ 后端目前没有 IntImpMove 模块(2026-07-31 api-doc 核对),接口按同名约定预接, + * 实机会请求失败(问题清单已登记),后端交付后自动生效。 + */ +class IntImpMoveViewModel : BasePageViewModel(), IOnItemClickListener { + + // ========== 搜索字段(设计稿筛选弹层:航班日期 / 航班号 / 特码 / 运单类型) ========== + val flightDate = MutableLiveData("") // 航班日期 + val flightNo = MutableLiveData("") // 航班号 + val spCode = MutableLiveData("") // 特码 + val awbType = MutableLiveData("") // 运单类型 + val moveState = MutableLiveData("0") // 移库状态(默认「待移库」Tab) + val waybillNo = MutableLiveData("") // 运单号 + + // ========== 下拉数据 ========== + val spCodeList = MutableLiveData>(emptyList()) + val awbTypeList = MutableLiveData>(emptyList()) + + /** 状态 Tab 配置(设计稿只有两个 Tab,无「全部」) */ + val moveStateTabs = MutableLiveData( + listOf(KeyValue("待移库", "0"), KeyValue("已移库", "1")) + ) + + /** 状态 Tab 角标(与 [moveStateTabs] 等长) */ + val moveStateCounts = MutableLiveData(listOf("", "")) + + /** 已选数量(底部操作条「已选 N 项」) */ + val selectedCount = MutableLiveData("0") + + // ========== 全选状态 ========== + val isAllChecked = MutableLiveData(false) + + // ========== 适配器配置 ========== + val itemViewHolder = IntImpMoveViewHolder::class.java + val itemLayoutId = R.layout.item_int_imp_move + + /** + * 初始化下拉字典(特码 + 运单类型,type=II 国际进港) + */ + fun initDictLists() { + // flag=1 国际;ieFlag 必须留空——传值后端返回空数组(与既有国际页面口径一致) + DictUtils.getSpecialCodeList(addAll = false, flag = 1, ieFlag = "") { list -> + spCodeList.postValue(listOf(KeyValue("全部", "")) + list) + } + DictUtils.getWaybillTypeList(type = "II", addAll = true) { + awbTypeList.postValue(it) + } + } + + fun searchClick() { + refresh() + } + + /** + * 全选/取消全选 + */ + fun toggleSelectAll() { + val adapter = pageModel.rv?.commonAdapter() ?: return + val list = adapter.items.filterIsInstance() + + CheckUtil.handleAllCheck(list) + updateCheckAllStatus() + adapter.notifyDataSetChanged() + } + + /** + * 更新全选状态与已选计数 + */ + fun updateCheckAllStatus() { + val adapter = pageModel.rv?.commonAdapter() ?: return + val list = adapter.items.filterIsInstance() + + isAllChecked.value = list.isNotEmpty() && list.all { it.checked.get() } + selectedCount.value = list.count { it.checked.get() }.toString() + } + + /** + * 单个item选择变化时调用(从Activity接收事件) + */ + fun onItemCheckChanged() { + updateCheckAllStatus() + } + + /** + * 获取选中的运单 + */ + fun getSelectedItems(): List { + val adapter = pageModel.rv?.commonAdapter() ?: return emptyList() + return adapter.items.filterIsInstance().filter { it.checked.get() } + } + + /** + * 提交移库(在Activity中显示确认对话框后调用) + */ + fun submitMove() { + val selectedItems = getSelectedItems() + + if (selectedItems.isEmpty()) { + showToast("请至少选择一条运单") + return + } + + launchLoadingCollect({ NetApply.api.submitIntImpMove(selectedItems.toRequestBody()) }) { + onSuccess = { + showToast("移库成功") + refresh() + } + onFailed = { _, msg -> + showToast(msg.noNull("移库失败")) + } + } + } + + /** + * 获取列表数据 + */ + override fun getData() { + // 构建筛选参数(只传递非空值;参数名按 IntExpMove 同名约定,待后端交付核对) + val filterParams = mutableMapOf() + + flightDate.value?.takeIf { it.isNotEmpty() }?.let { filterParams["fdate"] = it } + flightNo.value?.takeIf { it.isNotEmpty() }?.let { filterParams["fno"] = it } + spCode.value?.takeIf { it.isNotEmpty() }?.let { filterParams["spCode"] = it } + awbType.value?.takeIf { it.isNotEmpty() }?.let { filterParams["awbType"] = it } + moveState.value?.takeIf { it.isNotEmpty() }?.let { filterParams["moveState"] = it } + waybillNo.value?.takeIf { it.isNotEmpty() }?.let { filterParams["wbNo"] = it } + + val listParams = (filterParams + mapOf( + "pageNum" to pageModel.page, + "pageSize" to pageModel.limit + )).toRequestBody() + + launchLoadingCollect({ NetApply.api.getIntImpMoveList(listParams) }) { + onSuccess = { + pageModel.handleListBean(it) { updateCheckAllStatus() } + } + } + + // Tab 角标计数(复用统计接口,moveState=0/1 各查一次) + loadTabCounts(filterParams) + } + + private fun loadTabCounts(filterParams: Map) { + listOf("0", "1").forEachIndexed { index, state -> + val params = (filterParams + mapOf("moveState" to state)).toRequestBody() + launchCollect({ NetApply.api.getIntImpMoveTotal(params) }) { + onSuccess = { result -> + val count = (result.data?.wbNumber ?: 0).toString() + val current = moveStateCounts.value?.toMutableList() ?: mutableListOf("", "") + if (index < current.size) { + current[index] = count + moveStateCounts.value = current + } + } + } + } + } + + /** + * Item点击事件处理(点击已在ViewHolder中处理) + */ + override fun onItemClick(position: Int, type: Int) { + // 卡片交互均在 ViewHolder / XML 中处理 + } +} diff --git a/module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpQueryViewModel.kt b/module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpQueryViewModel.kt index c23da61..2dd1708 100644 --- a/module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpQueryViewModel.kt +++ b/module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpQueryViewModel.kt @@ -64,6 +64,24 @@ class IntImpQueryViewModel : BasePageViewModel(), IOnItemClickListener { val awbTypeList = MutableLiveData>(emptyList()) val businessTypeList = MutableLiveData>(emptyList()) + // ==================== 5.5寸手机版专属 ==================== + // 三格统计:已入库 / 已出库(总票数复用 totalCount,为服务端全量口径) + // pageQueryTotal 无分项统计出参——已入库/已出库为「已加载数据」客户端计数口径, + // 与卡片状态标签同一判定(dlvTime / inDate,见 IntImpQueryBean) + val storedCount = MutableLiveData("0") + val outboundCount = MutableLiveData("0") + + private var phoneExtrasEnabled = false + private var phoneLoadedList: List = emptyList() + + /** + * 手机形态专属初始化(Activity 在 DeviceUtil.isPhone() 时调用)。 + * 平板端不调用,请求次数与行为零变化。 + */ + fun initPhoneExtras() { + phoneExtrasEnabled = true + } + // ==================== 筛选条件 ==================== val spCode = MutableLiveData("") val flightNo = MutableLiveData("") @@ -165,6 +183,14 @@ class IntImpQueryViewModel : BasePageViewModel(), IOnItemClickListener { }) { onSuccess = { pageInfo -> pageModel.handleListBean(pageInfo.toBaseListBean()) + + // 手机三格统计:对已加载数据做客户端计数(平板不触发) + if (phoneExtrasEnabled) { + val pageItems = pageInfo.list ?: emptyList() + phoneLoadedList = + if (pageModel.page <= 1) pageItems else phoneLoadedList + pageItems + updatePhoneCounts() + } } } @@ -180,6 +206,16 @@ class IntImpQueryViewModel : BasePageViewModel(), IOnItemClickListener { } } + /** + * 手机三格统计(已入库/已出库):与卡片状态标签同一判定口径(dlvTime / inDate), + * 统计范围为已加载的列表数据。 + */ + private fun updatePhoneCounts() { + outboundCount.value = phoneLoadedList.count { it.isQueryOutbound }.toString() + storedCount.value = + phoneLoadedList.count { !it.isQueryOutbound && it.isQueryStored }.toString() + } + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (resultCode == Activity.RESULT_OK && data != null) { when (requestCode) { diff --git a/module_gjj/src/main/res/layout-sw600dp/activity_int_imp_query.xml b/module_gjj/src/main/res/layout-sw600dp/activity_int_imp_query.xml new file mode 100644 index 0000000..ab0223b --- /dev/null +++ b/module_gjj/src/main/res/layout-sw600dp/activity_int_imp_query.xml @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjj/src/main/res/layout-sw600dp/item_int_imp_query.xml b/module_gjj/src/main/res/layout-sw600dp/item_int_imp_query.xml new file mode 100644 index 0000000..5fd2b42 --- /dev/null +++ b/module_gjj/src/main/res/layout-sw600dp/item_int_imp_query.xml @@ -0,0 +1,325 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjj/src/main/res/layout/activity_int_imp_move.xml b/module_gjj/src/main/res/layout/activity_int_imp_move.xml new file mode 100644 index 0000000..c650e7c --- /dev/null +++ b/module_gjj/src/main/res/layout/activity_int_imp_move.xml @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjj/src/main/res/layout/activity_int_imp_move_detail.xml b/module_gjj/src/main/res/layout/activity_int_imp_move_detail.xml new file mode 100644 index 0000000..1f3d243 --- /dev/null +++ b/module_gjj/src/main/res/layout/activity_int_imp_move_detail.xml @@ -0,0 +1,334 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjj/src/main/res/layout/activity_int_imp_move_photo.xml b/module_gjj/src/main/res/layout/activity_int_imp_move_photo.xml new file mode 100644 index 0000000..2b6a422 --- /dev/null +++ b/module_gjj/src/main/res/layout/activity_int_imp_move_photo.xml @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjj/src/main/res/layout/activity_int_imp_query.xml b/module_gjj/src/main/res/layout/activity_int_imp_query.xml index ab0223b..093968d 100644 --- a/module_gjj/src/main/res/layout/activity_int_imp_query.xml +++ b/module_gjj/src/main/res/layout/activity_int_imp_query.xml @@ -1,205 +1,201 @@ + + - + + - + android:background="@color/phone_page_bg"> - - - - - + android:layout_height="match_parent" + android:orientation="vertical"> - + + + + android:layout_height="wrap_content" + android:background="@color/white" + android:orientation="vertical" + android:paddingHorizontal="16dp" + android:paddingTop="16dp" + android:paddingBottom="12dp"> - - + + + + + + + + - - + - - - - - - - - - - - - - + android:orientation="vertical" + android:paddingHorizontal="12dp" + android:paddingVertical="10dp"> - + - - - - - - - + - - - - - - - - + + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginStart="10dp" + android:layout_weight="1" + android:background="@drawable/bg_phone_card" + android:orientation="horizontal"> + + + android:orientation="vertical" + android:paddingHorizontal="12dp" + android:paddingVertical="10dp"> + android:text="已入库" + android:textColor="@color/phone_text_body" + android:textSize="12sp" /> + tools:text="2" /> + + + + + + + + + + + + + + tools:text="2" /> @@ -207,28 +203,131 @@ - - + + android:layout_height="0dp" + android:layout_weight="1"> - - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/module_gjj/src/main/res/layout/item_int_imp_move.xml b/module_gjj/src/main/res/layout/item_int_imp_move.xml new file mode 100644 index 0000000..38d6bdb --- /dev/null +++ b/module_gjj/src/main/res/layout/item_int_imp_move.xml @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjj/src/main/res/layout/item_int_imp_query.xml b/module_gjj/src/main/res/layout/item_int_imp_query.xml index 5fd2b42..241864a 100644 --- a/module_gjj/src/main/res/layout/item_int_imp_query.xml +++ b/module_gjj/src/main/res/layout/item_int_imp_query.xml @@ -1,325 +1,226 @@ + + + + - - - - - - - - - - + android:layout_marginHorizontal="16dp" + android:layout_marginTop="12dp" + android:background="@drawable/bg_phone_card" + android:orientation="vertical" + android:padding="14dp"> + + android:gravity="center_vertical" + android:orientation="horizontal"> - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:layout_weight="1" + android:text="@{bean.wbNo}" + android:textColor="@color/phone_text_title" + android:textSize="16sp" + android:textStyle="bold" + tools:text="78133363396" /> - - + + - + + - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - + + - - - - - + + + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="6dp" + android:text='@{"件数:" + (bean.inPc != null ? String.valueOf(bean.inPc) : "--")}' + android:textColor="@color/phone_text_body" + android:textSize="13sp" + tools:text="件数:444" /> - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_p/src/main/java/com/sixin/module_p/ui/enter/gj/GjViewModel.kt b/module_p/src/main/java/com/sixin/module_p/ui/enter/gj/GjViewModel.kt index d6309af..2348421 100644 --- a/module_p/src/main/java/com/sixin/module_p/ui/enter/gj/GjViewModel.kt +++ b/module_p/src/main/java/com/sixin/module_p/ui/enter/gj/GjViewModel.kt @@ -78,6 +78,20 @@ class GjViewModel : BaseViewModel() { Constant.AuthName.GjjWareHouseActivity, ARouterConstants.ACTIVITY_URL_GJJ_WARE_HOUSE ), + // 进港移库:后端暂无该模块与权限串 AppIntImpMove(问题清单已登记), + // 权限串下发前此入口不会显示;实机验证走 debug 直启 + ActionBean( + "进港移库", + R.drawable.gjc_yi_ku_icon, // 复用出港移库图标(Pad 端无进港移库菜单) + Constant.AuthName.IntImpMove, + ARouterConstants.ACTIVITY_URL_INT_IMP_MOVE + ), + ActionBean( + "进港查询", + R.drawable.gjj_query_icon, + Constant.AuthName.GjjQueryListActivity, + ARouterConstants.ACTIVITY_URL_GJJ_QUERY_LIST + ), ActionBean( "提取出库", R.drawable.gjj_chu_ku_icon, diff --git a/module_p/src/main/res/drawable-xxhdpi/gjj_query_icon.png b/module_p/src/main/res/drawable-xxhdpi/gjj_query_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..0e98155bb88ebfb32e2ee8fc614c558e5b2f97fa GIT binary patch literal 32431 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 LdW0Oj<$?bJtqHOv literal 0 HcmV?d00001