diff --git a/.claude/skills/phone-adapt/references/api-doc.md b/.claude/skills/phone-adapt/references/api-doc.md index 057ce55..62c4e22 100644 --- a/.claude/skills/phone-adapt/references/api-doc.md +++ b/.claude/skills/phone-adapt/references/api-doc.md @@ -85,6 +85,22 @@ curl -s -X POST "$URL" -H "$AUTH" -H "Content-Type: application/json" \ 详情「入库件数/入库重量」= `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) - `IntExpCheckIn`(出港计重,2026-07-29 内网实测):`likeNo` **并非任意模糊**——按 8 位 `no` 匹配(11 位 wbNo 或部分号均 0 条),11 位全号必须走 `wbNo`;`checkIn`/`checkInList` 文档有定义但 `pageQuery`/`pageQueryTotal` **均静默忽略**(缺口 #12,待计重/计重中计数依赖); diff --git a/.claude/skills/phone-adapt/references/proxyman.md b/.claude/skills/phone-adapt/references/proxyman.md index 185056b..d0a2aa4 100644 --- a/.claude/skills/phone-adapt/references/proxyman.md +++ b/.claude/skills/phone-adapt/references/proxyman.md @@ -59,6 +59,10 @@ isFclose 这类「参数是否生效」的 A/B 实验用这条链。给后端提 响应结构照抄真实 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 只是还没画完。 diff --git a/CHANGELOG.md b/CHANGELOG.md index bb6c835..a753159 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,42 @@ ## [Unreleased] ### 新增 (Added) +- 「进港仓库」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(运单号 + 扫码 + 筛选)+ 三格统计 (总票数/已入库/已离港,彩色左边条卡片)+ 状态标签卡片(已离港绿/已入库橙/未入库灰, @@ -34,6 +70,22 @@ (已回归出港计重 4 项弹层,行为不变) ### 验证 (Verified) +- 进港仓库双端验证通过(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 与卡片一致)、 筛选弹层(日期滚轮、特码/代理下拉真实取数、重置、确认后重新查询)、运单号搜索、扫码拉起、 diff --git a/CLAUDE.md b/CLAUDE.md index e7ae668..0481338 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1064,6 +1064,8 @@ DataBinding 适配器统一放在 `PhoneWidgetKtx.kt`(同名属性按控件类 出港查询追加:`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` 文字)。 ⚠️ **弹层与浮动按钮的层级**:`PhoneFilterPanel` 默认无 elevation,页面里有带 elevation 的浮动按钮(FAB)时 会穿透到弹层之上——给弹层实例加 `android:elevation="8dp"`(大于 FAB 的 6dp)。 @@ -1132,6 +1134,21 @@ override fun dispatchRestoreInstanceState(container: SparseArray) = `.checked.set(...)` 会崩溃——接收方 `initOnCreated` 必须对列表 `.map { it.copy() }` 补上。 2026-07-30 review 修正:状态重置弹框改手机底部弹层(弹框双变体首例,见改造步骤第 6 条)、 主列表/回执页补空态、分单浮层补「回执」、分单统计加分母、Tab 角标初始 0 + - 「进港仓库」`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="")`;分项统计为已加载 diff --git a/app/src/debug/AndroidManifest.xml b/app/src/debug/AndroidManifest.xml index a344348..dcccdf0 100644 --- a/app/src/debug/AndroidManifest.xml +++ b/app/src/debug/AndroidManifest.xml @@ -122,5 +122,23 @@ android:exported="true" tools:replace="android:exported" /> + + + + + + + + + diff --git a/documents/后端接口对接问题清单.xlsx b/documents/后端接口对接问题清单.xlsx index 59eab0a..def4f7d 100644 Binary files a/documents/后端接口对接问题清单.xlsx and b/documents/后端接口对接问题清单.xlsx differ diff --git a/module_base/src/main/java/com/lukouguoji/module_base/bean/GjcMaWb.kt b/module_base/src/main/java/com/lukouguoji/module_base/bean/GjcMaWb.kt index 38c926d..8fed403 100644 --- a/module_base/src/main/java/com/lukouguoji/module_base/bean/GjcMaWb.kt +++ b/module_base/src/main/java/com/lukouguoji/module_base/bean/GjcMaWb.kt @@ -162,6 +162,13 @@ data class GjcMaWb( /** 5.5寸手机版:空值统一占位 "--"(空串与 null 都兜底,布局绑定用) */ fun orDash(value: String?): String = if (value.isNullOrEmpty()) "--" else value + /** + * 5.5寸手机版-出港仓库:卡片状态标签(已清仓=绿 / 未清仓=橙,clearNormal 为空视作未清仓)。 + * 已清仓时卡片「清仓」按钮置灰不可点。 + */ + val isCleared: Boolean + get() = clearNormal == "1" + // ==================== 状态转换扩展属性 ==================== /** * 计重状态中文 diff --git a/module_base/src/main/res/drawable/bg_phone_btn_disabled.xml b/module_base/src/main/res/drawable/bg_phone_btn_disabled.xml new file mode 100644 index 0000000..e9ee944 --- /dev/null +++ b/module_base/src/main/res/drawable/bg_phone_btn_disabled.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpStorageUseActivity.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpStorageUseActivity.kt index 34d286a..ce52c87 100644 --- a/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpStorageUseActivity.kt +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpStorageUseActivity.kt @@ -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) } /** diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/dialog/IntExpInStorageDialogModel.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/dialog/IntExpInStorageDialogModel.kt index bac3a9c..46231ef 100644 --- a/module_gjc/src/main/java/com/lukouguoji/gjc/dialog/IntExpInStorageDialogModel.kt +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/dialog/IntExpInStorageDialogModel.kt @@ -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(DIALOG_TYPE_CENTER) { +) : BaseDialogModel( + if (DeviceUtil.isPhone()) DIALOG_TYPE_BOTTOM else DIALOG_TYPE_CENTER +) { // 库位列表 val locationList = MutableLiveData>() diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/dialog/IntExpModifyStorageDialogModel.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/dialog/IntExpModifyStorageDialogModel.kt index 2f5fca8..ec11e20 100644 --- a/module_gjc/src/main/java/com/lukouguoji/gjc/dialog/IntExpModifyStorageDialogModel.kt +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/dialog/IntExpModifyStorageDialogModel.kt @@ -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? = null, private val callback: (IntExpModifyStorageDialogModel) -> Unit -) : BaseDialogModel(DIALOG_TYPE_CENTER) { +) : BaseDialogModel( + if (DeviceUtil.isPhone()) DIALOG_TYPE_BOTTOM else DIALOG_TYPE_CENTER +) { // 库位列表 val locationList = MutableLiveData>() @@ -30,6 +39,13 @@ class IntExpModifyStorageDialogModel( // 库位名称 (后端需要的name) var locationName: String = "" + // ========== 手机卡片级操作专属:原库位单选 ========== + val sourceList = MutableLiveData>(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 } diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/dialog/IntExpMoveClearDialogModel.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/dialog/IntExpMoveClearDialogModel.kt index 8af9afa..2a6e29a 100644 --- a/module_gjc/src/main/java/com/lukouguoji/gjc/dialog/IntExpMoveClearDialogModel.kt +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/dialog/IntExpMoveClearDialogModel.kt @@ -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(DIALOG_TYPE_CENTER) { +) : BaseDialogModel( + if (DeviceUtil.isPhone()) DIALOG_TYPE_BOTTOM else DIALOG_TYPE_CENTER +) { // 清仓正常(存储的是 code:"0" 或 "1") val clearNormal = MutableLiveData("") diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpStorageUseViewHolder.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpStorageUseViewHolder.kt index 7013a5a..8109f37 100644 --- a/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpStorageUseViewHolder.kt +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpStorageUseViewHolder.kt @@ -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(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) } } } diff --git a/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpStorageUseViewModel.kt b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpStorageUseViewModel.kt index 4af85b6..152dc19 100644 --- a/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpStorageUseViewModel.kt +++ b/module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpStorageUseViewModel.kt @@ -17,6 +17,7 @@ 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.model.ScanModel +import com.lukouguoji.module_base.util.DictUtils import dev.utils.app.info.KeyValue import kotlinx.coroutines.launch @@ -38,6 +39,89 @@ class IntExpStorageUseViewModel : BasePageViewModel() { val totalPc = MutableLiveData("0") // 总件数 val totalWeight = MutableLiveData("0") // 总重量 + // ========== 5.5寸手机版专属 ========== + // 筛选弹层显隐 + val filterVisible = MutableLiveData(false) + + // 筛选条件(设计稿弹层 8 项中平板没有的 6 项;平板布局无对应控件 → 恒为空 → 不进请求) + val agentId = MutableLiveData("") // 代理(agentCode) + val spCode = MutableLiveData("") // 特码 + val dest = MutableLiveData("") // 目的站 + val awbType = MutableLiveData("") // 运单类型(pageQuery 无此入参,预留,见接口问题清单) + val businessType = MutableLiveData("") // 业务类型(同上预留) + val goodsCn = MutableLiveData("") // 品名(中)(同上预留) + + // 筛选下拉字典(initPhoneExtras 加载,平板不请求) + val agentList = MutableLiveData(listOf(KeyValue("全部", ""))) + val specialCodeList = MutableLiveData>(emptyList()) + val awbTypeList = MutableLiveData>(emptyList()) + val businessTypeList = MutableLiveData( + listOf( + KeyValue("全部", ""), + KeyValue("普货", "1"), + KeyValue("特货", "2") + ) + ) + + // 三格统计:未清仓 / 已清仓(总票数复用 totalWbNumber,服务端全量口径)。 + // 复用 pageQueryTotal 按 clearNormal=0/1 各查一次(入参 schema 含 clearNormal)。 + val unclearedCount = MutableLiveData("0") + val clearedCount = MutableLiveData("0") + + private var phoneExtrasEnabled = false + + /** + * 手机形态专属初始化(Activity 在 DeviceUtil.isPhone() 时调用)。 + * 平板端不调用,请求次数与行为零变化。 + */ + fun initPhoneExtras() { + phoneExtrasEnabled = true + // 代理(与 06 出港查询同源接口) + launchCollect({ NetApply.api.getIntExpAgentList() }) { + onSuccess = { result -> + val list = mutableListOf(KeyValue("全部", "")) + result.data?.forEach { list.add(KeyValue(it.name ?: "", it.code ?: "")) } + agentList.value = list + } + } + // 特码:flag=1 国际;ieFlag 必须留空——传 "E" 后端返回空数组 + DictUtils.getSpecialCodeList(addAll = false, flag = 1, ieFlag = "") { list -> + specialCodeList.postValue(listOf(KeyValue("全部", "")) + list) + } + // 运单类型(type=IO 国际出港) + DictUtils.getWaybillTypeList(type = Constant.businessType.IO, addAll = true) { + awbTypeList.postValue(it) + } + } + + /** 筛选按钮点击 - 打开筛选面板 */ + fun filterClick() { + filterVisible.value = true + } + + /** 关闭筛选面板 */ + fun closeFilter() { + filterVisible.value = false + } + + /** 重置筛选条件 */ + fun resetFilter() { + flightDate.value = "" + flightNo.value = "" + agentId.value = "" + spCode.value = "" + dest.value = "" + awbType.value = "" + businessType.value = "" + goodsCn.value = "" + } + + /** 确认筛选 - 关闭面板并刷新 */ + fun confirmFilter() { + filterVisible.value = false + refresh() + } + // ========== 全选状态 ========== val isAllChecked = MutableLiveData(false) @@ -301,13 +385,20 @@ class IntExpStorageUseViewModel : BasePageViewModel() { * 获取数据 (重写BasePageViewModel) */ override fun getData() { - // 构建搜索条件 + // 构建搜索条件(手机专属 6 项平板恒为空,不进请求;awbType/businessType/goodsCn + // 为 pageQuery 未定义入参,后端静默忽略,补齐后自动生效,见接口问题清单) val filterParams = mapOf( "fdate" to flightDate.value?.ifEmpty { null }, "fno" to flightNo.value?.ifEmpty { null }, "wbNo" to wbNo.value?.ifEmpty { null }, "location" to location.value?.ifEmpty { null }, - "clearNormal" to clearResult.value?.ifEmpty { null } + "clearNormal" to clearResult.value?.ifEmpty { null }, + "agentCode" to agentId.value?.ifEmpty { null }, + "spCode" to spCode.value?.ifEmpty { null }, + "dest" to dest.value?.ifEmpty { null }, + "awbType" to awbType.value?.ifEmpty { null }, + "businessType" to businessType.value?.ifEmpty { null }, + "goodsCn" to goodsCn.value?.ifEmpty { null } ) // 列表参数 (含分页) @@ -339,5 +430,17 @@ class IntExpStorageUseViewModel : BasePageViewModel() { totalWeight.value = (data?.totalWeight ?: 0.0).toString() } } + + // 手机专属:未清仓/已清仓分项统计(同条件 + clearNormal=0/1 各查一次,平板不发) + if (phoneExtrasEnabled) { + val unclearedParams = (filterParams + mapOf("clearNormal" to "0")).toRequestBody() + launchCollect({ NetApply.api.getIntExpStorageUseTotal(unclearedParams) }) { + onSuccess = { unclearedCount.value = (it.data?.wbNumber ?: 0).toString() } + } + val clearedParams = (filterParams + mapOf("clearNormal" to "1")).toRequestBody() + launchCollect({ NetApply.api.getIntExpStorageUseTotal(clearedParams) }) { + onSuccess = { clearedCount.value = (it.data?.wbNumber ?: 0).toString() } + } + } } } diff --git a/module_gjc/src/main/res/layout-sw600dp/activity_int_exp_storage_use.xml b/module_gjc/src/main/res/layout-sw600dp/activity_int_exp_storage_use.xml new file mode 100644 index 0000000..7719350 --- /dev/null +++ b/module_gjc/src/main/res/layout-sw600dp/activity_int_exp_storage_use.xml @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjc/src/main/res/layout-sw600dp/dialog_int_exp_in_storage.xml b/module_gjc/src/main/res/layout-sw600dp/dialog_int_exp_in_storage.xml new file mode 100644 index 0000000..0d6fee6 --- /dev/null +++ b/module_gjc/src/main/res/layout-sw600dp/dialog_int_exp_in_storage.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjc/src/main/res/layout-sw600dp/dialog_int_exp_modify_storage.xml b/module_gjc/src/main/res/layout-sw600dp/dialog_int_exp_modify_storage.xml new file mode 100644 index 0000000..31919b7 --- /dev/null +++ b/module_gjc/src/main/res/layout-sw600dp/dialog_int_exp_modify_storage.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjc/src/main/res/layout-sw600dp/dialog_int_exp_move_clear.xml b/module_gjc/src/main/res/layout-sw600dp/dialog_int_exp_move_clear.xml new file mode 100644 index 0000000..88206ec --- /dev/null +++ b/module_gjc/src/main/res/layout-sw600dp/dialog_int_exp_move_clear.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjc/src/main/res/layout-sw600dp/item_int_exp_storage_use.xml b/module_gjc/src/main/res/layout-sw600dp/item_int_exp_storage_use.xml new file mode 100644 index 0000000..eea3de2 --- /dev/null +++ b/module_gjc/src/main/res/layout-sw600dp/item_int_exp_storage_use.xml @@ -0,0 +1,419 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjc/src/main/res/layout/item_int_exp_storage_use_sub.xml b/module_gjc/src/main/res/layout-sw600dp/item_int_exp_storage_use_sub.xml similarity index 100% rename from module_gjc/src/main/res/layout/item_int_exp_storage_use_sub.xml rename to module_gjc/src/main/res/layout-sw600dp/item_int_exp_storage_use_sub.xml diff --git a/module_gjc/src/main/res/layout/activity_int_exp_storage_use.xml b/module_gjc/src/main/res/layout/activity_int_exp_storage_use.xml index 7719350..1dd552d 100644 --- a/module_gjc/src/main/res/layout/activity_int_exp_storage_use.xml +++ b/module_gjc/src/main/res/layout/activity_int_exp_storage_use.xml @@ -1,253 +1,327 @@ + - + - + + - + android:background="@color/phone_page_bg"> - - - + android:layout_height="match_parent" + android:orientation="vertical"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + hint='@{"请选择航班日期"}' + title='@{"航班日期"}' + type="@{PhoneDataLayoutType.DATE}" + value="@={viewModel.flightDate}" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + hint='@{"请输入航班号"}' + title='@{"航班号"}' + type="@{PhoneDataLayoutType.INPUT}" + value="@={viewModel.flightNo}" /> - - - - - - - - + + hint='@{"请选择代理"}' + list="@{viewModel.agentList}" + title='@{"代理"}' + type="@{PhoneDataLayoutType.SPINNER}" + value="@={viewModel.agentId}" /> - - - - - - - - - - + + hint='@{"请选择特码"}' + list="@{viewModel.specialCodeList}" + title='@{"特码"}' + type="@{PhoneDataLayoutType.SPINNER}" + value="@={viewModel.spCode}" /> - - + + - - + + - - + + - - + + - + - - - + diff --git a/module_gjc/src/main/res/layout/dialog_int_exp_in_storage.xml b/module_gjc/src/main/res/layout/dialog_int_exp_in_storage.xml index 0d6fee6..6b48409 100644 --- a/module_gjc/src/main/res/layout/dialog_int_exp_in_storage.xml +++ b/module_gjc/src/main/res/layout/dialog_int_exp_in_storage.xml @@ -1,8 +1,13 @@ + - + + android:background="@drawable/bg_phone_panel_top" + android:orientation="vertical" + android:paddingHorizontal="20dp" + android:paddingTop="24dp" + android:paddingBottom="32dp"> - - - - - + + android:layout_marginBottom="24dp"> - - + android:gravity="center" + android:text="入库操作" + android:textColor="@color/phone_text_strong" + android:textSize="18sp" + android:textStyle="bold" /> - + - + - - - - - - + + hint='@{"请选择库位"}' + list="@{model.locationList}" + title='@{"库位号"}' + type="@{PhoneDataLayoutType.SPINNER}" + value="@={model.selectedLocationCode}" /> - - - - - + + diff --git a/module_gjc/src/main/res/layout/dialog_int_exp_modify_storage.xml b/module_gjc/src/main/res/layout/dialog_int_exp_modify_storage.xml index 31919b7..c8c192b 100644 --- a/module_gjc/src/main/res/layout/dialog_int_exp_modify_storage.xml +++ b/module_gjc/src/main/res/layout/dialog_int_exp_modify_storage.xml @@ -1,8 +1,14 @@ + - + + android:background="@drawable/bg_phone_panel_top" + android:orientation="vertical" + android:paddingHorizontal="20dp" + android:paddingTop="24dp" + android:paddingBottom="32dp"> - - - - - + + android:layout_marginBottom="24dp"> - - + android:gravity="center" + android:text="修改库位" + android:textColor="@color/phone_text_strong" + android:textSize="18sp" + android:textStyle="bold" /> - + - + - - - - - - + + hint='@{"请选择原库位"}' + list="@{model.sourceList}" + title='@{"原库位"}' + type="@{PhoneDataLayoutType.SPINNER}" + value="@={model.selectedSourceId}" /> - + + - - - + + diff --git a/module_gjc/src/main/res/layout/dialog_int_exp_move_clear.xml b/module_gjc/src/main/res/layout/dialog_int_exp_move_clear.xml index 88206ec..2a301f3 100644 --- a/module_gjc/src/main/res/layout/dialog_int_exp_move_clear.xml +++ b/module_gjc/src/main/res/layout/dialog_int_exp_move_clear.xml @@ -1,8 +1,13 @@ + - + + android:background="@drawable/bg_phone_panel_top" + android:orientation="vertical" + android:paddingHorizontal="20dp" + android:paddingTop="24dp" + android:paddingBottom="32dp"> - - - - - + + android:layout_marginBottom="24dp"> - - + android:gravity="center" + android:text="清仓操作" + android:textColor="@color/phone_text_strong" + android:textSize="18sp" + android:textStyle="bold" /> - + - + - - - - - - + + hint='@{"请选择清仓正常"}' + list="@{model.clearNormalList}" + title='@{"清仓正常"}' + type="@{PhoneDataLayoutType.SPINNER}" + value="@={model.clearNormal}" /> - - - - - + + diff --git a/module_gjc/src/main/res/layout/item_int_exp_storage_use.xml b/module_gjc/src/main/res/layout/item_int_exp_storage_use.xml index eea3de2..ebbef2a 100644 --- a/module_gjc/src/main/res/layout/item_int_exp_storage_use.xml +++ b/module_gjc/src/main/res/layout/item_int_exp_storage_use.xml @@ -1,7 +1,23 @@ + + xmlns:tools="http://schemas.android.com/tools"> @@ -16,404 +32,243 @@ type="Integer" /> - - + 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_marginStart="8dp" + android:background="@drawable/bg_phone_tag_green" + android:gravity="center" + android:paddingHorizontal="8dp" + android:text="已清仓" + android:textColor="@color/phone_tag_green_text" + android:textSize="11sp" + android:visibility="@{bean.isCleared ? View.VISIBLE : View.GONE}" /> + + + + + - + + android:layout_marginTop="12dp" + android:orientation="horizontal"> - + android:layout_weight="1" + android:gravity="center_vertical" + android:orientation="horizontal"> + + - - - - - - - - - - + android:layout_marginStart="6dp" + android:text='@{"件数:" + (bean.pc != null ? String.valueOf(bean.pc) : "--")}' + android:textColor="@color/phone_text_body" + android:textSize="13sp" + tools:text="件数:111" /> - - - - + android:layout_weight="1" + android:gravity="center_vertical" + android:orientation="horizontal"> + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjj/src/main/java/com/lukouguoji/gjj/activity/IntImpStorageUseActivity.kt b/module_gjj/src/main/java/com/lukouguoji/gjj/activity/IntImpStorageUseActivity.kt index 43c7c77..2447fd8 100644 --- a/module_gjj/src/main/java/com/lukouguoji/gjj/activity/IntImpStorageUseActivity.kt +++ b/module_gjj/src/main/java/com/lukouguoji/gjj/activity/IntImpStorageUseActivity.kt @@ -19,6 +19,7 @@ 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.router.ARouterConstants +import com.lukouguoji.module_base.util.DeviceUtil /** * 国际进港-仓库 @@ -31,10 +32,13 @@ class IntImpStorageUseActivity : override fun viewModelClass() = IntImpStorageUseViewModel::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) @@ -182,6 +186,55 @@ class IntImpStorageUseActivity : }.show(this) } + // ==================== 5.5寸手机版:卡片级操作 ==================== + // 语义等价于「勾选该主单 + 其全部库位」再执行平板的批量操作,复用 performXxx 请求链路。 + + /** 卡片「清仓」(已清仓的卡片按钮置灰,ViewHolder 已拦截) */ + fun cardClear(bean: com.lukouguoji.module_base.bean.GjcMaWb) { + val maWbListForClear = listOf(bean.copy(storageUseList = bean.storageUseList ?: emptyList())) + IntImpMoveClearDialogModel { dialog -> + viewModel.performClear(dialog.clearNormal.value ?: "", maWbListForClear) + }.show(this) + } + + /** 卡片「修改库位」:弹层内先单选原库位(未出库的才可选,单库位时默认选中)再选新库位 */ + fun cardModifyStorage(bean: com.lukouguoji.module_base.bean.GjcMaWb) { + // 已出库的分单不允许修改库位(与平板校验同口径) + val modifiableList = (bean.storageUseList ?: emptyList()) + .filter { it.outOpId.isNullOrEmpty() && it.outDate.isNullOrEmpty() } + if (modifiableList.isEmpty()) { + showToast(if (bean.storageUseList.isNullOrEmpty()) "该运单暂无库位" else "该运单库位均已出库,不允许修改库位") + return + } + IntImpModifyStorageDialogModel(sourceStorageList = modifiableList) { dialog -> + val sourceStorage = dialog.selectedSourceStorage ?: return@IntImpModifyStorageDialogModel + 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())) + IntImpInStorageDialogModel { dialog -> + viewModel.performInStorage(dialog.locationName, dialog.locationId, maWbListForInStorage) + }.show(this) + } + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == Constant.RequestCode.WAYBILL && resultCode == Activity.RESULT_OK) { diff --git a/module_gjj/src/main/java/com/lukouguoji/gjj/dialog/IntImpInStorageDialogModel.kt b/module_gjj/src/main/java/com/lukouguoji/gjj/dialog/IntImpInStorageDialogModel.kt index 83de66b..cb6e6fa 100644 --- a/module_gjj/src/main/java/com/lukouguoji/gjj/dialog/IntImpInStorageDialogModel.kt +++ b/module_gjj/src/main/java/com/lukouguoji/gjj/dialog/IntImpInStorageDialogModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.MutableLiveData import com.lukouguoji.gjj.R import com.lukouguoji.gjj.databinding.DialogIntImpInStorageBinding import com.lukouguoji.module_base.base.BaseDialogModel +import com.lukouguoji.module_base.util.DeviceUtil import com.lukouguoji.module_base.http.net.NetApply import com.lukouguoji.module_base.ktx.launchCollect import com.lukouguoji.module_base.ktx.showToast @@ -16,7 +17,9 @@ import dev.utils.app.info.KeyValue */ class IntImpInStorageDialogModel( private val callback: (IntImpInStorageDialogModel) -> Unit -) : BaseDialogModel(DIALOG_TYPE_CENTER) { +) : BaseDialogModel( + if (DeviceUtil.isPhone()) DIALOG_TYPE_BOTTOM else DIALOG_TYPE_CENTER +) { // 库位列表 val locationList = MutableLiveData>() diff --git a/module_gjj/src/main/java/com/lukouguoji/gjj/dialog/IntImpModifyStorageDialogModel.kt b/module_gjj/src/main/java/com/lukouguoji/gjj/dialog/IntImpModifyStorageDialogModel.kt index a3abae6..ba2905c 100644 --- a/module_gjj/src/main/java/com/lukouguoji/gjj/dialog/IntImpModifyStorageDialogModel.kt +++ b/module_gjj/src/main/java/com/lukouguoji/gjj/dialog/IntImpModifyStorageDialogModel.kt @@ -8,17 +8,26 @@ 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 IntImpModifyStorageDialogModel( private val currentLocationId: String = "", private val currentLocationName: String = "", + private val sourceStorageList: List? = null, private val callback: (IntImpModifyStorageDialogModel) -> Unit -) : BaseDialogModel(DIALOG_TYPE_CENTER) { +) : BaseDialogModel( + if (DeviceUtil.isPhone()) DIALOG_TYPE_BOTTOM else DIALOG_TYPE_CENTER +) { // 库位列表 val locationList = MutableLiveData>() @@ -32,6 +41,13 @@ class IntImpModifyStorageDialogModel( // 库位名称 (后端需要的name) var locationName: String = "" + // ========== 手机卡片级操作专属:原库位单选 ========== + val sourceList = MutableLiveData>(emptyList()) + val selectedSourceId = MutableLiveData("") + + // 选中的原库位对象(保存后由调用方取用) + var selectedSourceStorage: GjcStorageUse? = null + override fun layoutId(): Int { return R.layout.dialog_int_imp_modify_storage } @@ -46,6 +62,19 @@ class IntImpModifyStorageDialogModel( 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() ?: "" + } + } } /** @@ -76,6 +105,10 @@ class IntImpModifyStorageDialogModel( * 保存按钮点击 */ fun onSaveClick() { + if (sourceStorageList != null && selectedSourceStorage == null) { + showToast("请选择原库位") + return + } if (selectedLocationCode.value.verifyNullOrEmpty("请选择库位")) { return } diff --git a/module_gjj/src/main/java/com/lukouguoji/gjj/dialog/IntImpMoveClearDialogModel.kt b/module_gjj/src/main/java/com/lukouguoji/gjj/dialog/IntImpMoveClearDialogModel.kt index a5e5528..c1f0f62 100644 --- a/module_gjj/src/main/java/com/lukouguoji/gjj/dialog/IntImpMoveClearDialogModel.kt +++ b/module_gjj/src/main/java/com/lukouguoji/gjj/dialog/IntImpMoveClearDialogModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.MutableLiveData import com.lukouguoji.gjj.R import com.lukouguoji.gjj.databinding.DialogIntImpMoveClearBinding import com.lukouguoji.module_base.base.BaseDialogModel +import com.lukouguoji.module_base.util.DeviceUtil import com.lukouguoji.module_base.ktx.verifyNullOrEmpty import dev.utils.app.info.KeyValue @@ -13,7 +14,9 @@ import dev.utils.app.info.KeyValue */ class IntImpMoveClearDialogModel( private val callback: (IntImpMoveClearDialogModel) -> Unit -) : BaseDialogModel(DIALOG_TYPE_CENTER) { +) : BaseDialogModel( + if (DeviceUtil.isPhone()) DIALOG_TYPE_BOTTOM else DIALOG_TYPE_CENTER +) { // 清仓正常(存储的是 code:"0" 或 "1") val clearNormal = MutableLiveData("") diff --git a/module_gjj/src/main/java/com/lukouguoji/gjj/holder/IntImpStorageUseViewHolder.kt b/module_gjj/src/main/java/com/lukouguoji/gjj/holder/IntImpStorageUseViewHolder.kt index 68c8fb6..d40ee7e 100644 --- a/module_gjj/src/main/java/com/lukouguoji/gjj/holder/IntImpStorageUseViewHolder.kt +++ b/module_gjj/src/main/java/com/lukouguoji/gjj/holder/IntImpStorageUseViewHolder.kt @@ -2,6 +2,8 @@ package com.lukouguoji.gjj.holder import android.view.View import com.lukouguoji.gjj.R +import com.lukouguoji.gjj.activity.IntImpQueryDetailsActivity +import com.lukouguoji.gjj.activity.IntImpStorageUseActivity import com.lukouguoji.gjj.databinding.ItemIntImpStorageUseBinding 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_header/divider_header/tv_empty + * (多选 + 库位子列表),手机变体含 ll/btn_clear/btn_modify/btn_out/btn_in + * (整卡进详情 + 卡片级四操作按钮)。单侧独有的 id 在 Binding 基类中为 @Nullable,必须判空访问。 */ class IntImpStorageUseViewHolder(view: View) : BaseViewHolder(view) { @@ -22,43 +28,58 @@ class IntImpStorageUseViewHolder(view: View) : binding.position = position binding.executePendingBindings() + // ==================== 平板:多选 + 子列表 ==================== + // 图标点击切换选择状态 - binding.ivIcon.setOnClickListener { + binding.ivIcon?.setOnClickListener { bean.checked.set(!bean.checked.get()) FlowBus.with(ConstantEvent.EVENT_CHECK_CHANGED).tryEmit("check_changed") binding.executePendingBindings() } // 展开按钮点击事件 - binding.ivShow.setOnClickListener { + binding.ivShow?.setOnClickListener { bean.showMore.set(!bean.showMore.get()) } // 初始化库位明细子列表 RecyclerView - setCommonAdapter( - binding.rvSub, - IntImpStorageUseSubViewHolder::class.java, - R.layout.item_int_imp_storage_use_sub - ) + binding.rvSub?.let { rvSub -> + setCommonAdapter( + rvSub, + IntImpStorageUseSubViewHolder::class.java, + R.layout.item_int_imp_storage_use_sub + ) - // 刷新库位明细数据(传递父Bean引用) - val storageUseList = bean.storageUseList ?: emptyList() - binding.rvSub.tag = bean - binding.rvSub.refresh(storageUseList) - updateSubListVisibility(storageUseList.isNotEmpty()) + // 刷新库位明细数据(传递父Bean引用) + val storageUseList = bean.storageUseList ?: emptyList() + rvSub.tag = bean + rvSub.refresh(storageUseList) + updateSubListVisibility(storageUseList.isNotEmpty()) + } + + // ==================== 手机:整卡进详情 + 卡片级操作 ==================== + + val activity = itemView.context as? IntImpStorageUseActivity + + // 整卡点击进详情(复用进港查询详情页,3 Tab 运单/仓库/库位信息) + binding.ll?.setOnClickListener { + IntImpQueryDetailsActivity.start(itemView.context, bean.prefix, bean.no) + } + + // 清仓(已清仓时置灰不可点,样式由 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) } } private fun updateSubListVisibility(hasData: Boolean) { - if (hasData) { - binding.llHeader.visibility = View.VISIBLE - binding.dividerHeader.visibility = View.VISIBLE - binding.rvSub.visibility = View.VISIBLE - binding.tvEmpty.visibility = View.GONE - } else { - binding.llHeader.visibility = View.GONE - binding.dividerHeader.visibility = View.GONE - binding.rvSub.visibility = View.GONE - binding.tvEmpty.visibility = View.VISIBLE - } + binding.llHeader?.visibility = if (hasData) View.VISIBLE else View.GONE + binding.dividerHeader?.visibility = if (hasData) View.VISIBLE else View.GONE + binding.rvSub?.visibility = if (hasData) View.VISIBLE else View.GONE + binding.tvEmpty?.visibility = if (hasData) View.GONE else View.VISIBLE } } diff --git a/module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpQueryDetailsViewModel.kt b/module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpQueryDetailsViewModel.kt index 05f7480..f0383b9 100644 --- a/module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpQueryDetailsViewModel.kt +++ b/module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpQueryDetailsViewModel.kt @@ -61,6 +61,39 @@ class IntImpQueryDetailsViewModel : BaseViewModel() { currentTab.value = index } + // ==================== 5.5寸手机版取值帮助(与出港 GjcQueryDetailsViewModel 同口径) ==================== + + /** + * 从详情 Map 取字符串展示值;数字自动去掉无意义的 .0;空值兜底 "--" + */ + fun str(map: Map?, 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 的展示值(如 by1 优先于 by0) + */ + fun strOr(map: Map?, key: String, fallbackKey: String): String { + val first = str(map, key) + return if (first != "--") first else str(map, fallbackKey) + } + + /** + * 取重量类数值(保留小数形式),空值兜底 "--" + */ + fun dec(map: Map?, key: String): String { + val v = map?.get(key) ?: return "--" + return when (v) { + is Double -> v.toString() + else -> v.toString().ifBlank { "--" } + } + } + /** * 加载详情数据 */ diff --git a/module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpStorageUseViewModel.kt b/module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpStorageUseViewModel.kt index 702680e..5f8e803 100644 --- a/module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpStorageUseViewModel.kt +++ b/module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpStorageUseViewModel.kt @@ -18,6 +18,7 @@ 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.model.ScanModel +import com.lukouguoji.module_base.util.DictUtils import dev.utils.app.info.KeyValue import kotlinx.coroutines.launch @@ -39,6 +40,109 @@ class IntImpStorageUseViewModel : BasePageViewModel() { val totalPc = MutableLiveData("0") // 总件数 val totalWeight = MutableLiveData("0") // 总重量 + // ========== 5.5寸手机版专属 ========== + // 搜索框统一入口(placeholder「搜索运单号/航班号」,phoneSearchClick 分流) + val phoneSearchKey = MutableLiveData("") + + // 筛选弹层显隐 + val filterVisible = MutableLiveData(false) + + // 筛选条件(fdep 为接口入参;其余 5 项为后端未定义入参,预留传参,见接口问题清单 #25) + val fdep = MutableLiveData("") // 始发站 + val agentId = MutableLiveData("") // 代理(agentCode,预留) + val spCode = MutableLiveData("") // 特码(预留) + val awbType = MutableLiveData("") // 运单类型(预留) + val businessType = MutableLiveData("") // 业务类型(预留) + val goodsCn = MutableLiveData("") // 品名(中)(预留) + + // 筛选下拉字典(initPhoneExtras 加载,平板不请求) + val agentList = MutableLiveData(listOf(KeyValue("全部", ""))) + val specialCodeList = MutableLiveData>(emptyList()) + val awbTypeList = MutableLiveData>(emptyList()) + val businessTypeList = MutableLiveData( + listOf( + KeyValue("全部", ""), + KeyValue("普货", "1"), + KeyValue("特货", "2") + ) + ) + + // 三格统计:未清仓 / 已清仓(复用 pageQueryTotal 按 clearNormal=0/1 各查一次) + val unclearedCount = MutableLiveData("0") + val clearedCount = MutableLiveData("0") + + private var phoneExtrasEnabled = false + + /** + * 手机形态专属初始化(Activity 在 DeviceUtil.isPhone() 时调用)。 + * 平板端不调用,请求次数与行为零变化。 + */ + fun initPhoneExtras() { + phoneExtrasEnabled = true + // 代理(国际进港口径) + DictUtils.getIntImpAgentList(addAll = false) { list -> + agentList.postValue(listOf(KeyValue("全部", "")) + list) + } + // 特码:flag=1 国际;ieFlag 必须留空 + DictUtils.getSpecialCodeList(addAll = false, flag = 1, ieFlag = "") { list -> + specialCodeList.postValue(listOf(KeyValue("全部", "")) + list) + } + // 运单类型(type=II 国际进港) + DictUtils.getWaybillTypeList(type = Constant.businessType.II, addAll = true) { + awbTypeList.postValue(it) + } + } + + /** + * 手机搜索框查询:按出港计重实测规则分流——含字母→航班号,其余→运单号 + */ + fun phoneSearchClick() { + val key = phoneSearchKey.value?.trim() ?: "" + when { + key.isEmpty() -> { + wbNo.value = "" + flightNo.value = "" + } + key.any { it.isLetter() } -> { + flightNo.value = key + wbNo.value = "" + } + else -> { + wbNo.value = key + flightNo.value = "" + } + } + refresh() + } + + /** 筛选按钮点击 - 打开筛选面板 */ + fun filterClick() { + filterVisible.value = true + } + + /** 关闭筛选面板 */ + fun closeFilter() { + filterVisible.value = false + } + + /** 重置筛选条件 */ + fun resetFilter() { + flightDate.value = "" + flightNo.value = "" + fdep.value = "" + agentId.value = "" + spCode.value = "" + awbType.value = "" + businessType.value = "" + goodsCn.value = "" + } + + /** 确认筛选 - 关闭面板并刷新 */ + fun confirmFilter() { + filterVisible.value = false + refresh() + } + // ========== 全选状态 ========== val isAllChecked = MutableLiveData(false) @@ -250,12 +354,20 @@ class IntImpStorageUseViewModel : BasePageViewModel() { } override fun getData() { + // 手机专属 6 项平板恒为空,不进请求;agentCode/spCode/awbType/businessType/goodsCn + // 为 pageQuery 未定义入参(后端静默忽略,补齐后自动生效,见接口问题清单 #25) val filterParams = mapOf( "fdate" to flightDate.value?.ifEmpty { null }, "fno" to flightNo.value?.ifEmpty { null }, "wbNo" to wbNo.value?.ifEmpty { null }, "location" to location.value?.ifEmpty { null }, - "clearNormal" to clearResult.value?.ifEmpty { null } + "clearNormal" to clearResult.value?.ifEmpty { null }, + "fdep" to fdep.value?.ifEmpty { null }, + "agentCode" to agentId.value?.ifEmpty { null }, + "spCode" to spCode.value?.ifEmpty { null }, + "awbType" to awbType.value?.ifEmpty { null }, + "businessType" to businessType.value?.ifEmpty { null }, + "goodsCn" to goodsCn.value?.ifEmpty { null } ) val listParams = (filterParams + mapOf( @@ -281,5 +393,17 @@ class IntImpStorageUseViewModel : BasePageViewModel() { totalWeight.value = (data?.totalWeight ?: 0.0).toString() } } + + // 手机专属:未清仓/已清仓分项统计(同条件 + clearNormal=0/1 各查一次,平板不发) + if (phoneExtrasEnabled) { + val unclearedParams = (filterParams + mapOf("clearNormal" to "0")).toRequestBody() + launchCollect({ NetApply.api.getIntImpStorageUseTotal(unclearedParams) }) { + onSuccess = { unclearedCount.value = (it.data?.wbNumber ?: 0).toString() } + } + val clearedParams = (filterParams + mapOf("clearNormal" to "1")).toRequestBody() + launchCollect({ NetApply.api.getIntImpStorageUseTotal(clearedParams) }) { + onSuccess = { clearedCount.value = (it.data?.wbNumber ?: 0).toString() } + } + } } } diff --git a/module_gjj/src/main/res/layout-sw600dp/activity_int_imp_query_details.xml b/module_gjj/src/main/res/layout-sw600dp/activity_int_imp_query_details.xml new file mode 100644 index 0000000..ad3219c --- /dev/null +++ b/module_gjj/src/main/res/layout-sw600dp/activity_int_imp_query_details.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjj/src/main/res/layout-sw600dp/activity_int_imp_storage_use.xml b/module_gjj/src/main/res/layout-sw600dp/activity_int_imp_storage_use.xml new file mode 100644 index 0000000..1d0eab7 --- /dev/null +++ b/module_gjj/src/main/res/layout-sw600dp/activity_int_imp_storage_use.xml @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjj/src/main/res/layout-sw600dp/dialog_int_imp_in_storage.xml b/module_gjj/src/main/res/layout-sw600dp/dialog_int_imp_in_storage.xml new file mode 100644 index 0000000..2dba956 --- /dev/null +++ b/module_gjj/src/main/res/layout-sw600dp/dialog_int_imp_in_storage.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjj/src/main/res/layout-sw600dp/dialog_int_imp_modify_storage.xml b/module_gjj/src/main/res/layout-sw600dp/dialog_int_imp_modify_storage.xml new file mode 100644 index 0000000..d3bc331 --- /dev/null +++ b/module_gjj/src/main/res/layout-sw600dp/dialog_int_imp_modify_storage.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjj/src/main/res/layout-sw600dp/dialog_int_imp_move_clear.xml b/module_gjj/src/main/res/layout-sw600dp/dialog_int_imp_move_clear.xml new file mode 100644 index 0000000..52dc564 --- /dev/null +++ b/module_gjj/src/main/res/layout-sw600dp/dialog_int_imp_move_clear.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjj/src/main/res/layout-sw600dp/fragment_int_imp_query_storage.xml b/module_gjj/src/main/res/layout-sw600dp/fragment_int_imp_query_storage.xml new file mode 100644 index 0000000..6a02988 --- /dev/null +++ b/module_gjj/src/main/res/layout-sw600dp/fragment_int_imp_query_storage.xml @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjj/src/main/res/layout-sw600dp/fragment_int_imp_query_warehouse.xml b/module_gjj/src/main/res/layout-sw600dp/fragment_int_imp_query_warehouse.xml new file mode 100644 index 0000000..e2cd6b3 --- /dev/null +++ b/module_gjj/src/main/res/layout-sw600dp/fragment_int_imp_query_warehouse.xml @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjj/src/main/res/layout-sw600dp/fragment_int_imp_query_waybill.xml b/module_gjj/src/main/res/layout-sw600dp/fragment_int_imp_query_waybill.xml new file mode 100644 index 0000000..7f5dabd --- /dev/null +++ b/module_gjj/src/main/res/layout-sw600dp/fragment_int_imp_query_waybill.xml @@ -0,0 +1,336 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjj/src/main/res/layout-sw600dp/item_int_imp_query_storage.xml b/module_gjj/src/main/res/layout-sw600dp/item_int_imp_query_storage.xml new file mode 100644 index 0000000..7c6937f --- /dev/null +++ b/module_gjj/src/main/res/layout-sw600dp/item_int_imp_query_storage.xml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjj/src/main/res/layout-sw600dp/item_int_imp_query_warehouse.xml b/module_gjj/src/main/res/layout-sw600dp/item_int_imp_query_warehouse.xml new file mode 100644 index 0000000..8c45c70 --- /dev/null +++ b/module_gjj/src/main/res/layout-sw600dp/item_int_imp_query_warehouse.xml @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjj/src/main/res/layout-sw600dp/item_int_imp_storage_use.xml b/module_gjj/src/main/res/layout-sw600dp/item_int_imp_storage_use.xml new file mode 100644 index 0000000..0045227 --- /dev/null +++ b/module_gjj/src/main/res/layout-sw600dp/item_int_imp_storage_use.xml @@ -0,0 +1,433 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjj/src/main/res/layout/item_int_imp_storage_use_sub.xml b/module_gjj/src/main/res/layout-sw600dp/item_int_imp_storage_use_sub.xml similarity index 100% rename from module_gjj/src/main/res/layout/item_int_imp_storage_use_sub.xml rename to module_gjj/src/main/res/layout-sw600dp/item_int_imp_storage_use_sub.xml diff --git a/module_gjj/src/main/res/layout/activity_int_imp_query_details.xml b/module_gjj/src/main/res/layout/activity_int_imp_query_details.xml index ad3219c..2a14f83 100644 --- a/module_gjj/src/main/res/layout/activity_int_imp_query_details.xml +++ b/module_gjj/src/main/res/layout/activity_int_imp_query_details.xml @@ -1,6 +1,18 @@ - + + @@ -14,27 +26,25 @@ - - + + android:textColor="@{viewModel.currentTab == 0 ? @color/phone_primary : @color/phone_text_body}" + android:textSize="14sp" + android:textStyle="bold" /> + + android:textColor="@{viewModel.currentTab == 1 ? @color/phone_primary : @color/phone_text_body}" + android:textSize="14sp" + android:textStyle="bold" /> + + android:textColor="@{viewModel.currentTab == 2 ? @color/phone_primary : @color/phone_text_body}" + android:textSize="14sp" + android:textStyle="bold" /> + + android:layout_height="1px" + android:background="@color/phone_divider" /> + - + - + + - + android:background="@color/phone_page_bg"> - - - + android:layout_height="match_parent" + android:orientation="vertical"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + hint='@{"请选择航班日期"}' + title='@{"航班日期"}' + type="@{PhoneDataLayoutType.DATE}" + value="@={viewModel.flightDate}" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + hint='@{"请输入航班号"}' + title='@{"航班号"}' + type="@{PhoneDataLayoutType.INPUT}" + value="@={viewModel.flightNo}" /> - - - - - - - - + + hint='@{"请选择代理"}' + list="@{viewModel.agentList}" + title='@{"代理"}' + type="@{PhoneDataLayoutType.SPINNER}" + value="@={viewModel.agentId}" /> - - - - - - - - - - + + hint='@{"请选择特码"}' + list="@{viewModel.specialCodeList}" + title='@{"特码"}' + type="@{PhoneDataLayoutType.SPINNER}" + value="@={viewModel.spCode}" /> - - + + - - + + - - + + - - + + - + - - - + diff --git a/module_gjj/src/main/res/layout/dialog_int_imp_in_storage.xml b/module_gjj/src/main/res/layout/dialog_int_imp_in_storage.xml index 2dba956..048e833 100644 --- a/module_gjj/src/main/res/layout/dialog_int_imp_in_storage.xml +++ b/module_gjj/src/main/res/layout/dialog_int_imp_in_storage.xml @@ -1,8 +1,13 @@ + - + + android:background="@drawable/bg_phone_panel_top" + android:orientation="vertical" + android:paddingHorizontal="20dp" + android:paddingTop="24dp" + android:paddingBottom="32dp"> - - - - - + + android:layout_marginBottom="24dp"> - - + android:gravity="center" + android:text="入库操作" + android:textColor="@color/phone_text_strong" + android:textSize="18sp" + android:textStyle="bold" /> - + - + - - - - - - + + hint='@{"请选择库位"}' + list="@{model.locationList}" + title='@{"库位号"}' + type="@{PhoneDataLayoutType.SPINNER}" + value="@={model.selectedLocationCode}" /> - - - - - + + diff --git a/module_gjj/src/main/res/layout/dialog_int_imp_modify_storage.xml b/module_gjj/src/main/res/layout/dialog_int_imp_modify_storage.xml index d3bc331..9151ebf 100644 --- a/module_gjj/src/main/res/layout/dialog_int_imp_modify_storage.xml +++ b/module_gjj/src/main/res/layout/dialog_int_imp_modify_storage.xml @@ -1,8 +1,14 @@ + - + + android:background="@drawable/bg_phone_panel_top" + android:orientation="vertical" + android:paddingHorizontal="20dp" + android:paddingTop="24dp" + android:paddingBottom="32dp"> - - - - - + + android:layout_marginBottom="24dp"> - - + android:gravity="center" + android:text="修改库位" + android:textColor="@color/phone_text_strong" + android:textSize="18sp" + android:textStyle="bold" /> - + - + - - - - - - + + hint='@{"请选择原库位"}' + list="@{model.sourceList}" + title='@{"原库位"}' + type="@{PhoneDataLayoutType.SPINNER}" + value="@={model.selectedSourceId}" /> - + + - - - + + diff --git a/module_gjj/src/main/res/layout/dialog_int_imp_move_clear.xml b/module_gjj/src/main/res/layout/dialog_int_imp_move_clear.xml index 52dc564..b9baf23 100644 --- a/module_gjj/src/main/res/layout/dialog_int_imp_move_clear.xml +++ b/module_gjj/src/main/res/layout/dialog_int_imp_move_clear.xml @@ -1,8 +1,13 @@ + - + + android:background="@drawable/bg_phone_panel_top" + android:orientation="vertical" + android:paddingHorizontal="20dp" + android:paddingTop="24dp" + android:paddingBottom="32dp"> - - - - - + + android:layout_marginBottom="24dp"> - - + android:gravity="center" + android:text="清仓操作" + android:textColor="@color/phone_text_strong" + android:textSize="18sp" + android:textStyle="bold" /> - + - + - - - - - - + + hint='@{"请选择清仓正常"}' + list="@{model.clearNormalList}" + title='@{"清仓正常"}' + type="@{PhoneDataLayoutType.SPINNER}" + value="@={model.clearNormal}" /> - - - - - + + diff --git a/module_gjj/src/main/res/layout/fragment_int_imp_query_storage.xml b/module_gjj/src/main/res/layout/fragment_int_imp_query_storage.xml index 6a02988..77a821b 100644 --- a/module_gjj/src/main/res/layout/fragment_int_imp_query_storage.xml +++ b/module_gjj/src/main/res/layout/fragment_int_imp_query_storage.xml @@ -1,4 +1,14 @@ + @@ -7,130 +17,37 @@ - + android:background="@color/phone_page_bg"> - + android:clipToPadding="false" + android:overScrollMode="never" + android:paddingBottom="16dp" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" /> - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + diff --git a/module_gjj/src/main/res/layout/fragment_int_imp_query_warehouse.xml b/module_gjj/src/main/res/layout/fragment_int_imp_query_warehouse.xml index e2cd6b3..f9cf2fb 100644 --- a/module_gjj/src/main/res/layout/fragment_int_imp_query_warehouse.xml +++ b/module_gjj/src/main/res/layout/fragment_int_imp_query_warehouse.xml @@ -1,4 +1,14 @@ + @@ -7,140 +17,37 @@ - + android:background="@color/phone_page_bg"> - + android:clipToPadding="false" + android:overScrollMode="never" + android:paddingBottom="16dp" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" /> - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + diff --git a/module_gjj/src/main/res/layout/fragment_int_imp_query_waybill.xml b/module_gjj/src/main/res/layout/fragment_int_imp_query_waybill.xml index 7f5dabd..0bd2ca5 100644 --- a/module_gjj/src/main/res/layout/fragment_int_imp_query_waybill.xml +++ b/module_gjj/src/main/res/layout/fragment_int_imp_query_waybill.xml @@ -1,9 +1,24 @@ + - - + @@ -12,322 +27,395 @@ + android:background="@color/phone_page_bg" + android:fillViewport="true" + android:overScrollMode="never"> + android:padding="12dp"> - + + android:paddingHorizontal="14dp" + android:paddingBottom="14dp"> - + + + + + + + + + + + + - + value='@{viewModel.str(viewModel.maWbData, "wbNo")}' /> - + value='@{viewModel.strOr(viewModel.maWbData, "agentName", "agentCode")}' /> - + + + + + + value='@{viewModel.str(viewModel.maWbData, "spCode")}' /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + value='@{viewModel.strOr(viewModel.maWbData, "by1", "by0")}' /> - + - + title='@{"始发站"}' + value='@{viewModel.str(viewModel.maWbData, "dep")}' /> - + + + + + + + + + + value='@{viewModel.str(viewModel.maWbData, "unNumber")}' /> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + android:gravity="center_vertical" + android:orientation="horizontal" + android:paddingVertical="12dp"> - + - + android:layout_marginStart="8dp" + android:text="回执信息" + android:textColor="@color/phone_text_title" + android:textSize="15sp" + android:textStyle="bold" /> - + + + - - - - - - - - - - + value='@{viewModel.str(viewModel.maWbData, "mftStatus")}' /> - + value='@{viewModel.str(viewModel.maWbData, "tallyStatus")}' /> - + value='@{viewModel.str(viewModel.maWbData, "command")}' /> - - - diff --git a/module_gjj/src/main/res/layout/item_int_imp_query_storage.xml b/module_gjj/src/main/res/layout/item_int_imp_query_storage.xml index 7c6937f..c73b07d 100644 --- a/module_gjj/src/main/res/layout/item_int_imp_query_storage.xml +++ b/module_gjj/src/main/res/layout/item_int_imp_query_storage.xml @@ -1,5 +1,16 @@ - + + @@ -15,85 +26,88 @@ + android:layout_marginHorizontal="12dp" + android:layout_marginTop="12dp" + android:background="@drawable/bg_phone_card" + android:orientation="vertical" + android:paddingHorizontal="14dp" + android:paddingBottom="14dp"> + + android:paddingVertical="12dp"> - - + - - - - - - - - - - - - - - + - - + android:layout_marginBottom="12dp" + android:background="@color/phone_divider" /> + + + + + + + + + + + + + + + + + + diff --git a/module_gjj/src/main/res/layout/item_int_imp_query_warehouse.xml b/module_gjj/src/main/res/layout/item_int_imp_query_warehouse.xml index 8c45c70..044195a 100644 --- a/module_gjj/src/main/res/layout/item_int_imp_query_warehouse.xml +++ b/module_gjj/src/main/res/layout/item_int_imp_query_warehouse.xml @@ -1,5 +1,16 @@ - + + @@ -15,95 +26,111 @@ + android:layout_marginHorizontal="12dp" + android:layout_marginTop="12dp" + android:background="@drawable/bg_phone_card" + android:orientation="vertical" + android:paddingHorizontal="14dp" + android:paddingBottom="14dp"> + + android:paddingVertical="12dp"> - - + - - - - - - - - - - - - - - - - - + - - + android:layout_marginBottom="12dp" + android:background="@color/phone_divider" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_gjj/src/main/res/layout/item_int_imp_storage_use.xml b/module_gjj/src/main/res/layout/item_int_imp_storage_use.xml index 0045227..c603527 100644 --- a/module_gjj/src/main/res/layout/item_int_imp_storage_use.xml +++ b/module_gjj/src/main/res/layout/item_int_imp_storage_use.xml @@ -1,7 +1,23 @@ + + xmlns:tools="http://schemas.android.com/tools"> @@ -16,418 +32,243 @@ type="Integer" /> - - + 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:paddingHorizontal="8dp" + android:text="已清仓" + android:textColor="@color/phone_tag_green_text" + android:textSize="11sp" + android:visibility="@{bean.isCleared ? View.VISIBLE : View.GONE}" /> - - + + - - - - - - - - - - - - - - - - - - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 dfbba7b..41412d8 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 @@ -66,6 +66,18 @@ class GjViewModel : BaseViewModel() { Constant.AuthName.GjcQueryListActivity, ARouterConstants.ACTIVITY_URL_GJC_QUERY_LIST ), + ActionBean( + "出港仓库", + R.drawable.gjc_cang_ku_icon, + Constant.AuthName.GjcIntExpStorageUse, + ARouterConstants.ACTIVITY_URL_INT_EXP_STORAGE_USE + ), + ActionBean( + "进港仓库", + R.drawable.gjc_cang_ku_icon, // Pad 端进港仓库菜单同样复用出港仓库图标 + Constant.AuthName.GjjWareHouseActivity, + ARouterConstants.ACTIVITY_URL_GJJ_WARE_HOUSE + ), // ULD管理属综合管理业务(Pad 端在「综合管理」菜单组),手机端首页暂无综合 Tab,挂在国际 Tab 下 ActionBean( "ULD管理", diff --git a/module_p/src/main/res/drawable-xxhdpi/gjc_cang_ku_icon.png b/module_p/src/main/res/drawable-xxhdpi/gjc_cang_ku_icon.png new file mode 100644 index 0000000..6dceea0 Binary files /dev/null and b/module_p/src/main/res/drawable-xxhdpi/gjc_cang_ku_icon.png differ