Files
aerologic-app/documents/双端合入主干交接文档.md
YANG JIANKUAN 388d605869 docs: 新增双端合入主干交接文档,修正 CLAUDE.md 过期信息
- documents/双端合入主干交接文档.md:分支状态、平板/手机开发状态、合并内容、
  开发规则、验证覆盖、待决事项与注意事项
- CLAUDE.md:版本 1.8.7 (87);JDK 17 运行 / Java 1.8 编译目标;模拟器路径与
  AVD 名(AeroLogic_Phone sw=394dp / AeroLogic_Tablet);运抵长按浮层与已删除的
  补充信息页;分支约定处链接交接文档

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 23:10:45 -07:00

220 lines
17 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 平板 + 5.5 寸手机合入主干后的交接
> 日期:2026-10-11 | 基线提交:`origin/main @ 131eb03` | 在线版:https://claude.ai/artifact/N8cWdTcMAzk9N86NSPevTC
>
> 本文描述合并当天的状态。分支、版本号等信息如有变化,以仓库为准。
## 接手前先知道这几件事
1. **只有一条开发分支:`main`。** 手机适配分支 `feature/phone-ui-adaptation` 已于 2026-10-11 合入,平板和 5.5 寸手机以后都在 `main` 上一起开发。
2. **业务以平板为准,手机只做界面。** 两端共用 ViewModel、接口、表单项、筛选入参和默认值;差异只能出现在布局(View)层。
3. **同一个页面有两份同名布局**:`res/layout-sw600dp/` 是平板,`res/layout/` 是手机。改平板页面时要同时检查手机布局和这个页面的所有弹框。
4. **有两件事等人拍板**:ULD 保存可能报 500(问题清单 #36),以及手机独有的几个界面功能留不留(见第 6 节)。
---
## 1. 仓库与分支
| 分支 / 位置 | 提交 | 状态 | 建议 |
|---|---|---|---|
| `origin/main` | 131eb03 | 唯一开发分支 | 以后所有开发从这里拉分支、合回这里。 |
| 本地 `main`(主 checkout `~/Development/Projects/aerologic-app`) | 871fa4c | 落后 30 个提交 | 合并是在另一个 worktree 里推送的,主 checkout 还没同步。到那个目录执行 `git pull --ff-only`。 |
| `feature/phone-ui-adaptation`(本地 + 远端) | 42647c2 | 已完整合入 | 不要再往上提交。确认无人使用后可以删除(删除远端分支前先跟团队确认)。 |
| `worktree/phone-adaptation`(仅本地) | 42647c2 | 已完整合入 | 可删除。 |
| `merge/phone-into-main`(仅本地,worktree `~/.herdr/worktrees/aerologic-app/worktree-phone-adaptation` 当前检出) | 131eb03 | 与 main 相同 | 合并时用的临时分支。可以 `git worktree remove` 这个 worktree 后删除分支。 |
合并提交 `131eb03` 的第一父提交是原 main(`871fa4c`),第二父提交是手机分支(`42647c2`),所以 `git log --first-parent main` 仍然是平板的历史。两条线的分叉点是 `9c4588e`:分叉后 main 有 58 个平板提交,手机分支有 29 个提交,合并时共 45 个文件冲突。
## 2. 平板与手机的开发状态
**平板(10 寸横屏)**
- 功能完整,即合并前 main 上的全部功能。
- 合并没有改平板的业务逻辑。冲突的平板布局用三方合并放进了 `layout-sw600dp/`,内容就是 main 最新版。
- 已有手机变体的页面:20 个 Activity 布局 + 11 个弹框布局在 `layout-sw600dp/`。
- 其余平板页面(舱单、理货、组装、航班管理等)只有一份布局,放在 `res/layout/`,没有手机版。
**手机(5.5 寸竖屏)**
- 设计稿 01~11 的 11 个入口全部完成,并已按 main 的新平板功能补齐(见第 3 节)。
- 手机首页是 `module_p` 的 `PDAEnterActivity`,菜单是手写清单(`GjViewModel` / `GnViewModel`),按登录权限串过滤。
- 设计参考:`documents/5.5寸手持端设计文件/`,技术方案 `documents/5.5寸手持端适配技术方案.md`。
### 手机已适配页面
| 首页入口 | 页面(Activity) | 模块 | 说明 |
|---|---|---|---|
| 国际 · 出港移库 | `IntExpMoveActivity`、`IntExpMoveEditActivity` | gjc | 详情 / 编辑与平板共用同一个 Activity,手机布局为「运单详情」样式。 |
| 国际 · 出库交接 | `IntExpOutHandoverActivity`、`IntExpOutHandoverDetailActivity` | gjc | 底部栏带「允许装机」「配运」次按钮。 |
| 国际 · 出港计重 | `GjcWeighingListActivity`、`GjcWeighingStartActivity`、`GjcWeighingRecordListActivity`、`GjcWeighingRecordDetailsActivity` | gjc | 另有手机专属 `GjcWeighingWbDetailActivity`(运单详情)。 |
| 国际 · 出港运抵 | `IntExpArriveActivity` | gjc | 手机专属 `IntExpArriveSubOrderActivity`(分单明细)、`IntExpArriveReceiptActivity`(分单回执);主单回执用两端共用的 `CustomsResponseActivity`。 |
| 国际 · 出港查询 | `GjcQueryActivity`、`GjcQueryDetailsActivity`、`LogDetailActivity`(运单追踪) | gjc / app | |
| 国际 · 出港仓库 | `IntExpStorageUseActivity` | gjc | 平板的「勾选 + 底部批量」在手机上改为卡片四按钮:清仓 / 修改库位 / 出库 / 入库。 |
| 国际 · 进港仓库 | `IntImpStorageUseActivity`、`IntImpQueryDetailsActivity` | gjj | 接口前缀是 `IntImpStorage`,不是 `IntImpStorageUse`。 |
| 国际 · 进港查询 | `IntImpQueryActivity` | gjj | |
| 国际 · 提取出库 | `IntImpPickUpDLVActivity` | gjj | 手机专属 `IntImpPickUpDetailActivity`。 |
| 国际 · ULD 管理 | `UldListActivity`、`UldEditActivity` | app | 一套编辑布局覆盖新增 / 修改 / 详情。 |
| 国内 · 进港移库 | `GnjMoveStashListActivity` | app | 业务归属国内进港移库(DomImpMove)。手机专属 `GnjMoveStashDetailActivity`、`GnjMoveStashPhotoActivity`。 |
手机首页还有一批旧的 PDA 竖屏入口(国际:普货收运、板箱组装、板箱过磅、进港理货;国内:出港收运、出港复磅、出港存放、进港卸机、货物转运、转运记录、事故签证、单证交接)。它们是 `module_p` 原有页面,不在这次设计稿范围内,合并没有改动,也没有验证。
## 3. 这次合并做了什么
### 冲突处理原则
- **布局**:平板布局取 main 最新版,三方合并进 `layout-sw600dp/`,没有冲突残留。手机布局保留原样,再逐页补上 main 新增的业务字段和操作。
- **Bean / ViewModel**:一律取平板逻辑。手机只保留它额外需要的展示字段(如 `opUserDisplay`、统计字段)。
- **Manifest**:取手机分支版本(屏幕方向统一为 `unspecified`),再补上 main 新增的 Activity。
### main 的平板功能同步到手机
| 页面 | 同步到手机的内容 |
|---|---|
| 出港运抵 | 卡片显示海关放行、运单类型;筛选加分单号;回执改走平板同一接口和回执页;长按菜单加「删除申报」(手机底部弹框)。 |
| 出库交接 | 卡片显示装机状态;底部栏加「允许装机」「配运」;配运弹框做了手机变体。 |
| 出港移库 | 详情和编辑改用平板的 `IntExpMoveEditActivity`,删除手机专属 `IntExpMoveDetailActivity`;卡片加「编辑」;筛选加卸货站。 |
| 出港 / 进港仓库 | 清仓弹框加备注,卡片显示清仓备注;入库、出库弹框可填件数和重量(出库弹框新做了手机变体);进港卡片件数取 `pcLabel`。 |
| 开始计重 | ViewModel 整体取平板版本:加运单号、地磅重量、平板车、托盘信息,运抵重量按平板公式自动计算;航班日期 / 航班号 / 航程可编辑。 |
| 计重 / 计重记录 | 计重列表加「新增」按钮;计重记录加航班号筛选,卡片加「运抵申报」入口。 |
| 计重明细 | 重量与托盘自重按平板逻辑联动(和恒定),同时保留手机的输入原文处理(避免光标跳动)。 |
| 进港查询 | 筛选加出库状态。 |
| ULD | 采用平板的来源列表与 HFE 默认值;卡片显示所在港 / 位置。 |
### 手机按平板收敛的地方(使用上能感觉到)
- 删除了平板不传的查询入参:`likeNo`(8 位运单号模糊查询)、进港移库的航班日期 / 航班号 / 特码、出港移库的特码。
- 恢复平板默认查询值:计重、计重记录、提取出库等页面默认查当天,首次打开常常是空列表,属于预期行为。
- 补齐平板有而手机缺的筛选项:运抵分单号、进港查询出库状态、计重记录航班号、进港移库承运人、出港移库卸货站。
- ULD 编辑去掉平板没有的「进港航班号」和手机额外加的必填校验(影响见 #36)。
## 4. 以后怎么开发
项目根目录的 `CLAUDE.md`「5.5 寸手持端双形态适配规范」一节是完整规范,`.claude/skills/phone-adapt/` 是手机适配流程。下面是最常用的几条。
### 布局双变体的硬性约束
- 两个变体**文件同名**:平板 `layout-sw600dp/xxx.xml`,手机 `layout/xxx.xml`。禁止用 `xxx_phone.xml` 加代码判断,那样会生成另一个 Binding 类,进页面就 `ClassCastException`。
- 两个变体的 `<variable>` 名称和类型必须一致。
- Kotlin 里引用的控件 id 两边都要有;只有一边有的 id 在 Binding 里是可空的,代码里要写 `binding.xxx?.`。
- 弹框同样做双变体,并在构造参数里切换位置:`BaseDialogModel(if (DeviceUtil.isPhone()) DIALOG_TYPE_BOTTOM else DIALOG_TYPE_CENTER)`。
- Manifest 新 Activity 的 `screenOrientation` 写 `unspecified`,由 `BaseActivity` 按设备锁方向。
### 平板改了一个已适配页面,标准步骤
1. 改平板布局(`layout-sw600dp/`)和 ViewModel。
2. 打开同名手机布局(`layout/`),补上同样的字段、筛选项和操作入口。平板的批量按钮在手机上可以改成卡片按钮或 `PhoneBottomBar` 的次按钮(`subAction1Text` / `subAction2Text`)。
3. 检查这个页面用到的每一个 DialogModel,新弹框要做手机变体。
4. 手机 Tab 角标、计数这类只有手机用的额外请求,放在 `phoneExtrasEnabled` 一类的开关后面,不能改变平板的请求。
5. 两台模拟器各走一遍,再编译 `./gradlew assembleDebug`。
### 手机端不能做的事
- 不能新增平板没有的查询入参(后端口径:手机筛选一律与平板一致,后端不认识的参数会被静默忽略)。
- 不能改写平板的默认查询值(如默认当天)。
- 不能少平板的表单项或校验,也不能多加平板没有的校验。
### 新做一个手机页面
按 `CLAUDE.md`「手机版页面改造步骤」:`git mv` 平板布局到 `layout-sw600dp/` → 写同名手机布局 → 优先复用 `module_base/.../ui/weight/phone/` 下的组件(`PhoneSearchBar`、`PhoneFormRow`、`PhoneBottomBar` 等)→ 到 `GjViewModel` / `GnViewModel` 加首页菜单入口(最容易忘,忘了在手机上就进不去)。
## 5. 已验证与未验证
验证环境:手机模拟器 `AeroLogic_Phone`(720×1440,API 31,sw=394dp),平板模拟器 `AeroLogic_Tablet`(1280×800,sw=800dp),连内网测试服务。
| 项目 | 结果 | 说明 |
|---|---|---|
| Debug 编译 | ✅ 通过 | 合并后 `assembleDebug` 成功。 |
| 手机 11 个入口主流程 | ✅ 已验证 | 列表、Tab、筛选、详情、弹框打开,无崩溃。 |
| 平板回归(已适配的页面) | ✅ 已验证 | 主要页面打开、筛选、弹框,无崩溃,布局为 main 最新版。 |
| 开始计重自动计算 | ✅ 已验证 | 地磅 500、托盘 2 个 × 18 → 运抵重量 464,与平板公式一致。新增模式头部不再显示 "null kg"。 |
| 手机新弹框(出库 / 入库 / 清仓 / 配运 / 删除申报) | ⚠️ 只打开过 | 样式和字段都确认了,没有点提交,以免改动测试数据。 |
| 所有写操作(申报、出入库、清仓、保存、移库、拍照上传) | ⚠️ 未提交验证 | 合并后没有真实提交过。建议用测试数据逐个点一次提交,平板和手机都要。 |
| 海关回执页有内容时的显示 | ❌ 未验证 | 测试数据里没有带回执的运单。 |
| ULD 管理、国内进港移库 | ❌ 只编译过 | 合并后的改动没在模拟器上点过。 |
| 手机首页旧 PDA 入口 | ❌ 未验证 | 不在本次范围。 |
| Release 包、真机(交付手持机 / 平板) | ❌ 未验证 | 只在模拟器上跑过 Debug 包。 |
## 6. 已知问题与待决事项
### 需要决定
- **ULD 保存可能报 500(问题清单 #36)。** 后端 `saveUld` 在缺少最大装载容积 / 最大载重时返回 500。之前只有手机做了必填拦截;按「以平板为准」去掉之后,两端都可能报错。可选做法:让后端修,或者在平板加同样的必填校验(再同步到手机)。
- **手机独有的界面功能目前保留。** 它们只在手机上发请求,不影响平板,所以合并时留下了:
- 各列表的「待 / 已」Tab,以及 Tab 角标额外发的统计请求;
- 进港移库「已移库」Tab(调用平板不用的 `searchMoved` 接口);
- 出港运抵分单明细页、分单回执页;ULD 状态显示为「可用 / 维修」;ULD 入库时间保存时补 `00:00:00`。
如果要求两端严格一致,需要逐项删除。
### 对用户的行为变化(属于预期)
- 手机列表默认查当天,首次打开常常为空,要在筛选里清掉日期。
- 手机输入 8 位运单号不再能模糊查到(去掉了 `likeNo`),和平板一致。
### 后端缺口(问题清单 #35~#41,待后端处理)
- ULD 列表按 uld 搜索返回 500;`saveUld` 缺 maxVolume / maxWeight 返回 500(#36)。
- `IntImpStorage/pageQuery` 列表过滤全部不生效。
- 出港仓库列表与统计的口径不一致。
- 已移库数据没有 `mawbId`,无法补传照片。
完整内容和每一项的后端答复在 `documents/后端接口对接问题清单.xlsx`。这份表是和后端对接的正式文档,新发现的缺口要继续记在里面。
### 其他待办
- `PhoneSearchBar` 还没接 AutoQuery 联想(`AutoQueryManager` 只接了平板组件)。
## 7. 容易踩的坑
1. **API 文档的 token 提交进了仓库。** `.mcp.json` 里写着 api-doc MCP 的 `Authorization: Bearer …`,并且已被 git 跟踪。建议轮换这个 token,改为从环境变量或本地未跟踪的配置读取。
2. **换行符混用,没有 `.gitattributes`。** main 原有文件多为 CRLF,手机分支新建的文件是 LF。编辑时保持文件原有换行符,否则会出现整文件 diff,合并和 review 都会很难看。
3. **没有手机变体的平板页面,在手机上会直接显示平板布局。** 给手机首页加入口前,必须先做手机布局。
4. **后端会静默忽略不认识的参数。** 猜错参数名会得出「后端不支持」的误判。入参出参一律用 api-doc MCP 核对,流程见 `.claude/skills/phone-adapt/references/api-doc.md`。
5. **XML 里 `??` 兜底不生效。** 网络层会把 JSON null 转成空串,`??` 只判断 null。要在 Bean 上写计算属性(如 `agentDisplay`、`opUserDisplay`)。
6. **RecyclerView 里给 item 设 `GONE` 不会收起高度。** Tab 过滤要在数据层过滤后整体 `refresh`。
7. **Intent 传递的 Bean 里 `@Transient` 字段会变成 null**(`checked`、`showMore` 等)。接收方要 `.map { it.copy() }`。
8. **同页多个手机复合组件会串状态。** 新写同类组件要覆写 `dispatchSaveInstanceState` / `dispatchRestoreInstanceState`(见 CLAUDE.md)。
第 5~8 条在 CLAUDE.md「常见编译错误速查」里都有详细说明和修复方式。
## 8. 环境与工具
- **工具链**:Gradle 用 Java 17 运行(`mise.toml`),编译目标是 Java 1.8;当前版本 1.8.7(versionCode 87)。
- **内网**:测试服务器在内网,模拟器要在内网环境下才能拉到数据,否则提示「接口访问失败」。测试账号向项目负责人索取(不写在文档里)。
- **登录不保留**:冷启动后要重新登录。
- **Debug 直达页面**:`app/src/debug/AndroidManifest.xml` 把适配页设为 exported,可以直接拉起(只在 Debug 包生效)。
- **平板模拟器没有物理按键**,`adb shell monkey` 拉起会失败,改用 `am start`。
- **手机模拟器**上软键盘弹出时按返回键,有时会被吞掉并退出到桌面,不是崩溃。
- **mobile-mcp** 偶尔识别不到 `emulator-5554`,可以直接用 adb。
```bash
# 启动模拟器(模拟器可执行文件在 Homebrew 的 android-commandlinetools 下)
/opt/homebrew/share/android-commandlinetools/emulator/emulator -avd AeroLogic_Phone &
/opt/homebrew/share/android-commandlinetools/emulator/emulator -avd AeroLogic_Tablet &
# 编译安装
./gradlew assembleDebug
adb -s emulator-5554 install -r app/build/outputs/apk/debug/*.apk
# 拉起登录页(平板没有物理键时用这个)
adb -s emulator-5556 shell am start -n com.lukouguoji.aerologic/com.lukouguoji.module_base.LoginActivity
# 确认设备形态识别
adb -s emulator-5554 logcat -d -s BaseActivity:D # PHONE(sw=394dp) / TABLET(sw=800dp)
```
## 9. 关键文件索引
| 文件 | 用途 |
|---|---|
| `CLAUDE.md` | 项目规范总入口,包括双形态适配规范、分支约定、常见错误速查。 |
| `CHANGELOG.md` | [Unreleased] 下「手机适配分支合入主干 · 2026-10-11」是本次合并的完整记录。 |
| `documents/后端接口对接问题清单.xlsx` | 与后端对接的正式问题清单(#1~#41)。 |
| `documents/5.5寸手持端设计文件/` | 手机设计稿(HTML)。 |
| `.claude/skills/phone-adapt/` | 手机适配流程,含 api-doc、组件、平板安全、验证等参考。 |
| `module_base/.../util/DeviceUtil.kt` | 手机 / 平板判定(sw ≥ 600dp 为平板)。 |
| `module_base/.../ui/weight/phone/` | 手机公共组件,适配器在 `PhoneWidgetKtx.kt`。 |
| `module_base/.../MyApplication.kt` | AutoSize 设计基准(手机竖屏 390×844,平板横屏 1152×720)。 |
| `module_p/.../ui/enter/gj/GjViewModel.kt`、`gn/GnViewModel.kt` | 手机首页国际 / 国内菜单清单。 |
| `app/.../HomeFragment.kt` | 平板首页菜单,手机入口的权限串和路由要以它为准。 |