- 手机版列表(三色状态标签卡片 + 筛选弹层 + 浮动新增 + 全选/批量删除)、 一套 activity_uld_edit 手机布局按 pageType 覆盖 ULD 新增/修改/详情三态 (详情右上铅笔进修改、状态底部选择面板、所在港默认 HFE、手机端必填校验); 平板布局迁至 layout-sw600dp,Kotlin 双端共用,平板端实机回归零变化 - 新增公共组件 PhoneFormRow(行式表单,INPUT/SELECT/DATE/TEXT 四形态, SELECT 内置底部选择面板);PhoneBottomBar 增加 actionDanger 危险按钮样式; 新增 FAB/danger按钮/浅红标签/垃圾桶/铅笔等资源 - ULDBean 补解析接口既有出参 ifNo/efNo/checkInDate/checkOutDate 并预留 source; 批量删除以队列串行调用单条 deleteUld 实现 - 手机首页「国际」Tab 接入 ULD管理入口(ARouter + ComprehensiveUld 权限), 登录→菜单→页面全链路实机验证通过,方向无闪屏,crash=0 - 后端缺口 5 项(状态三态、来源字段、筛选入参、批量删除接口、字段语义) 登记《后端接口对接问题清单.xlsx》#7~#11;skill 沉淀本次踩坑 (FAB elevation 盖弹层、Spinner 异步回调竞态、登录哈希回填) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
92 lines
5.9 KiB
Markdown
92 lines
5.9 KiB
Markdown
# api-doc MCP:接口定义核对流程(阶段 2 必读)
|
||
|
||
适配页面前,**所有用到的接口都要在 api-doc(AgentFox)里核对一遍入参/出参**,
|
||
不要靠平板代码或猜测推断参数名——出库交接就因为猜了 `hoState`(实际是 `handoverState`)
|
||
白白折腾了一轮实机排查。
|
||
|
||
## 连接方式
|
||
|
||
项目 `.mcp.json` 已配置 `api-doc` 远程 HTTP MCP。若会话内 MCP 工具可直接调用
|
||
(`mcp__api-doc__*`),直接用;**若工具没有注入会话**(ToolSearch 搜不到),用 curl 走
|
||
MCP 协议手工调用,三步:
|
||
|
||
```bash
|
||
URL=$(python3 -c "import json;print(json.load(open('.mcp.json'))['mcpServers']['api-doc']['url'])")
|
||
AUTH="Authorization: $(python3 -c "import json;print(json.load(open('.mcp.json'))['mcpServers']['api-doc']['headers']['Authorization'])")"
|
||
|
||
# 1) initialize:从响应头 mcp-session-id 取会话 id
|
||
curl -s -D /tmp/mcp_headers.txt -X POST "$URL" -H "$AUTH" -H "Content-Type: application/json" \
|
||
-H "Accept: application/json, text/event-stream" \
|
||
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"claude-code","version":"1.0"}}}' > /dev/null
|
||
SID=$(grep -i 'mcp-session-id' /tmp/mcp_headers.txt | tr -d '\r' | awk '{print $2}')
|
||
|
||
# 2) initialized 通知(必须发,否则 tools/* 报 session 未初始化)
|
||
curl -s -X POST "$URL" -H "$AUTH" -H "Content-Type: application/json" \
|
||
-H "Accept: application/json, text/event-stream" -H "mcp-session-id: $SID" \
|
||
-d '{"jsonrpc":"2.0","method":"notifications/initialized"}' > /dev/null
|
||
|
||
# 3) tools/call(响应是 SSE,`sed 's/^data: //'` 后按 JSON 解析)
|
||
curl -s -X POST "$URL" -H "$AUTH" -H "Content-Type: application/json" \
|
||
-H "Accept: application/json, text/event-stream" -H "mcp-session-id: $SID" \
|
||
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"search_endpoints","arguments":{"keyword":"IntExpMove"}}}'
|
||
```
|
||
|
||
## 可用工具(5 个)
|
||
|
||
| 工具 | 用途 |
|
||
|------|------|
|
||
| `get_project_overview` | 项目概览 + 模块清单(首次调用) |
|
||
| `list_modules` | 全部模块含描述 |
|
||
| `list_endpoints` | 单模块内接口列表(分页,`moduleId` + `cursor`) |
|
||
| `search_endpoints` | 按关键字搜接口(`keyword` 用控制器前缀最准,如 `IntExpOutHandover`) |
|
||
| `get_endpoint_detail` | **核心**:单接口完整契约,schema 已拍平成字段表(`endpointId`) |
|
||
|
||
## 核对清单(每个页面做一遍)
|
||
|
||
对 ViewModel 里每个 `NetApply.api.xxx` 调用:
|
||
|
||
1. 从 `module_base/.../http/net/Api.kt` 拿到 `@POST` 路径 → `search_endpoints` 找到接口 → `get_endpoint_detail`
|
||
2. **入参**:前端传的每个 key 必须能在文档字段表里找到**同名字段**;找不到 = 传了也白传(后端静默忽略,不报错)
|
||
3. **类型**:状态类字段(`moveState`/`handoverState`/`outState`)文档均为 integer,前端传 `"0"` 字符串靠
|
||
Jackson 隐式转换(实测可用);新代码尽量传数字
|
||
4. **出参**:设计稿卡片/详情页的每个展示字段,都要能对上出参字段;对不上就是后端缺口
|
||
5. **结论落两处**:
|
||
- 后端缺口(缺入参/缺出参/数据不回填)→ 记入 `documents/后端接口对接问题清单.xlsx`
|
||
(按「模块 → 页面 → 接口定义 → 接口地址」格式,含前端现状与期望,状态标 ⏳/🔍)
|
||
- 前端可自行解决的(参数名写错、字段绑错)→ 直接改代码,别记成后端问题
|
||
|
||
## 已核对过的语义(别再猜)
|
||
|
||
- `IntExpOutHandover`:交接状态入参 = `handoverState`(不是 `hoState`),**2026-07-29 内网实测过滤生效**
|
||
(传 0/1 分别返回纯净的待/已交接集合,字符串 `"0"`/`"1"` 同样被接受);`ldId` 是**组装人**不是交接人;
|
||
交接人姓名出参 `hoUserName`,编码 `hoId`;查询入参**没有**交接人筛选(后端缺口 #4)
|
||
- `IntExpOutHandover/pageQueryTotal`:**出参恒 0**(任何条件下 totalPc/totalWeight/wbNumber 均为 0,
|
||
与同条件 pageQuery 不一致,后端缺口 #6)——依赖它的 Tab 角标/底部统计显示 0 不是前端问题
|
||
- `IntExpMove`:出参无航班字段(缺口 #1)、无操作人姓名(缺口 #2);`opId`/`opdate`/`businessType`
|
||
文档有定义但实测恒 null(缺口 #3);`pageQueryTotal` 正常(与 pageQuery 口径一致,`moveState` 过滤生效)
|
||
- `typeCode/getSpecialCodeByParam`:`flag=1` 国际,`ieFlag` 必须传空串(传 `"E"` 返回空数组)
|
||
- `eqm/uld`(ULD信息,6 个端点):查询入参仅 `uld`/`status`/`uldSuffix`(uldSuffix 名义是
|
||
"uld后两位",实际就是**按所属航司筛选**,配 `DictUtils.getIntCarrierList`);`status` 仅两态
|
||
0 正常/1 故障(三态需求=缺口 #7);无「来源」字段(#8)、无 `checkInDate`/`ifNo` 筛选入参(#9)、
|
||
无批量删除(#10,`deleteUld` 是 `@Query` 单条);出参 `ifNo`/`efNo`/`checkInDate`/`checkOutDate`
|
||
文档无描述,按命名推断进/出港航班号与出入库时间(#11 待确认)
|
||
|
||
## 内网直调验证技巧(比驱动 UI 快得多)
|
||
|
||
登录态 token 存在 SharedPreference 里,取出后可以直接 curl 后端做行为验证
|
||
(**注意:不要把 token 打印到输出里**,落临时文件引用):
|
||
|
||
```bash
|
||
adb -s <serial> shell "run-as com.lukouguoji.aerologic cat \
|
||
/data/data/com.lukouguoji.aerologic/shared_prefs/data.xml" \
|
||
| grep -o '<string name="token">[^<]*' | sed 's/.*>//' > /tmp/air_token
|
||
|
||
curl -s -X POST "http://192.168.1.250:8093/IntExpOutHandover/pageQuery" \
|
||
-H "Authorization: $(cat /tmp/air_token)" -H "Content-Type: application/json" \
|
||
-d '{"pageNum":1,"pageSize":50,"handoverState":0}'
|
||
```
|
||
|
||
用它做「参数是否生效」的 A/B 对比(同条件只改一个参数看 total 变化),
|
||
再回 App UI 走一遍确认端到端链路。UI 里的滚轮日期选择器可用
|
||
`input swipe`(慢速 500ms、每次 3 格 ≈ 396px)驱动,滑完截图校准。
|