Compare commits
168 Commits
06713190e0
...
feature/ph
| Author | SHA1 | Date | |
|---|---|---|---|
| 49f11ef8e6 | |||
| eb0655d3fc | |||
| a33776d959 | |||
| b2a2cce585 | |||
| 3b732c3aec | |||
| 33c9f0e030 | |||
| 436202f15b | |||
| ef8e7cfacb | |||
| 1eb288a703 | |||
| 5a019a55c4 | |||
| bbc29ca2e1 | |||
| db062c8ee3 | |||
| 9c4588e47e | |||
| 084832e4e9 | |||
| 89989ef00a | |||
| 7b2bc00afc | |||
| c3c9a77942 | |||
| 2f875e32c9 | |||
| cc10987a60 | |||
| f69cf8043a | |||
| 00ea0bbb68 | |||
| de0f4a67d5 | |||
| 180d0ac7cb | |||
| 5ae63776ac | |||
| c92a17e316 | |||
| d876ea4640 | |||
| 657be255b0 | |||
| 794c873173 | |||
| 31a1e1ceec | |||
| 23b4a5ec31 | |||
| e9bef08309 | |||
| 9735dc5d9a | |||
| 04425d719a | |||
| d937ecef77 | |||
| 0f118391b5 | |||
| faf7698829 | |||
| f53a15abb5 | |||
| eba9b44699 | |||
| 128b7c3e4e | |||
| 3fedef27a7 | |||
| 608f1af1f4 | |||
| 0a0827f516 | |||
| 9f7b2dc27c | |||
| aa8920ec55 | |||
| b91b54acbe | |||
| 7d5b3b2438 | |||
| 30532386fb | |||
| 721b8c7128 | |||
| 8d70d6aaee | |||
| 9ff3bbbefc | |||
| c826db8718 | |||
| 0427020bc1 | |||
| 8c689d9d65 | |||
| c77c6a817b | |||
| 64721a6efe | |||
| 07f50fdfc7 | |||
| e2bda80e33 | |||
| a1bd9b330a | |||
| 2949f59800 | |||
| 338cffc633 | |||
| 02773b3f90 | |||
| 7c4d1cebe3 | |||
| 753e88b2c7 | |||
| e193e93c74 | |||
| c05608c5f1 | |||
| 76e613623a | |||
| df3abe32a2 | |||
| b18f2cfe1f | |||
| bdb8612081 | |||
| 48ab9d6e2e | |||
| 3a9f7f07e6 | |||
| 5750ab2036 | |||
| 623ebc22f7 | |||
| 1157a0c4ed | |||
| 6ad7f0d3d4 | |||
| 9d7453d3ee | |||
| 60478327e2 | |||
| 1d2b11bfd2 | |||
| 4117cbb489 | |||
| 4451b790de | |||
| 1fa0f6dde4 | |||
| faf343301f | |||
| 27d6e55cbe | |||
| 262ce8f099 | |||
| c7ab89b836 | |||
| ecbe7d9a5c | |||
| 1ec08b4847 | |||
| 2c7cf0c255 | |||
| 2865e2fd2d | |||
| 76ace545cd | |||
| cf8a7f38fb | |||
| 52171c94df | |||
| 39934df970 | |||
| 624331ca68 | |||
| 3e5f185721 | |||
| 936af73ec0 | |||
| 43acf0a2de | |||
| c9625f6bfd | |||
| 67b2dc6d71 | |||
| bfc39b5d96 | |||
| fcf5b7ac02 | |||
| da5137887c | |||
| 9e0a26f3bc | |||
| 3918ad64d6 | |||
| 88bbd73fa1 | |||
| 9402d895db | |||
| 56945f8488 | |||
| 471c81bdc7 | |||
| 6d2a79a639 | |||
| 5981a60d68 | |||
| 9ed6a4e494 | |||
| 26e7c040b3 | |||
| b2daabe2ab | |||
| de69eeefd8 | |||
| 56090e5092 | |||
| 59138535da | |||
| c7bf51bd9a | |||
| d2a0648238 | |||
| 0ae77ffbf8 | |||
| 78238907b0 | |||
| 5e1ccc9e8a | |||
| 89d4812d9f | |||
| 8af644288d | |||
| 9363717224 | |||
| df5fa2ea74 | |||
| 3c413833cf | |||
| 072df758db | |||
| 6c4e97945b | |||
| a663609eeb | |||
| 74e9f5a827 | |||
| d6f72186a3 | |||
| b2ea79512c | |||
| 8b666364ae | |||
| aac2c860c6 | |||
| c2b5e74156 | |||
| 093314d601 | |||
| 9b089d51b1 | |||
| 8ced5be7a9 | |||
| da50aa9794 | |||
| 47cef6ee59 | |||
| baaa9c5615 | |||
| edb1f576b7 | |||
| 8b0043d2f5 | |||
| 5ccb971c61 | |||
| 6278d9738d | |||
| 0b25e9c68c | |||
| a4095d6e72 | |||
| d31e78ff49 | |||
| 43b1b6f44f | |||
| f4d5904003 | |||
| 4b3c31252b | |||
| f61302a1f6 | |||
| a64b963d03 | |||
| 634dd96ac6 | |||
| 93939ed411 | |||
| 06d0244e24 | |||
| f04cf81ff2 | |||
| d31a408ddc | |||
| ce080f04a7 | |||
| 5a9dd6f97a | |||
| 8c774ef3a3 | |||
| af49cf4fb6 | |||
| 76f55597db | |||
| fada4b3231 | |||
| 15e13e8e12 | |||
| 03a6e75d68 | |||
| 2729e18043 | |||
| abac0d28fa |
159
.claude.local.md
Normal file
159
.claude.local.md
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
# 首页菜单页面地图
|
||||||
|
|
||||||
|
> **重要**:修改任何业务页面前,先在此处确认目标 Activity 是否为当前活跃页面。
|
||||||
|
> 若存在新旧两个同名/近名实现,以本文件中列出的为准(旧版已加 `@Deprecated`)。
|
||||||
|
>
|
||||||
|
> 菜单入口代码:`app/src/main/java/com/lukouguoji/aerologic/ui/fragment/HomeFragment.kt`
|
||||||
|
> 路由常量:`module_base/src/main/java/com/lukouguoji/module_base/router/ARouterConstants.kt`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一级菜单总览
|
||||||
|
|
||||||
|
| 菜单ID | 名称 | 模块 |
|
||||||
|
|--------|------|------|
|
||||||
|
| `DomExp` | 国内出港 | `module_gnc` |
|
||||||
|
| `DomImp` | 国内进港 | `app/page/gnj` |
|
||||||
|
| `IntExp` | 国际出港 | `module_gjc` |
|
||||||
|
| `IntImp` | 国际进港 | `module_gjj` |
|
||||||
|
| `Flight` | 航班查询 | `module_hangban` |
|
||||||
|
| `CargoStatus` | 货物追踪 | `module_cargo` |
|
||||||
|
| `Supervision` | 监装监卸 | `module_mit` + `app/page` |
|
||||||
|
| `Comprehensive` | 综合管理 | `app/page` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 国内出港(DomExp)& 国内进港(DomImp)
|
||||||
|
|
||||||
|
> ⛔ **不在维护范围内**:国内出港(`module_gnc`)和国内进港(`module_gnj` / `app/page/gnj`)不会涉及历史修改,也不会有新的需求。**无需关注这两个模块的任何页面。**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 国际出港(IntExp)
|
||||||
|
|
||||||
|
路由前缀:`/gjc/`
|
||||||
|
|
||||||
|
### 二级菜单
|
||||||
|
|
||||||
|
| 菜单名 | 权限ID | Activity | 路由常量 |
|
||||||
|
|--------|--------|----------|---------|
|
||||||
|
| 收运检查 | `AppIntExpInspection` | `GjcInspectionActivity` | `ACTIVITY_URL_GJC_INSPECTION` |
|
||||||
|
| 出港计重 | `AppIntExpCheckWeighing` | `GjcWeighingListActivity` | `ACTIVITY_URL_GJC_WEIGHING_LIST` |
|
||||||
|
| 出港运抵 | `AppIntExpArrive` | `IntExpArriveActivity` | `ACTIVITY_URL_INT_EXP_ARRIVE` |
|
||||||
|
| 组装分配 | `AppIntExpAssembleAllocate` | `GjcAssembleAllocateActivity` | `ACTIVITY_URL_GJC_ASSEMBLE_ALLOCATE` |
|
||||||
|
| 出港组装 | `AppIntExpAssemble` | `IntExpAssembleActivity` | `ACTIVITY_URL_INT_EXP_ASSEMBLE` |
|
||||||
|
| 板箱过磅 | `GjcFuBangActivity`(权限ID,非类名)| `GjcBoxWeighingActivity` | `ACTIVITY_URL_GJC_BOX_WEIGHING` |
|
||||||
|
| 出港装载 | `AppIntExpLoad` | `IntExpLoadActivity` | `ACTIVITY_URL_INT_EXP_LOAD` |
|
||||||
|
| 出库交接 | `AppIntExpOutHandover` | `IntExpOutHandoverActivity` | `ACTIVITY_URL_INT_EXP_OUT_HANDOVER` |
|
||||||
|
| 出港理货 | `AppIntExpTally` | `IntExpTallyActivity` | `ACTIVITY_URL_INT_EXP_TALLY` |
|
||||||
|
| 出港移库 | `AppIntExpMove` | `IntExpMoveActivity` | `ACTIVITY_URL_INT_EXP_MOVE` |
|
||||||
|
| 出港仓库 | `AppIntExpStorageUse` | `IntExpStorageUseActivity` | `ACTIVITY_URL_INT_EXP_STORAGE_USE` |
|
||||||
|
| 出港查询 | `AppIntExpSearch` | `GjcQueryListActivity` | `ACTIVITY_URL_GJC_QUERY_LIST` |
|
||||||
|
|
||||||
|
> ⚠️ 旧版文件(已加 `@Deprecated`):`GjcFuBangActivity`(`module_gjc/.../activity/`),已被 `GjcBoxWeighingActivity` 替代
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 国际进港(IntImp)
|
||||||
|
|
||||||
|
路由前缀:`/gjj/`
|
||||||
|
|
||||||
|
### 二级菜单
|
||||||
|
|
||||||
|
| 菜单名 | 权限ID | Activity | 路由常量 |
|
||||||
|
|--------|--------|----------|---------|
|
||||||
|
| 电报解析 | `AppIntImpMsgParse` | `IntImpMsgParseActivity` | `ACTIVITY_URL_INT_IMP_MSG_PARSE` |
|
||||||
|
| 进港舱单 | `AppIntImpManifest` | `IntImpManifestActivity` | `ACTIVITY_URL_INT_IMP_MANIFEST` |
|
||||||
|
| 原始舱单 | `AppIntArrAirManifest` | `IntArrAirManifestActivity` | `ACTIVITY_URL_INT_ARR_AIR_MANIFEST` |
|
||||||
|
| 理货报告 | `AppIntImpTally` | `IntImpTallyActivity` | `ACTIVITY_URL_INT_IMP_TALLY` |
|
||||||
|
| 进港仓库 | `AppIntImpWareHouse` | `GjjWareHouseActivity` | `ACTIVITY_URL_GJJ_WARE_HOUSE` |
|
||||||
|
| 提取记录 | `AppIntImpPickUpRecord` | `IntImpPickUpRecordActivity` | `ACTIVITY_URL_INT_IMP_PICK_UP_RECORD` |
|
||||||
|
| 提取出库 | `AppIntImpPickUpDLV` | `IntImpPickUpDLVActivity` | `ACTIVITY_URL_INT_IMP_PICK_UP_DLV` |
|
||||||
|
| 进港查询 | `AppIntImpSearch` | `IntImpQueryActivity` ⚡ | `ACTIVITY_URL_GJJ_QUERY_LIST` |
|
||||||
|
| 事故签证 | `AppIntImpAccidentVisa` | `IntImpAccidentVisaActivity` | `ACTIVITY_URL_INT_IMP_ACCIDENT_VISA` |
|
||||||
|
|
||||||
|
### 三级页面(进港舱单)
|
||||||
|
|
||||||
|
| 页面名 | Activity | 说明 |
|
||||||
|
|--------|----------|------|
|
||||||
|
| 舱单列表(入口) | `IntImpManifestActivity` | 二级入口页 |
|
||||||
|
| 舱单子列表 | `GjjManifestListActivity` | 活跃,独立路由 `ACTIVITY_URL_GJJ_MANIFEST` |
|
||||||
|
| 舱单详情 | `GjjManifestDetailsActivity` / `IntImpManifestDetailsActivity` | 两个活跃详情页 |
|
||||||
|
| 分单编辑 | `GjjManifestAddActivity` / `IntImpManifestSubEditActivity` | 活跃编辑页 |
|
||||||
|
|
||||||
|
### 三级页面(进港查询)
|
||||||
|
|
||||||
|
| 页面名 | Activity | 说明 |
|
||||||
|
|--------|----------|------|
|
||||||
|
| 查询列表(入口) | `IntImpQueryActivity` | 二级入口页(注意:非 GjjQueryListActivity)|
|
||||||
|
| 查询详情 | `IntImpQueryDetailsActivity` | 活跃 |
|
||||||
|
| 运单修改 | `IntImpQueryEditActivity` | 活跃 |
|
||||||
|
|
||||||
|
> ⚠️ 旧版(已加 `@Deprecated`):`GjjQueryListActivity`、`GjjQueryInfoActivity`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 航班查询(Flight)
|
||||||
|
|
||||||
|
直接跳转,无二级菜单。
|
||||||
|
|
||||||
|
| Activity | 路由 | 文件路径 |
|
||||||
|
|----------|------|---------|
|
||||||
|
| `HbQueryListActivity` | `/hb/HbQueryListActivity` | `module_hangban/...` |
|
||||||
|
|
||||||
|
> ⚠️ 旧版:`FlightQueryListActivity`(`app/.../page/flight/query/list/`)已加 `@Deprecated`,由 HomeFragment 注释确认废弃
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 货物追踪(CargoStatus)
|
||||||
|
|
||||||
|
直接跳转,无二级菜单。
|
||||||
|
|
||||||
|
| Activity | 路由 |
|
||||||
|
|----------|------|
|
||||||
|
| `CargoTrackingActivity` | `/cg/CargoTrackingActivity` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 监装监卸(Supervision)
|
||||||
|
|
||||||
|
### 二级菜单
|
||||||
|
|
||||||
|
| 菜单名 | 权限ID | Activity | 文件路径 |
|
||||||
|
|--------|--------|----------|---------|
|
||||||
|
| 进港卸机 | `AppImpLoad` | `GnjUnloadListActivity` | `app/.../page/gnj/unload/list/` |
|
||||||
|
| 事故签证(监装) | `AppAccidentVisa` | `AccidentVisaActivity` | 路由 `/mit/AccidentVisaActivity` |
|
||||||
|
| 事故签证(综合) | `AppComprehensiveAccidentVisa` | `AccidentVisaListActivity` | `app/.../page/accident/visa/list/` |
|
||||||
|
| 出港装板 | `AppExpLoad` | `OutLoadingActivity` | 路由 `/mit/OutLoadingActivity` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 综合管理(Comprehensive)
|
||||||
|
|
||||||
|
### 二级菜单
|
||||||
|
|
||||||
|
| 菜单名 | 权限ID | Activity | 文件路径 |
|
||||||
|
|--------|--------|----------|---------|
|
||||||
|
| 消息管理 | `AppComprehensiveMessage` | `MessageListActivity` | `app/.../page/message/list/` |
|
||||||
|
| 电报管理 | `AppComprehensiveTelegram` | `TelegramListActivity` | `app/.../page/telegram/list/` |
|
||||||
|
| 货物转运 | `AppComprehensiveTransfer` | `GoodsTransportActivity` | `app/.../page/transport/` |
|
||||||
|
| 平板车管理 | `AppComprehensiveCar` | `CarListActivity` | `app/.../page/car/list/` |
|
||||||
|
| 日志查询 | `AppComprehensiveLog` | `LogQueryActivity` | `app/.../page/log/list/` |
|
||||||
|
| 转运记录 | `AppTransportLog` | `TransportLogActivity` | `app/.../page/transportLog/list/` |
|
||||||
|
| ULD管理 | `AppComprehensiveUld` | `UldListActivity` | `app/.../page/uld/list/` |
|
||||||
|
| 冷库登记 | `AppComprehensiveColdStorage` | `ColdStorageActivity` | `app/.../page/coldStorage/list/` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 废弃页面清单(已加 @Deprecated)
|
||||||
|
|
||||||
|
以下页面确认废弃,勿修改、勿参考:
|
||||||
|
|
||||||
|
| 废弃类名 | 文件路径 | 替代页面 | 依据 |
|
||||||
|
|----------|---------|---------|------|
|
||||||
|
| `FlightQueryListActivity` | `app/.../page/flight/query/list/` | `HbQueryListActivity` | HomeFragment 注释"已废弃" |
|
||||||
|
| `HangBanQueryActivity` | `module_hangban/.../activity/` | `HbQueryListActivity` | 路由注释"已废弃,使用 HbQueryListActivity" |
|
||||||
|
| `HangBanQueryInfoActivity` | `module_hangban/.../activity/` | — | 仅被废弃的 HangBanQueryActivity 调用,实际不可达 |
|
||||||
|
| `GjcFuBangActivity` | `module_gjc/.../activity/` | `GjcBoxWeighingActivity` | HomeFragment 注释"旧版跳转" |
|
||||||
|
| `GjjQueryListActivity` | `module_gjj/.../activity/` | `IntImpQueryActivity` | 路由被注释,IntImpQueryActivity 接管同一路由 |
|
||||||
|
| `GjjQueryInfoActivity` | `module_gjj/.../activity/` | `IntImpQueryDetailsActivity` | 路由注释"已替换为 IntImpQueryDetailsActivity" |
|
||||||
@@ -1,14 +1,10 @@
|
|||||||
{
|
{
|
||||||
"mcpServers": {
|
"mcpServers": {
|
||||||
"空港集团 - API 文档": {
|
"api-doc": {
|
||||||
"command": "/Users/kid/.version-fox/sdks/nodejs/bin/npx",
|
"type": "http",
|
||||||
"args": [
|
"url": "https://www.agentfoxapp.com/mcp/976caff7-5f98-4487-bccf-3aa20c92cf1f",
|
||||||
"-y",
|
"headers": {
|
||||||
"apifox-mcp-server@latest",
|
"Authorization": "Bearer afk_G_VKmHTdXUi3GjQdg5AeHeH-0BSYQEPP"
|
||||||
"--project-id=7382863"
|
|
||||||
],
|
|
||||||
"env": {
|
|
||||||
"APIFOX_ACCESS_TOKEN": "APS-S2aVVwqasbdByzPLgSqryRC8BB0ZFqhQ"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,13 +69,97 @@
|
|||||||
"Bash(python3:*)",
|
"Bash(python3:*)",
|
||||||
"mcp__apifox__read_project_oas_ukz3j4",
|
"mcp__apifox__read_project_oas_ukz3j4",
|
||||||
"mcp__apifox__read_project_oas_ref_resources_ukz3j4",
|
"mcp__apifox__read_project_oas_ref_resources_ukz3j4",
|
||||||
"mcp__apifox__refresh_project_oas_ukz3j4"
|
"mcp__apifox__refresh_project_oas_ukz3j4",
|
||||||
|
"mcp__playwright__browser_click",
|
||||||
|
"mcp__playwright__browser_take_screenshot",
|
||||||
|
"mcp__playwright__browser_snapshot",
|
||||||
|
"Bash(/tmp/communicate_type_findings.md:*)",
|
||||||
|
"Read(//tmp/**)",
|
||||||
|
"mcp__apifox__read_project_oas_3gn3lx",
|
||||||
|
"mcp__apifox__read_project_oas_ref_resources_3gn3lx",
|
||||||
|
"mcp__apifox__refresh_project_oas_3gn3lx",
|
||||||
|
"Bash(cp \"/var/folders/qz/qk20ny650h1fhmxrx46gdfhr0000gn/T/images/Warp 2026-03-13 09.54.13.tiff\" /tmp/screenshot.png)",
|
||||||
|
"Read(//private/var/folders/qz/qk20ny650h1fhmxrx46gdfhr0000gn/T/images/**)",
|
||||||
|
"mcp__apifox__read_project_oas_2s2uhx",
|
||||||
|
"mcp__apifox__read_project_oas_ref_resources_2s2uhx",
|
||||||
|
"mcp__apifox__refresh_project_oas_2s2uhx",
|
||||||
|
"Bash(find /Users/kid/Development/Fusion/Projects/aerologic-app -path \"*/build\" -prune -o -type f \\\\\\( -name \"*manifest*\" -o -name \"*bean*\" \\\\\\) | grep -i \"gjj\\\\|tally\" | grep -E \"\\\\.\\(kt\\)$\" | sort)",
|
||||||
|
"mcp__apifox__read_project_oas_9otrai",
|
||||||
|
"mcp__apifox__read_project_oas_ref_resources_9otrai",
|
||||||
|
"Bash(cd:*)",
|
||||||
|
"mcp__apifox__read_project_oas_tua249",
|
||||||
|
"mcp__apifox__read_project_oas_ref_resources_tua249",
|
||||||
|
"mcp__apifox__read_project_oas_heib77",
|
||||||
|
"mcp__apifox__read_project_oas_ref_resources_heib77",
|
||||||
|
"Bash(export JAVA_HOME=\"/Applications/Android Studio.app/Contents/jbr/Contents/Home\")",
|
||||||
|
"Bash(export PATH=\"$JAVA_HOME/bin:$PATH\")",
|
||||||
|
"Read(//Library/Java/JavaVirtualMachines/**)",
|
||||||
|
"Read(//usr/local/**)",
|
||||||
|
"Read(//opt/homebrew/opt/**)",
|
||||||
|
"Bash(/Users/kid/.vfox/sdks/java/bin/java -version 2>&1)",
|
||||||
|
"Bash(export JAVA_HOME=/Users/kid/.vfox/sdks/java)",
|
||||||
|
"mcp__apifox__read_project_oas_kcl8s7",
|
||||||
|
"mcp__apifox__refresh_project_oas_kcl8s7",
|
||||||
|
"mcp__apifox__read_project_oas_ref_resources_kcl8s7",
|
||||||
|
"mcp__apifox__read_project_oas_x3v6fh",
|
||||||
|
"mcp__apifox__read_project_oas_ref_resources_x3v6fh",
|
||||||
|
"mcp__plugin_claude-mem_mcp-search__smart_outline",
|
||||||
|
"Bash(find /Users/kid/Development/Fusion/Projects/aerologic-app/module_gjj/src/main -type f \\\\\\(-name *IntImpAccidentVisa* -o -name *AccidentVisa* \\\\\\))",
|
||||||
|
"mcp__apifox__read_project_oas_g3xqex",
|
||||||
|
"mcp__apifox__read_project_oas_ref_resources_g3xqex",
|
||||||
|
"mcp__apifox__refresh_project_oas_g3xqex",
|
||||||
|
"mcp__apifox__read_project_oas_4h0w3b",
|
||||||
|
"mcp__apifox__read_project_oas_ref_resources_4h0w3b",
|
||||||
|
"mcp__apifox__read_project_oas_6i29va",
|
||||||
|
"mcp__apifox__read_project_oas_ref_resources_6i29va",
|
||||||
|
"mcp__plugin_claude-mem_mcp-search__smart_search",
|
||||||
|
"Bash(echo \"exit:$?\")",
|
||||||
|
"mcp__apifox__read_project_oas_j7j64k",
|
||||||
|
"mcp__apifox__read_project_oas_ref_resources_j7j64k",
|
||||||
|
"mcp__apifox__read_project_oas_ruugy8",
|
||||||
|
"mcp__apifox__read_project_oas_ref_resources_ldmedm",
|
||||||
|
"mcp__apifox__read_project_oas_ldmedm",
|
||||||
|
"mcp__apifox__refresh_project_oas_ldmedm",
|
||||||
|
"Skill(update-config)",
|
||||||
|
"mcp__apidoc__get_project_overview",
|
||||||
|
"mcp__apidoc__search_endpoints",
|
||||||
|
"mcp__apidoc__list_endpoints",
|
||||||
|
"mcp__apidoc__get_endpoint_detail",
|
||||||
|
"mcp__api-doc__search_endpoints",
|
||||||
|
"mcp__api-doc__get_endpoint_detail",
|
||||||
|
"mcp__api-doc__list_modules",
|
||||||
|
"mcp__api-doc__list_endpoints",
|
||||||
|
"Bash(sed -n '11,15p' /Users/kid/Development/Fusion/Projects/aerologic-app/app/src/main/java/com/lukouguoji/aerologic/page/flight/query/list/FlightQueryListActivity.kt)",
|
||||||
|
"Bash(sed -n '23,27p' /Users/kid/Development/Fusion/Projects/aerologic-app/module_gjc/src/main/java/com/lukouguoji/gjc/activity/GjcFuBangActivity.kt)",
|
||||||
|
"Bash(sed -i '' '/@Deprecated\\(\"旧版国内出港出库,已由 Gnc 前缀新版页面替代\"\\)/d' /Users/kid/Development/Fusion/Projects/aerologic-app/module_gnc/src/main/java/com/lukouguoji/gnc/activity/GoutChuKuListActivity.kt)",
|
||||||
|
"Bash(sed -i '' '/@Deprecated\\(\"旧版国内出港收运,已由 Gnc 前缀新版页面替代\"\\)/d' /Users/kid/Development/Fusion/Projects/aerologic-app/module_gnc/src/main/java/com/lukouguoji/gnc/activity/GoutCollectionActivity.kt)",
|
||||||
|
"Bash(sed -i '' '/@Deprecated\\(\"旧版国内出港复磅,使用 GncFuBangListActivity 替代\"\\)/d' /Users/kid/Development/Fusion/Projects/aerologic-app/module_gnc/src/main/java/com/lukouguoji/gnc/activity/GoutFuBangActivity.kt)",
|
||||||
|
"Bash(sed -i '' '/@Deprecated\\(\"旧版国内出港复磅(组合),使用 GncFuBangListActivity 替代\"\\)/d' /Users/kid/Development/Fusion/Projects/aerologic-app/module_gnc/src/main/java/com/lukouguoji/gnc/activity/GoutFuBangCotActivity.kt)",
|
||||||
|
"Bash(sed -i '' '/@Deprecated\\(\"旧版国内出港收运开始,使用 GncShouYunUnListActivity 替代\"\\)/d' /Users/kid/Development/Fusion/Projects/aerologic-app/module_gnc/src/main/java/com/lukouguoji/gnc/activity/GoutStartCotActivity.kt)",
|
||||||
|
"Bash(cp \"/Users/kid/Downloads/Desktop/进港舱单.png\" /Users/kid/Development/Fusion/Projects/aerologic-app/module_gjj/src/main/res/mipmap-mdpi/gjj_jin_gang_cang_dan_icon.png)",
|
||||||
|
"Bash(cp \"/Users/kid/Downloads/Desktop/原始舱单.png\" /Users/kid/Development/Fusion/Projects/aerologic-app/module_gjj/src/main/res/mipmap-mdpi/gjj_yuan_shi_cang_dan_icon.png)",
|
||||||
|
"Bash(cp \"/Users/kid/Downloads/Desktop/提取记录.png\" /Users/kid/Development/Fusion/Projects/aerologic-app/module_gjj/src/main/res/mipmap-mdpi/gjj_ti_qu_ji_lu_icon.png)",
|
||||||
|
"mcp__api-doc__get_project_overview",
|
||||||
|
"mcp__plugin_claude-mem_mcp-search__get_observations",
|
||||||
|
"Bash(awk *)",
|
||||||
|
"Bash(sed -n '65,90p' module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpLoadViewModel.kt)",
|
||||||
|
"Bash(sed -n '73,95p' module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpArriveViewModel.kt)",
|
||||||
|
"Bash(sed -n '60,75p' module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpOutHandoverViewModel.kt)",
|
||||||
|
"Bash(sed -n '73,100p' module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpArriveViewModel.kt)",
|
||||||
|
"Bash(sed -n '82,115p' module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpStorageUseViewModel.kt)",
|
||||||
|
"Bash(sed -n '212,240p' module_gjj/src/main/java/com/lukouguoji/gjj/viewModel/IntImpManifestViewModel.kt)",
|
||||||
|
"mcp__plugin_claude-mem_mcp-search__search",
|
||||||
|
"Read(//Users/kid/.claude/**)",
|
||||||
|
"Bash(bash /Users/kid/Development/Fusion/Projects/aerologic-app/.claude/skills/sync-air-cargo/scripts/sync.sh)"
|
||||||
],
|
],
|
||||||
"deny": [],
|
"deny": [],
|
||||||
"ask": []
|
"ask": []
|
||||||
},
|
},
|
||||||
|
"enableAllProjectMcpServers": true,
|
||||||
"enabledMcpjsonServers": [
|
"enabledMcpjsonServers": [
|
||||||
"空港集团 - API 文档",
|
"空港集团 - API 文档",
|
||||||
"apifox"
|
"apifox",
|
||||||
|
"aerologic-app",
|
||||||
|
"apidoc"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
465
.claude/skills/new-page/SKILL.md
Normal file
465
.claude/skills/new-page/SKILL.md
Normal file
@@ -0,0 +1,465 @@
|
|||||||
|
---
|
||||||
|
name: new-page
|
||||||
|
description: 根据设计截图和菜单入口名称,在 AirLogistics 项目中创建新的业务页面。自动分析截图判断页面类型(6种典型类型之一),规划所需文件,然后完整实现(Kotlin + XML + 路由注册 + 菜单接入)。当用户说"创建页面"、"新建页面"、"实现这个页面"、"做这个页面"或提供设计截图要求开发时触发。
|
||||||
|
---
|
||||||
|
|
||||||
|
# 新建业务页面
|
||||||
|
|
||||||
|
根据设计截图和菜单入口名称,在 AirLogistics 项目中完整创建一个新的业务页面。
|
||||||
|
|
||||||
|
## 前置要求
|
||||||
|
|
||||||
|
用户需要提供:
|
||||||
|
1. **设计截图**(必须)— 页面 UI 设计图
|
||||||
|
2. **菜单入口名称**(必须)— 页面在首页菜单中显示的名称
|
||||||
|
3. **所属模块**(可选)— 如 module_gjj(国际进港)、module_gjc(国际出港)等,可从截图标题推断
|
||||||
|
|
||||||
|
## 执行步骤
|
||||||
|
|
||||||
|
### 第 1 步:分析截图,判定页面类型
|
||||||
|
|
||||||
|
仔细阅读截图,提取以下信息:
|
||||||
|
|
||||||
|
1. **页面标题**(标题栏文字)
|
||||||
|
2. **搜索区字段**(每个搜索控件的 hint 文本、类型:日期/输入/下拉/扫码)
|
||||||
|
3. **列表项字段**(每个数据字段的标签名和显示格式)
|
||||||
|
4. **底部操作栏**(统计项 + 操作按钮)
|
||||||
|
5. **特殊交互**(全选、展开/收起、右箭头、子列表等)
|
||||||
|
|
||||||
|
然后对照 CLAUDE.md 中的 **6 种典型页面类型**判定:
|
||||||
|
|
||||||
|
| 类型 | 关键特征 | 判定依据 |
|
||||||
|
|------|----------|----------|
|
||||||
|
| **类型 1:列表查询页** | 搜索 + 分页列表 + 底部统计 | 无全选、无勾选,纯查看 |
|
||||||
|
| **类型 2:多选列表 + 批量操作页** | 类型 1 + 全选按钮 + 飞机图标选中态 + 操作按钮 | 有全选、有批量操作按钮(如"清除提货") |
|
||||||
|
| **类型 3:嵌套多选列表页** | 类型 2 + 子列表(展开/收起)+ 主子联动全选 | 有展开按钮、列表项内含子 RecyclerView |
|
||||||
|
| **类型 4:Tab 详情页** | 自定义 Tab 栏 + ViewPager2 + 多 Fragment | 有 Tab 切换、无列表搜索 |
|
||||||
|
| **类型 5:编辑表单页** | ScrollView + PadDataLayoutNew 表单 + 保存/取消 | 有可编辑字段、有保存按钮 |
|
||||||
|
| **类型 6:添加表单页** | 类型 5 + 输入回调 + 实时计算 | 有 setRefreshCallBack 联动 |
|
||||||
|
|
||||||
|
**向用户确认**判定结果,格式:
|
||||||
|
|
||||||
|
```
|
||||||
|
📋 页面分析结果:
|
||||||
|
|
||||||
|
页面标题:XXX
|
||||||
|
页面类型:类型 N — XXXX
|
||||||
|
所属模块:module_xxx
|
||||||
|
|
||||||
|
搜索条件:
|
||||||
|
1. XXX(DATE)
|
||||||
|
2. XXX(SPINNER)
|
||||||
|
3. XXX(INPUT + 扫码)
|
||||||
|
|
||||||
|
列表字段(第一行):XXX | XXX | XXX
|
||||||
|
列表字段(第二行):XXX | XXX | XXX
|
||||||
|
|
||||||
|
底部操作:全选 + 统计(合计/总件数/总重量) + [操作按钮名称]
|
||||||
|
|
||||||
|
是否正确?确认后开始实现。
|
||||||
|
```
|
||||||
|
|
||||||
|
### 第 2 步:查找参考模板并提取 UI 设计规范
|
||||||
|
|
||||||
|
根据判定的页面类型,在项目中找到**同类型的最新参考实现**,并严格提取 UI 设计规范。
|
||||||
|
|
||||||
|
**查找策略**(优先级从高到低):
|
||||||
|
1. 优先查找**最近提交的同类型页面**(最新的页面代表最新的 UI 规范)
|
||||||
|
2. 其次在**同模块**内查找同类型页面
|
||||||
|
3. 最后在 **module_gjc**(国际出港)查找
|
||||||
|
|
||||||
|
**最新典型参考页面**(2024年后新增,代表当前 UI 规范):
|
||||||
|
|
||||||
|
| 页面类型 | 参考页面 | 布局文件 |
|
||||||
|
|----------|----------|----------|
|
||||||
|
| 列表查询页 | 航班查询列表 | `activity_flight_query_list.xml` / `item_flight_query_list.xml` |
|
||||||
|
| 列表查询页 | 日志查询页 | `activity_log_query.xml` / `item_log_query.xml` |
|
||||||
|
| 详情页 | 航班查询详情 | `activity_flight_query_details.xml` |
|
||||||
|
| 详情页 | 日志详情 | `activity_log_detail.xml` |
|
||||||
|
|
||||||
|
**必须读取的参考文件**:
|
||||||
|
- 上述最新典型参考页面中**与当前页面类型匹配的布局 XML**(Activity 布局 + Item 布局)
|
||||||
|
- 对应的 Activity、ViewModel、ViewHolder Kotlin 代码
|
||||||
|
- Dialog(如有批量操作弹窗)
|
||||||
|
|
||||||
|
**UI 设计规范提取(必做)**:
|
||||||
|
|
||||||
|
读取参考布局后,必须逐一确认以下规范项,并在开发计划中明确列出:
|
||||||
|
|
||||||
|
| 规范项 | 必须确认的内容 |
|
||||||
|
|--------|---------------|
|
||||||
|
| 页面背景色 | 根容器 `background` 属性(新规范:`@color/color_f2`) |
|
||||||
|
| 搜索区样式 | 使用的搜索控件类型、间距、布局方式 |
|
||||||
|
| 搜索按钮样式 | 图标资源、尺寸、style(新规范:`@drawable/img_search`,36dp) |
|
||||||
|
| 底部栏背景色 | 背景色 + 文字颜色(新规范有两种变体) |
|
||||||
|
| 底部栏文字样式 | 字号、粗细、颜色 |
|
||||||
|
| 列表项背景 | 背景、间距、padding |
|
||||||
|
| 详情页卡片样式 | 背景、圆角、padding、行间距 |
|
||||||
|
| 表单控件 | 使用 PadDataLayoutNew(非旧版 PadDataLayout) |
|
||||||
|
|
||||||
|
**同时检查**:
|
||||||
|
- 该页面需要的**下拉列表数据源 API** 是否已存在(代理人、特码等)
|
||||||
|
- 该页面需要的 **Bean 类**是否已存在,或需要新建
|
||||||
|
- `ARouterConstants` 中是否已有对应路由常量
|
||||||
|
- `Constant.AuthName` 中是否已有对应权限名
|
||||||
|
|
||||||
|
### 第 3 步:制定文件清单
|
||||||
|
|
||||||
|
列出所有需要**新建**和**修改**的文件。
|
||||||
|
|
||||||
|
**新建文件清单**(根据页面类型调整):
|
||||||
|
|
||||||
|
| 类别 | 文件 | 路径 |
|
||||||
|
|------|------|------|
|
||||||
|
| Bean | `XxxBean.kt`(如需) | `module_base/.../bean/` |
|
||||||
|
| Activity | `XxxActivity.kt` | `module_xxx/.../activity/` |
|
||||||
|
| ViewModel | `XxxViewModel.kt` | `module_xxx/.../viewModel/` |
|
||||||
|
| ViewHolder | `XxxViewHolder.kt` | `module_xxx/.../holder/` |
|
||||||
|
| Dialog | `XxxDialogModel.kt`(如需) | `module_xxx/.../dialog/` |
|
||||||
|
| Activity 布局 | `activity_xxx.xml` | `module_xxx/.../res/layout/` |
|
||||||
|
| Item 布局 | `item_xxx.xml` | `module_xxx/.../res/layout/` |
|
||||||
|
| Dialog 布局 | `dialog_xxx.xml`(如需) | `module_xxx/.../res/layout/` |
|
||||||
|
|
||||||
|
**修改文件清单**(固定):
|
||||||
|
|
||||||
|
| 文件 | 修改内容 |
|
||||||
|
|------|----------|
|
||||||
|
| `Api.kt` | 添加 API 接口方法 + import |
|
||||||
|
| `ARouterConstants.kt` | 添加路由常量(如不存在) |
|
||||||
|
| `Constant.kt` | 添加 AuthName 常量(如不存在) |
|
||||||
|
| `AndroidManifest.xml` | 注册 Activity |
|
||||||
|
| `HomeFragment.kt` | 添加菜单项 + 点击路由处理 |
|
||||||
|
| 旧版 Activity(如有) | 注释掉 `@Route` 注解避免冲突 |
|
||||||
|
|
||||||
|
### 第 4 步:创建 Bean(如需)
|
||||||
|
|
||||||
|
如果截图中的列表字段与现有 Bean 不匹配,创建新的 Bean 类。
|
||||||
|
|
||||||
|
**规则**:
|
||||||
|
- 放在 `module_base/.../bean/` 目录下
|
||||||
|
- 如果是类型 2/3(多选),必须包含 `ObservableBoolean` 选中状态:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
val checked: ObservableBoolean = ObservableBoolean(false)
|
||||||
|
var isSelected: Boolean
|
||||||
|
get() = checked.get()
|
||||||
|
set(value) = checked.set(value)
|
||||||
|
```
|
||||||
|
|
||||||
|
- 字段类型映射:数字用 `Int/Long/Double`,文本用 `String = ""`,时间用 `String = ""`
|
||||||
|
- 在 `Api.kt` 的 import 区按字母顺序添加 import
|
||||||
|
|
||||||
|
### 第 5 步:添加 API 接口
|
||||||
|
|
||||||
|
在 `Api.kt` 中添加 API 方法。
|
||||||
|
|
||||||
|
**标准 API 组合**(根据页面需要选取):
|
||||||
|
- `getXxxList(@Body)` — 分页查询,返回 `PageInfo<XxxBean>`
|
||||||
|
- `getXxxTotal(@Body)` — 分页合计,返回 `BaseResultBean<ManifestTotalDto>`
|
||||||
|
- 批量操作 API — 返回 `BaseResultBean<Boolean>`
|
||||||
|
- 下拉列表 API(代理人、特码等)— 如不存在则添加
|
||||||
|
|
||||||
|
**API 路径命名**:先使用 `ModuleName/methodName` 格式占位(如 `IntImpPickUpRecord/pageQuery`),后续由第 13 步替换为真实接口路径
|
||||||
|
|
||||||
|
### 第 6 步:添加路由和权限常量
|
||||||
|
|
||||||
|
1. 在 `ARouterConstants.kt` 添加路由(如不存在):
|
||||||
|
```kotlin
|
||||||
|
const val ACTIVITY_URL_XXX = "/module/XxxActivity"
|
||||||
|
```
|
||||||
|
|
||||||
|
2. 在 `Constant.kt` 的 `AuthName` 中添加权限名(如不存在):
|
||||||
|
```kotlin
|
||||||
|
const val XxxPage = "AppXxxPage"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 第 7 步:创建 ViewHolder
|
||||||
|
|
||||||
|
根据 item 布局创建 ViewHolder。
|
||||||
|
|
||||||
|
**类型 1**:基础绑定
|
||||||
|
**类型 2**:增加图标点击切换 `checked` 状态
|
||||||
|
**类型 3**:增加子列表 `setCommonAdapter` + 展开按钮 + 父子联动
|
||||||
|
|
||||||
|
### 第 8 步:创建 ViewModel
|
||||||
|
|
||||||
|
**必须包含的元素**(根据截图):
|
||||||
|
- 搜索条件 `MutableLiveData`(与搜索区对应)
|
||||||
|
- 下拉列表数据源 `MutableLiveData<List<KeyValue>>`
|
||||||
|
- 统计字段 `MutableLiveData<String>`
|
||||||
|
- 适配器配置:`itemViewHolder` + `itemLayoutId`
|
||||||
|
- `searchClick()` 方法
|
||||||
|
- `getData()` override:调用列表 API + 统计 API
|
||||||
|
|
||||||
|
**类型 2 额外**:`isAllChecked` + `checkAllClick()` + 批量操作方法
|
||||||
|
**类型 3 额外**:`isAllExpanded` + `toggleAllExpand()` + 联动全选逻辑
|
||||||
|
|
||||||
|
**下拉列表初始化**:
|
||||||
|
- 代理人:`DictUtils.getAgentList()` / `NetApply.api.getIntImpAgentList()` / `getIntExpAgentList()`
|
||||||
|
- 特码:`DictUtils.getSpecialCodeList(flag, ieFlag, parentcode)`
|
||||||
|
- 其他字典:`DictUtils` 或自定义 API
|
||||||
|
|
||||||
|
### 第 9 步:创建布局文件
|
||||||
|
|
||||||
|
**⚠️ 重要:所有布局必须严格遵循最新 UI 设计规范,参照第 2 步中提取的规范项。**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 新版 UI 设计规范(强制执行)
|
||||||
|
|
||||||
|
**1. 页面背景色**:
|
||||||
|
```xml
|
||||||
|
<!-- 根容器必须使用 color_f2 背景色 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:background="@color/color_f2"
|
||||||
|
android:orientation="vertical">
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. 搜索区规范**:
|
||||||
|
```xml
|
||||||
|
<!-- 搜索区:marginHorizontal=10dp, marginTop=10dp, gravity=center_vertical -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_marginHorizontal="10dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<!-- 搜索控件使用 PadSearchLayout -->
|
||||||
|
<PadSearchLayout
|
||||||
|
type="@{SearchLayoutType.DATE}"
|
||||||
|
hint='@{"请选择航班日期"}'
|
||||||
|
icon="@{@drawable/img_date}"
|
||||||
|
value="@={viewModel.date}"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<!-- 搜索按钮:img_search 图标,36x36dp,padding=2dp -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center_vertical|start"
|
||||||
|
android:paddingHorizontal="24dp">
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="36dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:padding="2dp"
|
||||||
|
android:onClick="@{()-> viewModel.searchClick()}"
|
||||||
|
android:src="@drawable/img_search" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
```
|
||||||
|
|
||||||
|
**3. 底部统计栏规范**(两种变体,根据截图选择):
|
||||||
|
|
||||||
|
**变体 A — 深蓝色底部栏**(多数列表页使用):
|
||||||
|
```xml
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:background="@color/color_bottom_layout"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingHorizontal="15dp">
|
||||||
|
<TextView
|
||||||
|
android:text='@{"合计:"+viewModel.count+"条"}'
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
</LinearLayout>
|
||||||
|
```
|
||||||
|
|
||||||
|
**变体 B — 白色底部栏**:
|
||||||
|
```xml
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:background="@color/white"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingHorizontal="15dp">
|
||||||
|
<TextView
|
||||||
|
android:text='@{"合计:" + viewModel.count + "条"}'
|
||||||
|
android:textColor="@color/bottom_tool_tips_text_color"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
</LinearLayout>
|
||||||
|
```
|
||||||
|
|
||||||
|
**4. 详情页/表单页规范**:
|
||||||
|
- 必须使用 **PadDataLayoutNew**(非旧版 PadDataLayout)
|
||||||
|
- 卡片背景:`@drawable/bg_white_radius_8`,padding `15dp`
|
||||||
|
- 行间距:`marginTop="8dp"`
|
||||||
|
- 三列标准布局,每列 `layout_weight="1"`
|
||||||
|
```xml
|
||||||
|
<ScrollView android:fillViewport="true">
|
||||||
|
<LinearLayout android:padding="15dp" android:orientation="vertical">
|
||||||
|
<LinearLayout android:background="@drawable/bg_white_radius_8"
|
||||||
|
android:padding="15dp" android:orientation="vertical">
|
||||||
|
<LinearLayout android:orientation="horizontal">
|
||||||
|
<PadDataLayoutNew layout_weight="1" enable="@{false}"
|
||||||
|
title='@{"航班日期"}' type="@{DataLayoutType.INPUT}"
|
||||||
|
value='@{viewModel.dataBean.fdate}' />
|
||||||
|
<!-- 更多列... -->
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout android:orientation="horizontal" android:layout_marginTop="8dp">
|
||||||
|
<!-- 第二行... -->
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### Activity 布局完整结构
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<layout>
|
||||||
|
<data>
|
||||||
|
<import SearchLayoutType />
|
||||||
|
<variable viewModel />
|
||||||
|
<variable activity /> <!-- 类型 3 或有 Dialog 操作时 -->
|
||||||
|
</data>
|
||||||
|
<LinearLayout background="@color/color_f2" vertical> <!-- ← 新规范:背景色 -->
|
||||||
|
<include title_tool_bar />
|
||||||
|
<!-- 搜索区:marginHorizontal=10dp, marginTop=10dp -->
|
||||||
|
<LinearLayout horizontal marginHorizontal="10dp" marginTop="10dp">
|
||||||
|
PadSearchLayout × N + 搜索按钮(img_search, 36dp) <!-- ← 新规范:搜索按钮 -->
|
||||||
|
</LinearLayout>
|
||||||
|
<!-- 列表 -->
|
||||||
|
<SmartRefreshLayout> <RecyclerView /> </SmartRefreshLayout>
|
||||||
|
<!-- 底部栏:50dp,根据截图选择深蓝/白色变体 --> <!-- ← 新规范:底部栏 -->
|
||||||
|
<LinearLayout height="50dp" background="..." paddingHorizontal="15dp">
|
||||||
|
<TextView textSize="18sp" textStyle="bold" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</layout>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Item 布局(从截图精确还原每一行每一列)
|
||||||
|
|
||||||
|
- 逐行对照截图中的字段顺序和标签文本
|
||||||
|
- 使用 `completeSpace` 对齐 Key 文本
|
||||||
|
- 运单号等关键字段用 `@color/colorPrimary`
|
||||||
|
- 类型 2/3 左侧有飞机图标:`loadImage="@{bean.checked.get() ? @drawable/img_plane_s : @drawable/img_plane}"`
|
||||||
|
- 列表项背景统一使用 `@drawable/bg_item`
|
||||||
|
- 间距统一:`marginHorizontal="15dp"`, `marginVertical="5dp"`, `padding="10dp"`
|
||||||
|
|
||||||
|
**关键原则:务必尽可能还原截图上的页面设计,不推测不假想。**
|
||||||
|
|
||||||
|
### 第 10 步:创建 Activity
|
||||||
|
|
||||||
|
**固定结构**:
|
||||||
|
```kotlin
|
||||||
|
@Route(path = ARouterConstants.ACTIVITY_URL_XXX)
|
||||||
|
class XxxActivity : BaseBindingActivity<XxxBinding, XxxViewModel>() {
|
||||||
|
override fun layoutId() = R.layout.activity_xxx
|
||||||
|
override fun viewModelClass() = XxxViewModel::class.java
|
||||||
|
|
||||||
|
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||||
|
setBackArrow("页面标题") // 与截图标题一致
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
binding.activity = this // 类型 3 或有 Dialog 时
|
||||||
|
|
||||||
|
// 类型 2/3:观察全选状态
|
||||||
|
viewModel.isAllChecked.observe(this) { binding.checkIcon.alpha = if (it) 1.0f else 0.5f }
|
||||||
|
|
||||||
|
// 绑定分页
|
||||||
|
viewModel.pageModel.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, this)
|
||||||
|
|
||||||
|
// 监听刷新事件
|
||||||
|
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).observe(this) { viewModel.refresh() }
|
||||||
|
|
||||||
|
// 初始化下拉列表(如有)
|
||||||
|
viewModel.initAgentList()
|
||||||
|
viewModel.initSpecialCodeList()
|
||||||
|
|
||||||
|
viewModel.refresh()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 第 11 步:注册 Activity + 菜单入口
|
||||||
|
|
||||||
|
1. **AndroidManifest.xml**:在其他 gjj Activity 注册附近添加:
|
||||||
|
```xml
|
||||||
|
<activity android:name="com.lukouguoji.xxx.activity.XxxActivity"
|
||||||
|
android:configChanges="orientation|keyboardHidden"
|
||||||
|
android:exported="false" android:screenOrientation="userLandscape" />
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **HomeFragment.kt**:
|
||||||
|
- 在对应模块的菜单列表区添加 `RightMenu` 项(图标 + 标题)
|
||||||
|
- 在 onClick 处理区添加路由跳转
|
||||||
|
|
||||||
|
3. **旧版 Activity**(如有):注释掉 `@Route` 注解
|
||||||
|
|
||||||
|
### 第 12 步:编译验证
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew assembleDebug
|
||||||
|
```
|
||||||
|
|
||||||
|
编译必须通过(0 errors)。如有错误,立即修复后重新编译。
|
||||||
|
|
||||||
|
### 第 13 步:查找并对接 API 接口
|
||||||
|
|
||||||
|
页面创建并编译通过后,通过"空港集团 - API 文档"Apifox MCP 工具查找真实接口,替换第 5 步中的占位路径。
|
||||||
|
|
||||||
|
**A. 基础接口查找(每次必查):**
|
||||||
|
|
||||||
|
1. 根据页面所属业务路径(如"国际进港 → 原始舱单"),在 Apifox MCP 中按模块目录搜索
|
||||||
|
2. 查找以下基础接口:
|
||||||
|
- **列表接口**(分页查询,如 `pageQuery`、`list`)
|
||||||
|
- **合计接口**(统计,如 `total`、`count`、`statistics`)
|
||||||
|
- **修改/保存接口**(如 `update`、`save`、`edit`)
|
||||||
|
- **删除接口**(如 `delete`、`remove`)
|
||||||
|
|
||||||
|
**B. 智能接口匹配(根据页面分析):**
|
||||||
|
|
||||||
|
3. 根据**页面类型特性**查找对应接口:
|
||||||
|
- 类型 2(多选批量操作)→ 查找批量操作接口(如批量删除、批量确认等)
|
||||||
|
- 类型 3(嵌套列表)→ 查找子列表相关接口
|
||||||
|
- 类型 5/6(表单页)→ 查找详情查询接口、下拉选项字典接口
|
||||||
|
- 类型 4(Tab 详情)→ 查找各 Tab 对应的数据接口
|
||||||
|
4. 根据**页面中的按钮和文案**,逐一匹配对应接口:
|
||||||
|
- 例如页面有"审核"按钮 → 查找审核接口
|
||||||
|
- 例如页面有"导出"按钮 → 查找导出接口
|
||||||
|
- 例如页面有"打印"按钮 → 查找打印相关接口
|
||||||
|
- 例如底部栏有"清除提货"按钮 → 查找清除提货接口
|
||||||
|
- 例如搜索区有下拉框(代理人、状态等)→ 查找对应的字典/下拉数据接口
|
||||||
|
5. 根据**截图中可见的交互元素**,推断可能需要的接口:
|
||||||
|
- 列表项有右箭头 → 可能需要详情接口
|
||||||
|
- 列表项有编辑图标 → 可能需要编辑/更新接口
|
||||||
|
- 有扫码图标 → 可能需要扫码查询接口
|
||||||
|
|
||||||
|
**C. 对接与校准:**
|
||||||
|
|
||||||
|
6. 找到接口后,更新 `Api.kt` 中的占位路径为真实路径
|
||||||
|
7. 根据接口的请求参数和返回字段结构,校准 Bean 类的字段名和类型
|
||||||
|
8. 遵循 memory 中的 API 搜索原则:不跨模块混用接口,遇到不确定的接口询问用户确认
|
||||||
|
|
||||||
|
### 第 14 步:重新编译验证
|
||||||
|
|
||||||
|
对接真实 API 后重新编译,确保无错误:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew assembleDebug
|
||||||
|
```
|
||||||
|
|
||||||
|
编译必须通过(0 errors)。如有错误,立即修复后重新编译。
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
### UI 设计规范(强制)
|
||||||
|
|
||||||
|
- **必须使用最新 UI 规范**:不管是新增页面、覆盖旧页面还是修改旧页面,都必须完全采用最新典型参考页面的 UI 设计规范
|
||||||
|
- **页面背景色**:根容器必须使用 `@color/color_f2`(`#F2F2F2`),禁止使用旧的白色或其他背景
|
||||||
|
- **搜索按钮**:使用 `@drawable/img_search` 图标(36x36dp + padding 2dp),不使用旧的 `iv_search_action` style
|
||||||
|
- **底部栏**:高度 50dp,文字 18sp bold,根据截图选择深蓝色(`@color/color_bottom_layout` + 白字)或白色(`@color/white` + `@color/bottom_tool_tips_text_color`)
|
||||||
|
- **详情页/表单页**:必须使用 **PadDataLayoutNew**(非旧版 PadDataLayout),卡片用 `bg_white_radius_8`
|
||||||
|
- **严格匹配典型页面**:在写开发计划前,必须先读取最新典型参考页面(如航班查询列表、日志查询页等),总结并列出 UI 设计规范要点
|
||||||
|
|
||||||
|
### 通用规则
|
||||||
|
|
||||||
|
- **资源引用必须存在**:使用 drawable/color/mipmap 前确认资源存在,不存在则换用已有资源
|
||||||
|
- **import 路径查阅 CLAUDE.md**:基类和扩展函数的正确 import 路径参见开发指南的 Import 速查表
|
||||||
|
- **不创建不需要的文件**:如果截图中没有 Dialog 弹窗,不要创建 Dialog 文件
|
||||||
|
- **Bean 复用优先**:如果现有 Bean 的字段足以覆盖截图需求,直接复用
|
||||||
|
- **API 接口对接**:页面创建完成后,通过空港集团 API 文档 MCP 查找真实接口并替换占位路径。遵循 API 搜索原则,按业务模块目录查找,不跨模块混用
|
||||||
|
- **DataBinding 规则**:遵循 CLAUDE.md 中的 DataBinding 关键规则(双向绑定、字符串拼接、View 导入等)
|
||||||
307
.claude/skills/phone-adapt/SKILL.md
Normal file
307
.claude/skills/phone-adapt/SKILL.md
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
---
|
||||||
|
name: phone-adapt
|
||||||
|
description: 参照 documents/5.5寸手持端设计文件/ 的 HTML 设计稿,把 AirLogistics 指定页面适配成 5.5 寸手机竖屏版本——浏览器渲染设计稿逐态截图分析、复用 Phone* 公共组件写手机布局、复用现有 ViewModel 与接口、保证 Pad 端零改动,最后走完整登录流程实机联调并与设计稿逐项核对 UI。当用户说"适配手机端/做手机版/手持端适配"、点名某个设计稿入口(如"02 出库交接"、"做一下出港计重")、要求"按设计稿还原页面"、或提到 5.5 寸/手机版/双形态时,都要使用本 skill,即使没明说"适配"二字。
|
||||||
|
---
|
||||||
|
|
||||||
|
# 5.5 寸手持端页面适配
|
||||||
|
|
||||||
|
把一个已有的平板页面,按设计稿适配出手机竖屏版本。核心约束是**只重写布局,业务逻辑与接口全部复用**,
|
||||||
|
Pad 端行为必须零变化。
|
||||||
|
|
||||||
|
先读 `CLAUDE.md` 的「5.5 寸手持端(手机版)双形态适配规范」章节——那里是权威规范,本 skill 是执行流程。
|
||||||
|
|
||||||
|
## 前置确认
|
||||||
|
|
||||||
|
需要用户给出**目标页面**(设计稿目录名或业务名,如「02 出库交接」/「出港计重」)。
|
||||||
|
其余自己查:`documents/5.5寸手持端设计文件/00_全部入口总览.html` 列出全部 11 个入口,
|
||||||
|
每个子目录下可能有多个 HTML(主页 + 详情 + 子页面),都要处理。
|
||||||
|
|
||||||
|
对应的平板页面靠业务名在 `module_gjc/gjj/gnc/gnj` 里搜 Activity。**注意认准首页菜单实际跳转的那个
|
||||||
|
Activity**,同名旧版文件在这个仓库里很常见。
|
||||||
|
|
||||||
|
## 阶段 1:渲染设计稿,看图不看代码
|
||||||
|
|
||||||
|
设计稿是带 Tailwind + JS 的交互原型,一个 HTML 里常塞了列表页、Tab、详情页、筛选弹层,靠 JS 切换。
|
||||||
|
|
||||||
|
**只读 HTML 源码会出错**,必须渲染成图:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
S=.claude/skills/phone-adapt/scripts
|
||||||
|
# 1) 先看有哪些状态可切
|
||||||
|
python3 $S/design_shots.py --html "documents/5.5寸手持端设计文件/02_出库交接/出库交接.html" --list
|
||||||
|
|
||||||
|
# 2) 按 --list 结果逐态渲染(照抄 onclick 里的真实参数最省事)
|
||||||
|
python3 $S/design_shots.py --html "…/出库交接.html" --out /tmp/design \
|
||||||
|
--state "01_列表:" \
|
||||||
|
--state "02_已交接Tab:switchTab('shipped');" \
|
||||||
|
--state "03_详情:showDetail({id:'PMC90901CZ',status:'已交接',rackNo:'076'});" \
|
||||||
|
--state "04_筛选弹层:toggleFilterDrawer(true);"
|
||||||
|
```
|
||||||
|
|
||||||
|
然后用 Read 工具**逐张看图**,抽取:配色、字号、圆角、间距、图标、控件顺序、空态、
|
||||||
|
各状态下哪些元素显示/隐藏(例如「已交接」Tab 下底部操作条整条消失)。
|
||||||
|
|
||||||
|
`--list` 输出里如果出现 `window.location.href='xxx.html'`,说明是多文件原型,那些文件同样要渲染。
|
||||||
|
|
||||||
|
**设计稿的 JS 可能有 bug,别照抄字段映射。** 出库交接的详情页就把「航班日期」绑成了重量、
|
||||||
|
「备注」绑成了航班号(HTML 里 id 重复)。判断依据是**静态 label 文案**:label 写「航班日期」
|
||||||
|
就绑 `fdate`,写「板型」就绑 `boardType`。label 是设计意图,JS 只是 demo 接线。
|
||||||
|
|
||||||
|
标签文案同理:卡片上写死的「IMP代码」是占位符,实际要绑 `bean.dgrCode` 的值。
|
||||||
|
|
||||||
|
## 阶段 2:对齐接口能力,不要臆想
|
||||||
|
|
||||||
|
把设计稿的每个筛选项/Tab/字段,对照平板 ViewModel 已有的字段:
|
||||||
|
|
||||||
|
- **已有字段** → 直接复用(如出港移库的 Tab 直接绑既有 `moveState`)
|
||||||
|
- **平板没有的新维度**(新 Tab 状态、新下拉、新排序)→ **先查 api-doc MCP 拿权威参数名**,
|
||||||
|
流程见 `references/api-doc.md`(连接方式 + 5 个工具 + 逐接口核对清单)
|
||||||
|
|
||||||
|
**最高决策规则(用户 2026-07-29 拍板,此后不再逐次询问):业务改动完全以设计稿为准,不做妥协。**
|
||||||
|
接口不支持设计稿的某个维度时:UI 照设计稿完整实现(绑预留字段/占位,传参后端静默忽略无副作用),
|
||||||
|
缺口直接登记 `documents/后端接口对接问题清单.xlsx` 提修改需求,后端补齐后前端自动生效。
|
||||||
|
仅当设计稿本身歧义(label 无法推断字段语义)才用 `AskUserQuestion` 问用户。
|
||||||
|
|
||||||
|
这一步不能猜,也**不要拿「实测不生效」当结论**。出库交接第一版猜了 `hoState`,实测两个 Tab
|
||||||
|
返回同一批数据,一度误判为「后端不支持」;后查 api-doc 才发现正确参数名是 `handoverState`——
|
||||||
|
后端对不认识的参数是**静默忽略**,不报错,实测只能证明「这个名字不对」,证不出「后端没这能力」。
|
||||||
|
|
||||||
|
「参数是否真的生效」的 A/B 验证优先走 Proxyman MCP(`create_compose_http_from_flow` 复制
|
||||||
|
真实请求改参重发,token 自动带上),分工与流程见 `references/proxyman.md`:
|
||||||
|
**api-doc 管契约(该有什么),Proxyman 管事实(实际发/回了什么)**。
|
||||||
|
|
||||||
|
核对完把结论落两处(模板与格式见 `references/api-doc.md`):
|
||||||
|
|
||||||
|
- 后端真实缺口(缺入参/缺出参/数据不回填)→ 记入 `documents/后端接口对接问题清单.xlsx`,
|
||||||
|
这是与后端对接的正式文档,按「模块 → 页面 → 接口定义 → 接口地址」索引,**每个页面适配完都要维护**
|
||||||
|
- 参数名/字段绑定错误这类前端问题 → 直接改代码
|
||||||
|
|
||||||
|
阶段 5 仍要用真实请求体验证新参数确实生效;没生效就在清单文档与交付说明里如实标注,
|
||||||
|
不要让它看起来是通的。
|
||||||
|
|
||||||
|
### 开工前对齐方案
|
||||||
|
|
||||||
|
分析完先把结论摊给用户,避免闷头做错方向。一次说清,别挤牙膏:
|
||||||
|
|
||||||
|
```
|
||||||
|
📱 页面适配方案:<页面名>
|
||||||
|
|
||||||
|
设计稿:documents/5.5寸手持端设计文件/<目录>/(N 个 HTML:主页 / 详情 / …)
|
||||||
|
平板页面:XxxActivity + XxxViewModel(module_xxx)
|
||||||
|
|
||||||
|
手机版结构:
|
||||||
|
搜索行:<字段>(含扫码/筛选按钮)
|
||||||
|
状态 Tab:<Tab1> / <Tab2> → 绑定 <字段名>
|
||||||
|
列表卡片:<字段…>,两种形态(<形态A> / <形态B>)
|
||||||
|
底部操作条:全选 + 已选统计 + [<按钮>]
|
||||||
|
筛选弹层:<字段1> / <字段2> / <字段3>
|
||||||
|
二级页:<详情页名>(新增 Activity / 复用已有)
|
||||||
|
|
||||||
|
复用组件:PhoneSearchBar、PhoneStatusTab、PhoneStatBox…(无需新增 / 需新增 XXX)
|
||||||
|
|
||||||
|
接口:列表 <接口> 复用;新增参数 <名>(待你确认);新增字典 <DictUtils 方法>
|
||||||
|
Pad 端影响:无(新字段默认空、额外请求由手机开关控制)
|
||||||
|
|
||||||
|
设计稿与平板的差异:<如手机版无「配运」按钮>
|
||||||
|
|
||||||
|
确认后开始编码。
|
||||||
|
```
|
||||||
|
|
||||||
|
## 阶段 3:写布局,复用公共组件
|
||||||
|
|
||||||
|
`module_base/.../ui/weight/phone/` 已有 7 个组件,**优先复用,不要重写 XML**。
|
||||||
|
组件清单、属性表与用法见 `references/components.md`(写布局前读一遍)。
|
||||||
|
|
||||||
|
改造步骤:
|
||||||
|
|
||||||
|
1. 平板布局 `git mv` 到 `res/layout-sw600dp/`(item 布局同理)
|
||||||
|
2. 在 `res/layout/` 下建**同名**文件写手机布局
|
||||||
|
3. Kotlin 侧 `layoutId()` / `itemLayoutId` **一律不动**,不做设备分支
|
||||||
|
|
||||||
|
三条硬约束(违反会编译失败或运行时崩溃,细节见 `references/pad-safety.md`):
|
||||||
|
|
||||||
|
| 约束 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| 两变体 `<variable>` 完全一致 | 手机变体新增 `activity` 变量时,平板变体也要补上(写注释说明平板不用它) |
|
||||||
|
| 共用 id 双方都要有 | ViewHolder/Activity 引用的 id(`srl`/`rv`/`iv_icon` 等)两边都保留 |
|
||||||
|
| 单侧独有 id 自动 `@Nullable` | 如手机独有的 `ll_detail`,ViewHolder 里必须判空调用 |
|
||||||
|
|
||||||
|
**一套 item 布局覆盖多种卡片形态**,不要为「待交接/已交接」建两个布局。按 bean 状态切
|
||||||
|
visibility 即可(Bean 上加个只读计算属性如 `isHandovered` 让 XML 更干净;计算属性不参与 Gson
|
||||||
|
序列化,安全)。
|
||||||
|
|
||||||
|
## 阶段 4:接业务,且不碰 Pad
|
||||||
|
|
||||||
|
手机端新增的查询维度用这个模式,能做到平板端请求次数与行为零变化:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
// ViewModel:新字段默认空值,getData() 里仅非空才进请求
|
||||||
|
val handoverState = MutableLiveData("") // 平板布局无对应控件 → 恒为空 → 不进请求
|
||||||
|
val filterParams = mapOf(
|
||||||
|
/* 原有字段… */
|
||||||
|
"handoverState" to handoverState.value?.ifEmpty { null }, // 参数名以 api-doc 为准
|
||||||
|
)
|
||||||
|
|
||||||
|
// 手机专属的额外请求(Tab 角标计数、新下拉字典)用内部开关控制
|
||||||
|
private var phoneExtrasEnabled = false
|
||||||
|
fun initPhoneExtras() { phoneExtrasEnabled = true; handoverState.value = "0"; /* 加载字典 */ }
|
||||||
|
```
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
// Activity:只有手机形态才开启,平板不调用
|
||||||
|
if (DeviceUtil.isPhone()) viewModel.initPhoneExtras()
|
||||||
|
```
|
||||||
|
|
||||||
|
设备判断只用于**数据默认值与额外请求**,**绝不用于选布局**(选布局靠资源限定符)。
|
||||||
|
|
||||||
|
纯 UI 交互(弹层显隐、Tab 切换)写在 Activity,用 `ObservableBoolean` 暴露给 XML,不下沉到 ViewModel。
|
||||||
|
|
||||||
|
设计稿若少了平板上的某个按钮(如出库交接手机版只有「交接」没有「配运」),按设计稿做,
|
||||||
|
但要在交付说明里点出来这个功能在手机端不可达,让用户决定。
|
||||||
|
|
||||||
|
新增手机专属页面(详情页等)记得:`app/src/main/AndroidManifest.xml` 注册 +
|
||||||
|
`app/src/debug/AndroidManifest.xml` 追加 `exported="true"` 便于直启调试。
|
||||||
|
|
||||||
|
注册时 `screenOrientation` **必须写 `unspecified`**:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<activity android:name="…"
|
||||||
|
android:configChanges="orientation|keyboardHidden"
|
||||||
|
android:exported="false"
|
||||||
|
android:screenOrientation="unspecified" />
|
||||||
|
```
|
||||||
|
|
||||||
|
- 写死 `userLandscape` → 手机端「先横屏、约 1 秒后转竖屏」闪一下(方向在建窗口时就定了,代码再纠正已晚)
|
||||||
|
- 用 `@integer/xxx` 资源引用 → **更糟**:系统解析 Manifest 不套用设备限定符,平板会取到默认(竖屏)值,
|
||||||
|
先竖后横,且 AutoSize 随之选错基准导致 UI 放大约 1.6 倍
|
||||||
|
|
||||||
|
`unspecified` 让系统按设备当前物理方向建窗口,两端起始方向本就正确,
|
||||||
|
`BaseActivity` 的形态锁定不会产生二次纠正。
|
||||||
|
|
||||||
|
### ⚠️ 别忘了加手机端首页入口
|
||||||
|
|
||||||
|
手机端首页是 `module_p` 的 `PDAEnterActivity`,「国际」Tab 的菜单在
|
||||||
|
`module_p/.../ui/enter/gj/GjViewModel.kt`(国内在 `gn/GnViewModel.kt`)。
|
||||||
|
**菜单是手写清单,不是接口下发**;权限串只做过滤(`authList.contains(bean.key)`)。
|
||||||
|
|
||||||
|
适配完页面不回来加一行,手机上就**根本没有入口**——出库交接第一版就漏了这步,
|
||||||
|
只能靠 adb 直启才能进去。加法:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
ActionBean(
|
||||||
|
"出港移库",
|
||||||
|
R.drawable.gjc_yi_ku_icon, // 图标复用 Pad 同款,复制 PNG 到 module_p/res/drawable-xxhdpi/
|
||||||
|
Constant.AuthName.GjcYiKuListActivity, // 权限串与 Pad 端菜单一致
|
||||||
|
ARouterConstants.ACTIVITY_URL_INT_EXP_MOVE // 填了 route 就走通用跳转,无需 when 分支
|
||||||
|
),
|
||||||
|
```
|
||||||
|
|
||||||
|
权限串和路由**都以 Pad 端 `app/.../HomeFragment.kt` 里该权限对应的 `ARouter.build(...)` 为准**
|
||||||
|
(同一业务常有新旧两个 Activity,Pad 菜单实际跳的才是要适配的那个)。
|
||||||
|
`module_p` 只依赖 `module_base`,看不到业务模块,所以跨模块必须走 ARouter、图标必须复制一份。
|
||||||
|
|
||||||
|
菜单没出现时先分清是「没权限」还是「没加清单」:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
adb -s <serial> shell "run-as com.lukouguoji.aerologic \
|
||||||
|
cat /data/data/com.lukouguoji.aerologic/shared_prefs/data.xml" | tr ',' '\n' | grep -oE "App[A-Za-z]+" | sort -u
|
||||||
|
```
|
||||||
|
|
||||||
|
## 阶段 5:端到端实机验证
|
||||||
|
|
||||||
|
先构建,再双端跑。命令与排障细节见 `references/verification.md`。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew assembleDebug 2>&1 | grep -E "^(BUILD|FAILURE)|error:"
|
||||||
|
```
|
||||||
|
|
||||||
|
构建过后核对 DataBinding 变体是否如预期(单侧 id 应为 `@Nullable`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -B3 "llDetail" module_gjc/build/generated/data_binding_base_class_source_out/debug/out/\
|
||||||
|
com/lukouguoji/gjc/databinding/ItemXxxBinding.java
|
||||||
|
```
|
||||||
|
|
||||||
|
**手机端**(真实数据链路,从登录开始):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
P=.claude/skills/phone-adapt/scripts/ui_probe.sh
|
||||||
|
adb -s <phone> install -r -d app/build/outputs/apk/debug/app-debug.apk
|
||||||
|
# 走登录 → 底部「国际」Tab → 点新加的菜单项进入(顺便验证入口加对了)
|
||||||
|
# 同名文字多处时 tap-text 会提示命中数,用第 4 个参数指定序号(如底部 Tab 的「国际」)
|
||||||
|
# 若账号确实没有该权限,改用冷启动直启(见 verification.md)
|
||||||
|
$P <phone> form # 应打印 PHONE(sw=411dp…)
|
||||||
|
$P <phone> wait-text "待交接" # 点击前先等页面就绪:加载弹窗会吞掉点击
|
||||||
|
$P <phone> tap-text "已交接" # 按文字点击,比手算坐标可靠
|
||||||
|
$P <phone> texts # 用文字变化断言点击确实生效(如底部条应消失)
|
||||||
|
$P <phone> shot /tmp/p1.png
|
||||||
|
$P <phone> crash # 必须为 0
|
||||||
|
```
|
||||||
|
|
||||||
|
核对请求/响应体优先用 Proxyman MCP(`filter_flows` + `get_flow_detail`,比 `req` 的
|
||||||
|
logcat 抓包完整可靠;模拟器代理一行命令接入,见 `references/proxyman.md`);
|
||||||
|
Proxyman 不可用时兜底 `$P <phone> req pageQuery`。
|
||||||
|
|
||||||
|
逐项走查:列表/卡片两种形态、详情页、筛选弹层(重置+确认)、Tab 切换、单选与全选联动、
|
||||||
|
下拉真实取数、扫码入口。每步 `crash` 都要为 0。
|
||||||
|
|
||||||
|
点完**一定要断言效果**(`texts` 或截图),不要假设点中了——加载弹窗盖屏时 `input tap` 会被静默吞掉。
|
||||||
|
|
||||||
|
手机端还要确认方向没闪屏(冷启动采样 `mRotation` 应恒为 0),命令见 `references/verification.md`。
|
||||||
|
|
||||||
|
**Pad 端回归**(必做):同样安装到平板模拟器打开同一页面截图,与改造前逐项对比——
|
||||||
|
搜索条数量、默认值、按钮、底部统计都应一致。改过 `module_base` 公共组件时这步尤其不能省。
|
||||||
|
|
||||||
|
## 阶段 6:与设计稿二次核对
|
||||||
|
|
||||||
|
把阶段 1 的设计稿截图和阶段 5 的实机截图放在一起,用 Read 工具对照看,逐项核对:
|
||||||
|
|
||||||
|
配色 / 字号 / 字重 / 圆角 / 内外间距 / 图标形状与大小 / 控件顺序 / 选中态 / 状态标签配色 /
|
||||||
|
**空值兜底**(真实数据空字段很常见——出库交接就出现过「库位」为空时橙色高亮标签只剩一个孤零零的
|
||||||
|
小色块,需要空值时不套标签底)。
|
||||||
|
|
||||||
|
服务端当天没数据时(列表空)先放宽条件重查;仍为空、或要覆盖真实数据凑不出的形态
|
||||||
|
(空字段、超长文本、罕见状态标签),**首选 Proxyman Map Local 造 mock**——零代码改动、
|
||||||
|
零重构建,见 `references/proxyman.md` 场景 3(2026-07-31 出港查询用它一次验完
|
||||||
|
已离港/已入库/未入库三种卡片形态)。验证完 `delete_rule` + 清模拟器代理。
|
||||||
|
|
||||||
|
Proxyman 不可用时才退回老办法:Activity 里临时注入样例 Bean 截图比对:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
// import com.lukouguoji.module_base.ktx.commonAdapter
|
||||||
|
binding.rv.postDelayed({
|
||||||
|
binding.rv.commonAdapter()?.refresh(listOf(/* 覆盖每种卡片形态各一条 */))
|
||||||
|
}, 2500) // 等首次请求结束,否则会被真实结果覆盖
|
||||||
|
```
|
||||||
|
|
||||||
|
**核对完必须删掉**,删完重新构建并 grep 确认无残留。
|
||||||
|
|
||||||
|
## 收尾:文档与交付说明
|
||||||
|
|
||||||
|
代码之外还要落四处文档,否则下一个人会重复踩坑:
|
||||||
|
|
||||||
|
- 新增了公共组件/资源 → 更新 `CLAUDE.md`「手机版公共组件库」表 + `references/components.md`
|
||||||
|
- 踩到新坑(崩溃、静默失效、环境问题)→ 写进 `CLAUDE.md`「常见编译错误速查」和本 skill 的
|
||||||
|
对应 reference,把**定位手法**也写上,不只写结论
|
||||||
|
- 接口有后端缺口(阶段 2 / 阶段 5 发现的)→ 维护 `documents/后端接口对接问题清单.xlsx`;
|
||||||
|
已确认的字段语义追加到 `references/api-doc.md` 的「已核对过的语义」,别让下个页面再查一遍
|
||||||
|
- `CHANGELOG.md` 追加条目(新增 / 改进 / 修复 / 验证 四段),记忆文件
|
||||||
|
`phone-5.5inch-adaptation.md` 同步
|
||||||
|
|
||||||
|
向用户汇报时明确写出这四块:
|
||||||
|
|
||||||
|
1. 新增/修改的文件清单(布局、组件、Activity/ViewModel/Bean)
|
||||||
|
2. Pad 端零破坏的具体做法 + 回归结论
|
||||||
|
3. 复用与新增的公共组件
|
||||||
|
4. **待确认事项**:后端未生效的参数、自己推断的业务规则(如 IMP 代码红/绿的判定)、
|
||||||
|
设计稿与平板功能的差异。如实说,别含糊。
|
||||||
|
|
||||||
|
## 参考文件
|
||||||
|
|
||||||
|
- `references/api-doc.md` — api-doc MCP 连接与逐接口核对流程、后端缺口记录规范、已核对字段语义(阶段 2 前读)
|
||||||
|
- `references/proxyman.md` — Proxyman MCP 抓包/直调 A/B/Map Local mock 的接入与四个场景(阶段 2、5、6 用;与 api-doc 的分工:契约 vs 事实)
|
||||||
|
- `references/components.md` — 7 个手机版公共组件的属性表、用法与封装新组件的规矩(写布局前读)
|
||||||
|
- `references/pad-safety.md` — 布局变体约束、Pad 零破坏模式、易崩点(写代码前读)
|
||||||
|
- `references/verification.md` — 双端 adb 命令、登录与直启、已知环境坑(验证前读)
|
||||||
|
- `scripts/design_shots.py` — 设计稿逐态渲染截图
|
||||||
|
- `scripts/ui_probe.sh` — 实机取文字/按文字点击/等待/截图/抓请求体/查崩溃
|
||||||
160
.claude/skills/phone-adapt/references/api-doc.md
Normal file
160
.claude/skills/phone-adapt/references/api-doc.md
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
# 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 待确认)
|
||||||
|
- `IntExpArrive`(出港运抵,2026-07-30 内网实测):`declareStatus`(申报状态)只在出参,
|
||||||
|
`pageQuery`/`pageQueryTotal` 入参均无此字段(缺口 #20,待运抵/已运抵 Tab 靠客户端拆分);
|
||||||
|
`declareStatus`/`GjcHaWb.arrivalStatus` 三色编码:`01`=正常(绿)、`W`=靛蓝态、其余非空=琥珀异常态;
|
||||||
|
`haWbList[].response`/`arrivalOpDate` 是回执文本与对应时间,实测确认真实存在非空数据;
|
||||||
|
分单补充收发货人信息**后端完全没有对应接口**(`search_endpoints` 对 `IntExpArrive`/`HaWb`
|
||||||
|
关键字均搜不到分单更新接口,只有国际进港的 `IntImpAirManifest/complete`),
|
||||||
|
实机调用拟定路径 `IntExpArrive/haWb/supplement` 确认 404(缺口 #19)
|
||||||
|
- `IntExpSearch`(出港查询,2026-07-31 内网实测):查询入参 `outState`/`fno`/`dest`/`spCode`/`awbType`/
|
||||||
|
`businessType`/`goodsCn`/`beginDate`/`endDate`/`agentCode`/`wbNo` 全部真实生效(平板既有口径);
|
||||||
|
文档定义的 `isFclose`(筛选航班是否关闭)**pageQuery 与 pageQueryTotal 均静默忽略**(A/B 对照
|
||||||
|
全量 72 票与单日两组,加参前后结果完全一致,缺口 #21);`pageQueryTotal` 出参无已入库/已离港
|
||||||
|
分项计数(#21);`detail` 出参 Map 无 `lockStatus`(锁定状态)与计费重量字段(#22);
|
||||||
|
详情「入库件数/入库重量」= `warehouseList` 各批次 pc/weight 求和(mock 与实测均吻合);
|
||||||
|
卡片状态推断口径:`fclose` 非空=已离港、否则 `opDate` 非空=已入库;
|
||||||
|
特码字典沿用 `DictUtils.getSpecialCodeList(flag=1, ieFlag="")`(ieFlag 必须空串)
|
||||||
|
- `IntExpStorageUse`(出港仓库,2026-07-31 文档核对,内网 A/B 未测——当日开发机不在内网):
|
||||||
|
`pageQuery`/`pageQueryTotal` 同一套入参 schema:`fdate`/`fno`/`wbNo`/`likeNo`/`spCode`/`dest`/
|
||||||
|
`agentCode`/`location`/`clearNormal`/`checkIn`/`reviewStatus`/`dep`/`hno`/`prefix`;设计稿筛选的
|
||||||
|
**运单类型/业务类型/品名(中) 均无入参**(`awbType`/`businessType`/`goodsCn`,缺口 #23);
|
||||||
|
手机三格统计按 `clearNormal=0/1` 各调一次 `pageQueryTotal` 取 `wbNumber`,该过滤**是否真实生效
|
||||||
|
待内网 A/B**(缺口 #24,参照 isFclose 有定义但被忽略的先例);出参 `clearNormal` 0=未清仓/1=已清仓
|
||||||
|
(卡片标签与「清仓」按钮置灰按 ==\"1\" 判定);详情复用 `IntExpSearch/detail`(maWbId Query 参数)
|
||||||
|
- `IntImpStorage`(进港仓库,2026-07-31 文档核对;**注意前端 Api.kt 路径前缀是 `IntImpStorage`
|
||||||
|
不是 `IntImpStorageUse`**,api-doc 按后者搜不到):`pageQuery`/`pageQueryTotal` 同一套入参:
|
||||||
|
`fdate`/`fno`/`wbNo`/`hno`/`fdep`(始发站)/`location`/`clearNormal`/`fid`;比出港仓库还少
|
||||||
|
`agentCode`/`spCode`/`dest`——设计稿筛选的代理/特码/运单类型/业务类型/品名(中) **5 项均无入参**
|
||||||
|
(缺口 #25);分项统计与 clearNormal 过滤待实测同 #24(记为 #26);详情复用
|
||||||
|
`IntImpSearch/detail`(Body 传 `prefix`+`no`,出参 `data.maWb` 无 schema,字段 key 以平板绑定为准:
|
||||||
|
`awbPc`/`awbWeight`/`cashWeight`/`inPc`/`inWeight`/`lockState`(0/1 需转中文)/`mftStatus` 原始舱单/
|
||||||
|
`tallyStatus` 理货报告/`command` 海关放行/`by1` 承运人/`dlvTime` 出库时间;`dep`/`dest1`/`dest`/
|
||||||
|
`unNumber`/`opDate` 为按出港推断,待实测 #27)
|
||||||
|
- `IntImpPickUpDlv`(提取出库,2026-07-31 文档核对):`pageQuery` 入参含 **`outState`
|
||||||
|
(0 未出库/1 已出库)**——待出库/已出库 Tab 直接真实过滤(抓包证实携带,效果待内网 A/B #29);
|
||||||
|
另有 `fno`/`dest`/`origin`/`carrier`/`awbType`/`businessType`/`goods`/`likeNo`/`pkId`/
|
||||||
|
`beginDate`/`endDate`+`dateType`(0 入库/1 离港)/`chargeFlag`(0 未提取/1 已提取);
|
||||||
|
**无 `fdate`(航班日期)入参**(缺口 #28);出参无车牌/目的港/业务类型名称(#28);
|
||||||
|
运单号筛选参数名是 **`no`**(平板既有口径);`chargeName`/`chargeTime` = 柜台办理人/缴费(提取)时间,
|
||||||
|
`dlvTime` = 出库时间,`dlvName` 按提货人语义推断作「出库人」展示(待确认 #29);
|
||||||
|
确认出库接口 `pickUpOut` 文档注明**需将全字段传至后端**(平板 `selectedItems.toRequestBody()` 已满足)
|
||||||
|
- `IntImpSearch`(进港查询,2026-07-31 文档核对):`pageQuery`/`pageQueryTotal` 分页参数名是
|
||||||
|
**`page`/`limit`**(不是 pageNum/pageSize);手机筛选 9 项入参全部真实存在:`beginDate`/`endDate`/
|
||||||
|
`fno`/`agentCode`/`spCode`/`origin`(始发站)/`awbType`/`businessType`/`goods`(品名,**不是 goodsCn**);
|
||||||
|
`outState`(0 未出库/1 已出库)文档为 integer,前端传字符串靠 Jackson 隐式转换;`pageQueryTotal`
|
||||||
|
出参无已入库/已出库分项计数(缺口 #30,手机三格统计为客户端计数口径:dlvTime 非空=已出库、
|
||||||
|
inDate 非空=已入库);出参含 `agentName`(中文名)+ `agentCode`,agentName 可为 null
|
||||||
|
- 「进港移库」(设计稿 11)**归属更正(2026-08-03 用户确认):属国内进港移库 `DomImpMove`**,
|
||||||
|
不是国际进港移库——「后端模块缺失」的旧结论(原缺口 #31)作废,原按 IntExpMove 约定预接的
|
||||||
|
IntImpMove 前端实现已整体删除。溯源:api-doc 53 模块中移库仅 `DomImpMove`(国内进港,8 接口)与
|
||||||
|
`IntExpMove`(国际出港,4 接口),移库按转关业务前缀划分(DomImpMove 处理 `CI**`、IntExpMove
|
||||||
|
处理 `IO**`),设计稿详情卡的「国际进港」红标签实为 `awbType` 值(如「国际进港(国内中转)」),
|
||||||
|
不代表页面归属
|
||||||
|
- `DomImpMove`(国内进港移库,2026-08-03 内网实测):手机 Tab 双端点——待移库 `search` /
|
||||||
|
已移库 `searchMoved`(同一套入参 schema,分页参数名 **`page`/`limit`**);入参 A/B 实测:
|
||||||
|
**`wbNo`、`awbType`(值为 CICO/CIII/CIIO 转关码)过滤生效;`fdate`/`fno`/`spCode` 文档有定义但
|
||||||
|
被静默忽略**(缺口 #32);`searchMoved`/`detail` 出参 **`opId`/`opDate` 恒 null** 且无操作人姓名
|
||||||
|
字段(缺口 #33,移库人/移库时间显示"-"),`moveId` 形如 `CICO240617155016` 疑似内嵌移库时间戳但无
|
||||||
|
文档语义;`searchMoved` 出参**无 pic 三字段**(search 有)——拍照上传页统一先调 `GET detail`
|
||||||
|
回填已有照片(#34 前端已规避);照片提交走 `modify` 最小体
|
||||||
|
`{mawbId, remark, picNumber, pic, originalPic}`(平板移交编辑页同链路,removeEmptyOrNull);
|
||||||
|
批量移库 `move` 入参 `{fid:"0", ids:[mawbId]}`;国内进港特码字典
|
||||||
|
`DictUtils.getSpecialCodeList(flag=0, ieFlag="I")` 实测取数正常
|
||||||
|
- `IntExpCheckIn`(出港计重,2026-07-29 内网实测):`likeNo` **并非任意模糊**——按 8 位 `no`
|
||||||
|
匹配(11 位 wbNo 或部分号均 0 条),11 位全号必须走 `wbNo`;`checkIn`/`checkInList`
|
||||||
|
文档有定义但 `pageQuery`/`pageQueryTotal` **均静默忽略**(缺口 #12,待计重/计重中计数依赖);
|
||||||
|
查询入参无通道号/承运人/运单类型(#13)、`checked/*` 无收运时间范围(#14);`checked/pageQuery`
|
||||||
|
出参无通道号(#15)但有 `userName`(计重人中文名);`listRecordByWh` 出参计重人仅 `opId`(#16);
|
||||||
|
`preArrive` 成功后 `pageQuery` 的 `arriveFlag` 不回填(#17);`splitCheckIn`/`completeCheckIn`
|
||||||
|
无 `palletNumber`/`carWeight` 入参(#18,手机版托盘数量/自重按设计稿传预留参数);
|
||||||
|
运单类型字典:`DictUtils.getWaybillTypeList2(ieFlag="E", type="IO")`
|
||||||
|
|
||||||
|
## 内网直调验证技巧(比驱动 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)驱动,滑完截图校准。
|
||||||
140
.claude/skills/phone-adapt/references/components.md
Normal file
140
.claude/skills/phone-adapt/references/components.md
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
# 手机版公共组件(`module_base/.../ui/weight/phone/`)
|
||||||
|
|
||||||
|
7 个组件覆盖设计稿反复出现的部件。**先复用,实在没有再新增**——每个新组件都要维护、都要踩一遍
|
||||||
|
状态恢复的坑,能少一个是一个。
|
||||||
|
|
||||||
|
所有属性都是**无命名空间写法**(与平板端 `PadSearchLayout` 一致),DataBinding 适配器集中在
|
||||||
|
`PhoneWidgetKtx.kt`。同名属性(`hint`/`value`/`title`/`list`)按控件类型解析,与 Pad 系组件不冲突。
|
||||||
|
|
||||||
|
## 组件与属性
|
||||||
|
|
||||||
|
| 组件 | 用途 | 属性 |
|
||||||
|
|------|------|------|
|
||||||
|
| `PhoneSearchBar` | 顶部搜索行:搜索框 + 扫码 + 圆形筛选按钮 | `hint`、`value`(双向)、`showScan`、`showFilter`、`upperCase`、`setOnScanClickListener`、`setOnFilterClickListener`、`setRefreshCallBack` |
|
||||||
|
| `PhoneStatusTab` | 状态 Tab 条(文字 + 角标 + 选中下划线) | `tabs`(List\<KeyValue\>)、`counts`(List\<String\>)、`value`(双向)、`setOnTabChanged` |
|
||||||
|
| `PhoneDataLayout` | 表单/筛选项,三形态 | `title`、`hint`、`type`(`PhoneDataLayoutType.INPUT`/`DATE`/`SPINNER`)、`value`(双向)、`list`、`required`、`enable`、`setRefreshCallBack` |
|
||||||
|
| `PhoneFilterPanel` | 底部筛选弹层(遮罩 + 面板 + 重置/确认) | `title`、`panelVisible`、`setOnResetClick`、`setOnConfirmClick`、`setOnDismissClick` |
|
||||||
|
| `PhoneBottomBar` | 底部操作条(全选 + 已选统计 + 主按钮) | `allChecked`、`countText`、`actionText`、`setOnAllCheckClick`、`setOnActionClick` |
|
||||||
|
| `PhoneStatBox` | 卡片内 2~4 列统计框,未传 label 的列自动隐藏 | `label1..4`、`value1..4` |
|
||||||
|
| `PhoneKvItem` | 详情页字段项(灰标签 + 数值) | `title`、`value`、`tag`(true → 高亮标签)、`tagColor`("orange" 默认 / "green" 放行正常态);占位符 "-"/"--" 不套标签底 |
|
||||||
|
| `PhoneFormRow` | 行式表单项(左标签 minWidth 110dp + 右值 + 1px 分隔线),覆盖新增/修改/详情三态表单 | `title`、`hint`、`type`(`PhoneFormRowType.INPUT`/`SELECT`/`DATE`/`TEXT`)、`value`(双向)、`list`(SELECT 选项)、`required`、`enable`、`numeric`、`setRefreshCallBack` |
|
||||||
|
|
||||||
|
`PhoneFormRow` 要点:SELECT 内置 XPopup 底部选择面板(点击整行弹出,无需页面代码);TEXT 为只读右对齐、
|
||||||
|
空值自动占位 "--"(详情态);type 用三元按 `pageType` 切换即可一套布局覆盖三态页面(参考
|
||||||
|
`app/res/layout/activity_uld_edit.xml`)。`PhoneBottomBar` 的 `actionDanger="@{true}"` 切浅红删除按钮。
|
||||||
|
|
||||||
|
`PhoneFilterPanel` 内容插槽已内置 ScrollView(2026-07-31 加):筛选项少时行为不变;
|
||||||
|
筛选项多到超屏(出港查询 9 项)时内容区收缩滚动,底部「重置/确认」按钮始终可见——
|
||||||
|
此前无滚动时按钮会被挤出屏幕外且毫无报错,只表现为"点不到确认"。
|
||||||
|
|
||||||
|
⚠️ 两个已踩坑:
|
||||||
|
- **FAB 盖住弹层**:浮动按钮带 elevation 时会浮在 `PhoneFilterPanel` 之上,弹层实例要加
|
||||||
|
`android:elevation="8dp"`(> FAB 的 6dp)
|
||||||
|
- **Spinner 选择回调是异步的**:`onItemSelected` 由系统 post,自动化测试里 tap 选项后立即 tap「确认」
|
||||||
|
可能抢在回值之前发出请求(表现为 UI 已显示选中但请求参数为 null)——脚本里选完要 `sleep 1` 以上;
|
||||||
|
真人操作间隔足够,不受影响
|
||||||
|
|
||||||
|
`KeyValue` 是 `dev.utils.app.info.KeyValue`,字段是 **`key`(显示文案)+ `value`(业务值)**,
|
||||||
|
不是 `name`。`PhoneStatusTab` 的 `tabs` 就按 `KeyValue("待交接","0")` 传。
|
||||||
|
|
||||||
|
## PhoneFilterPanel 的内容插槽
|
||||||
|
|
||||||
|
筛选项直接写在标签内,组件 `onFinishInflate` 会自动把它们移进面板中部并施加 20dp 项间距,
|
||||||
|
使用方不用关心内部层级、也不用逐个写 `marginTop`:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneFilterPanel
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
title='@{"筛选条件"}'
|
||||||
|
panelVisible="@{activity.filterPanelVisible}"
|
||||||
|
setOnResetClick="@{(v)-> activity.resetFilter()}"
|
||||||
|
setOnConfirmClick="@{(v)-> activity.confirmFilter()}"
|
||||||
|
setOnDismissClick="@{(v)-> activity.toggleFilterPanel()}">
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
title='@{"航班日期"}' hint='@{"请选择航班日期"}'
|
||||||
|
type="@{PhoneDataLayoutType.DATE}" value="@={viewModel.flightDate}" />
|
||||||
|
|
||||||
|
</com.lukouguoji.module_base.ui.weight.phone.PhoneFilterPanel>
|
||||||
|
```
|
||||||
|
|
||||||
|
记得在 `<data>` 里 `<import type="com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayoutType" />`。
|
||||||
|
|
||||||
|
## ⚠️ 新增复合组件必做:屏蔽子控件状态恢复
|
||||||
|
|
||||||
|
同一页面放多个同类组件时(比如筛选弹层里 3 个 `PhoneDataLayout`),它们的内部子控件
|
||||||
|
(`et`/`tv`/`spinner`…)**共用同一套 id**。系统按 id 保存/恢复视图状态会跨实例串档。
|
||||||
|
|
||||||
|
实际后果(出库交接踩过):DATE 项的默认日期被邻近输入框恢复的空文本覆盖,
|
||||||
|
`EditText.setText("")` 触发 `doOnTextChanged`,再经双向绑定把 ViewModel 的航班日期也写成空——
|
||||||
|
**筛选条件静默丢失,界面上只表现为"日期没了",极难联想到状态恢复**。
|
||||||
|
|
||||||
|
所以每个含内部 id 的组件都要写:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
override fun dispatchSaveInstanceState(container: SparseArray<Parcelable>) =
|
||||||
|
dispatchFreezeSelfOnly(container)
|
||||||
|
|
||||||
|
override fun dispatchRestoreInstanceState(container: SparseArray<Parcelable>) =
|
||||||
|
dispatchThawSelfOnly(container)
|
||||||
|
```
|
||||||
|
|
||||||
|
取值本来就由 ViewModel + DataBinding 持有,不需要视图级恢复,屏蔽掉没有副作用。
|
||||||
|
|
||||||
|
配套的第二道防线:多形态组件里,文本回写要限定形态,别让隐藏控件影响取值:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
et.doOnTextChanged { text, _, _, _ ->
|
||||||
|
if (type == PhoneDataLayoutType.INPUT) value = text.toString()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 遇到"值被神秘清空"怎么定位
|
||||||
|
|
||||||
|
在 setter 里打一条带堆栈的日志,一次就能看到真凶:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
android.util.Log.d("DBG", "value '$field' -> '$v'", Throwable("trace"))
|
||||||
|
```
|
||||||
|
|
||||||
|
出库交接那次的栈是 `TextView.onRestoreInstanceState → EditText.setText → doOnTextChanged`,
|
||||||
|
指向非常明确。**排完记得删日志。**
|
||||||
|
|
||||||
|
## 新增组件的写法约定
|
||||||
|
|
||||||
|
照现有 7 个组件的模式来,保持一致:
|
||||||
|
|
||||||
|
1. 继承 `LinearLayout`/`FrameLayout`,`init` 里 `inflate(context, R.layout.layout_phone_xxx, this)`
|
||||||
|
2. 内部布局用 `<merge tools:parentTag="android.widget.LinearLayout">`,避免多一层嵌套
|
||||||
|
3. 属性做成 Kotlin `var` + setter 里立即生效;双向绑定值用
|
||||||
|
`onChangeListener: InverseBindingListener?`
|
||||||
|
4. BindingAdapter 统一加到 `PhoneWidgetKtx.kt`,函数名带组件名前缀避免顶层函数重名
|
||||||
|
5. 有互斥形态时,**`type` 要先于 `value` 生效**(把 type 放进同一个多属性 adapter 的第一个
|
||||||
|
`?.let`),否则 value 会写进错误的子控件
|
||||||
|
6. 加上上面那两个 `dispatch*SelfOnly` 覆写
|
||||||
|
7. 完成后同步更新 `CLAUDE.md` 的组件表和记忆文件 `phone-5.5inch-adaptation.md`
|
||||||
|
|
||||||
|
## 资源
|
||||||
|
|
||||||
|
配色一律用 `phone_*`,背景用 `bg_phone_*`,图标用 `ic_phone_*`,禁止写死色值。
|
||||||
|
已有的(不够再加,加完更新 CLAUDE.md):
|
||||||
|
|
||||||
|
- 色:`phone_primary` `phone_page_bg` `phone_bg` `phone_stat_bg` `phone_text_title/body/hint/label/strong/weak_btn`
|
||||||
|
`phone_divider` `phone_badge_bg` `phone_green` `phone_check_border` `phone_tag_gray_*` `phone_tag_green_*`
|
||||||
|
`phone_tag_red_*` `phone_orange_bg/text`
|
||||||
|
- 背景:`bg_phone_card` `bg_phone_search` `bg_phone_input` `bg_phone_stat_box` `bg_phone_panel_top`
|
||||||
|
`bg_phone_icon_round` `bg_phone_btn_primary` `bg_phone_btn_outline` `bg_phone_btn_weak`(浅蓝弱按钮)
|
||||||
|
`bg_phone_badge` `bg_phone_tag_green/gray/red/orange` `bg_phone_card_header_blue/green`
|
||||||
|
`bg_phone_card_top_accent`(卡片顶部主色描边条,出港计重头部卡片)
|
||||||
|
- 图标:`ic_phone_airplane` `ic_phone_location` `ic_phone_person` `ic_phone_check_circle`
|
||||||
|
`ic_phone_chevron_right/down` `ic_phone_calendar` `ic_phone_close`
|
||||||
|
`ic_phone_check_round_checked/unchecked`(圆形复选框)
|
||||||
|
`ic_phone_clipboard`(剪贴板,白色 FAB 用)`ic_phone_weight`(砝码,可 tint)
|
||||||
|
`ic_phone_package`(件数)`ic_phone_tag`(特码/标签)
|
||||||
|
- 圆点:`bg_phone_dot_green/blue/gray`(状态指示点;蓝=出港查询卡片头,灰=时间线未达节点)
|
||||||
|
- 复用 Pad 的矢量图:`img_search` `img_scan` `img_filter`(可 `app:tint` 染色)
|
||||||
|
|
||||||
|
设计稿里的 MDI 图标若缺失,直接写 24×24 的 vector(用 MDI 官方 path),比找位图靠谱且能染色。
|
||||||
267
.claude/skills/phone-adapt/references/pad-safety.md
Normal file
267
.claude/skills/phone-adapt/references/pad-safety.md
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
# Pad 端零破坏 & 易崩点
|
||||||
|
|
||||||
|
平板端是在跑的生产功能,适配手机不能改变它的任何行为。以下是必须遵守的约束和踩过的坑。
|
||||||
|
|
||||||
|
## 布局变体的三条硬约束
|
||||||
|
|
||||||
|
同名布局 + 资源限定符(`layout/` 手机 / `layout-sw600dp/` 平板)会让 DataBinding 生成
|
||||||
|
**一个 Binding 基类 + 两个变体实现**,因此 Kotlin 侧零改动。代价是两个变体必须兼容:
|
||||||
|
|
||||||
|
### 1. `<variable>` 必须完全一致
|
||||||
|
|
||||||
|
手机变体需要 `activity` 变量(暴露纯 UI 方法给 XML)时,**平板变体也要补上**,否则编译报
|
||||||
|
`variable not found`。平板不用它,加个注释说明即可:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<!-- 平板端不使用,仅为与手机变体保持变量一致 -->
|
||||||
|
<variable name="activity" type="com.lukouguoji.gjc.activity.XxxActivity" />
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 共用 id 双方都要保留
|
||||||
|
|
||||||
|
Activity / ViewHolder 引用到的 id(`srl`、`rv`、`iv_icon`、`checkIcon`…)两个变体都要有。
|
||||||
|
可以换位置换样式,但 id 得在。
|
||||||
|
|
||||||
|
### 3. 单侧独有的 id 会变 `@Nullable`
|
||||||
|
|
||||||
|
只在手机变体存在的 id(如「查看详情」的 `ll_detail`),Binding 基类里是可空字段,
|
||||||
|
Kotlin 侧必须判空:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
// 平板变体没有这个控件,为 null 时直接跳过
|
||||||
|
binding.llDetail?.setOnClickListener { XxxDetailActivity.start(itemView.context, bean) }
|
||||||
|
```
|
||||||
|
|
||||||
|
编译器会强制你处理,不用担心漏掉。改完可以核对生成代码确认:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -B3 "llDetail" module_gjc/build/generated/data_binding_base_class_source_out/debug/out/\
|
||||||
|
com/lukouguoji/gjc/databinding/ItemXxxBinding.java
|
||||||
|
```
|
||||||
|
|
||||||
|
### ⛔ 绝对不要用「不同文件名 + 代码判断」切布局
|
||||||
|
|
||||||
|
`activity_xxx_phone.xml` 会生成 `ActivityXxxPhoneBinding`,而字段声明的类型是
|
||||||
|
`ActivityXxxBinding`。泛型擦除让**编译期查不出来**,一进页面就 `ClassCastException`。
|
||||||
|
|
||||||
|
### 弹框(BaseDialogModel)也要双变体,最容易漏
|
||||||
|
|
||||||
|
页面布局适配完,长按/批量操作弹出的 DialogModel 仍会以 Pad 居中样式出现在手机上
|
||||||
|
(出港运抵的「状态重置」就漏过)。做法与页面完全同构:
|
||||||
|
|
||||||
|
1. dialog 布局 `git mv` 到 `layout-sw600dp/`,`layout/` 下写同名手机版(设计稿通常是底部弹层:
|
||||||
|
`bg_phone_panel_top` + 居中标题 + `ic_phone_close` + 全宽 `bg_phone_btn_primary` 确定键)
|
||||||
|
2. 弹出位置在构造参数按形态切换(XPopup 位置与布局是两回事,都要改):
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
class XxxDialogModel(...) : BaseDialogModel<DialogXxxBinding>(
|
||||||
|
if (DeviceUtil.isPhone()) DIALOG_TYPE_BOTTOM else DIALOG_TYPE_CENTER
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
3. 两变体 `<variable>` 一致(imports 不要求一致)
|
||||||
|
|
||||||
|
参考:`IntExpArriveResetDialogModel` + `dialog_int_exp_arrive_reset.xml` 双变体。
|
||||||
|
**适配收尾时逐个 grep 该页 ViewModel 里 `DialogModel(` 的调用点**,每个弹框都过一遍。
|
||||||
|
|
||||||
|
## 业务层零破坏的三个模式
|
||||||
|
|
||||||
|
### 新增查询维度:默认空值 + 仅非空进请求
|
||||||
|
|
||||||
|
平板布局没有对应控件 → 字段恒为空 → 不进请求体 → 平板查询与改造前逐字节一致。
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
val handoverState = MutableLiveData("") // 手机 Tab 绑这个,平板无控件
|
||||||
|
val hoId = MutableLiveData("")
|
||||||
|
|
||||||
|
val filterParams = mapOf(
|
||||||
|
"fdate" to flightDate.value?.ifEmpty { null },
|
||||||
|
/* 原有字段… */
|
||||||
|
"hoState" to handoverState.value?.ifEmpty { null }, // 空 → null → 不影响平板
|
||||||
|
"hoId" to hoId.value?.ifEmpty { null },
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 手机专属的额外请求:ViewModel 内部开关
|
||||||
|
|
||||||
|
Tab 角标计数、新增下拉字典这类请求,平板不需要,多发就是改变了平板行为(请求次数)。
|
||||||
|
用一个内部布尔控制,由 Activity 在手机形态下开启:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
// ViewModel
|
||||||
|
private var phoneExtrasEnabled = false
|
||||||
|
|
||||||
|
fun initPhoneExtras() {
|
||||||
|
phoneExtrasEnabled = true
|
||||||
|
handoverState.value = "0" // 手机默认停在第一个 Tab
|
||||||
|
DictUtils.getWHSUserList(addAll = false) { hoUserList.postValue(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getData() {
|
||||||
|
/* 原有列表 + 统计请求… */
|
||||||
|
if (phoneExtrasEnabled) loadTabCounts(filterParams) // 平板不触发
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
// Activity
|
||||||
|
if (DeviceUtil.isPhone()) viewModel.initPhoneExtras()
|
||||||
|
```
|
||||||
|
|
||||||
|
`DeviceUtil.isPhone()` 只用来决定**数据默认值和额外请求**,**永远不用来选布局**。
|
||||||
|
|
||||||
|
### 纯 UI 状态放 Activity
|
||||||
|
|
||||||
|
弹层显隐、Tab 高亮这类与业务无关的状态,用 `ObservableBoolean` 放在 Activity 上暴露给 XML,
|
||||||
|
不要污染 ViewModel:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
val filterPanelVisible = ObservableBoolean(false)
|
||||||
|
fun toggleFilterPanel() = filterPanelVisible.set(!filterPanelVisible.get())
|
||||||
|
```
|
||||||
|
|
||||||
|
### 同名 id 在两个变体里必须是同一种控件
|
||||||
|
|
||||||
|
平板变体的 `btnMove` 是 `TextView`,手机版底部换成了 `PhoneBottomBar`——**不要为了复用
|
||||||
|
Activity 里的 `binding.btnMove` 而把这个 id 安到 PhoneBottomBar 上**。同名不同类型会让
|
||||||
|
DataBinding 把字段类型退化成公共父类,编译期未必报错,运行时行为难料。
|
||||||
|
|
||||||
|
正确做法:手机端的按钮点击走组件自身的 `setOnActionClick`,`btnMove` 就只留在平板变体里,
|
||||||
|
Activity 侧判空调用:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
binding.btnMove?.setOnClickListener { showMoveConfirmDialog() }
|
||||||
|
```
|
||||||
|
|
||||||
|
被 XML 调用的 Activity 方法记得改成 public。
|
||||||
|
|
||||||
|
### 调字典要对齐既有页面的参数口径
|
||||||
|
|
||||||
|
`DictUtils` 的方法参数常有"看起来合理但后端不认"的取值。出港移库的特码下拉一开始传
|
||||||
|
`ieFlag="E"`(出港),接口返回空数组;而同模块既有页面(`GjcWeighingStartViewModel` 等)
|
||||||
|
一律传 `ieFlag=""`,能正常返回。
|
||||||
|
|
||||||
|
所以调字典前先 grep 一下同模块其他页面怎么调的,照抄它们的参数;改完必须在实机上
|
||||||
|
**把下拉点开确认真的有数据**,空列表在 UI 上看不出报错。
|
||||||
|
|
||||||
|
### 共享方法别为手机改语义
|
||||||
|
|
||||||
|
`checkAllClick()` 这类平板也在用的方法,不要为了手机端的语义去改它。
|
||||||
|
例:手机「待交接」Tab 下理论上只有未交接记录(服务端按状态过滤),所以全选照原样全量勾选就是对的;
|
||||||
|
若为此加上「跳过已交接」的过滤,反而改变了平板端(平板列表混排两种状态)的行为。
|
||||||
|
|
||||||
|
## 屏幕方向:Manifest 一律写 `unspecified`
|
||||||
|
|
||||||
|
新增 Activity 注册时:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<activity android:name="…"
|
||||||
|
android:configChanges="orientation|keyboardHidden"
|
||||||
|
android:exported="false"
|
||||||
|
android:screenOrientation="unspecified" />
|
||||||
|
```
|
||||||
|
|
||||||
|
**两种错误方案都实测踩过,别再试:**
|
||||||
|
- 写死 `userLandscape` → 手机「先横屏、约 1 秒后转竖屏」(方向在建窗口时就定了,
|
||||||
|
`BaseActivity` 在 `super.onCreate` 之前纠正也来不及)
|
||||||
|
- 用 `@integer/screen_orientation` 资源引用(曾经以为是优雅方案)→ **更糟**:系统解析
|
||||||
|
Manifest 属性不套用设备限定符,所有 Activity 实际都拿到 `values/` 默认值(竖屏),
|
||||||
|
平板因此先竖后横,且 AutoSize 在竖屏配置下选中平板竖屏 720dp 基准
|
||||||
|
(正常应为 1152×720 横屏基准),交互几次后整个 UI 放大约 1.6 倍
|
||||||
|
|
||||||
|
`unspecified` 让系统按设备当前物理方向建窗口(平板横屏摆放→横屏起,手机→竖屏起,
|
||||||
|
两端起始方向本就正确),`BaseActivity.applyDeviceOrientation()` 再按形态锁定,
|
||||||
|
不产生二次纠正。全项目 192 处已统一为 `unspecified`。
|
||||||
|
|
||||||
|
## 改 module_base 公共代码时
|
||||||
|
|
||||||
|
`module_base` 被所有业务模块依赖,改动会影响全部页面。原则:
|
||||||
|
|
||||||
|
- **只做增量**:加新组件、新颜色、新 drawable,别改既有组件的行为
|
||||||
|
- 确实要改公共基类(`BaseActivity` / `BaseBindingActivity` / Pad 系组件)时,
|
||||||
|
**必须在平板上回归**至少 2~3 个不同类型的既有页面
|
||||||
|
- Bean 上加只读计算属性是安全的(Gson 只序列化字段,不动 getter);
|
||||||
|
加**字段**要谨慎,会进请求体
|
||||||
|
|
||||||
|
## RecyclerView 里不要用 item 级 visibility 做 Tab/分类过滤
|
||||||
|
|
||||||
|
普通 ViewGroup(LinearLayout 等)里 `View.GONE` 的子 View 会自动塌陷为 0 高度、不占布局空间——
|
||||||
|
但 **RecyclerView + LinearLayoutManager 不是这样**:它按子项的测量高度参与滚动区域计算,
|
||||||
|
不会因为子项是 GONE 就跳过。给 item 根节点加 `visibility="@{tab条件 ? VISIBLE : GONE}"`
|
||||||
|
切 Tab,会在列表里留下一段空白(隐藏项的高度仍被保留),角标数字和实际卡片数量对不上。
|
||||||
|
|
||||||
|
出港运抵的「待运抵/已运抵」Tab 就踩了这个坑(实机截图验证:切到「已运抵」后顶部有一大块
|
||||||
|
空白,隐藏的待运抵卡片高度并未塌陷)。正确做法是在数据层过滤,而不是视图层:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
// ViewModel:自己维护完整列表,不依赖 adapter.items 的历史状态
|
||||||
|
// (见下一节:adapter.items 在 loadMore 场景可能已经是上次过滤后的子集,不能当作真源)
|
||||||
|
private var allLoadedList: List<GjcMaWb> = emptyList()
|
||||||
|
|
||||||
|
override fun getData() {
|
||||||
|
launchLoadingCollect({ ... }) {
|
||||||
|
onSuccess = { result ->
|
||||||
|
val newPageItems = result.list ?: emptyList()
|
||||||
|
allLoadedList = if (pageModel.page <= 1) newPageItems else allLoadedList + newPageItems
|
||||||
|
|
||||||
|
pageModel.handleListBean(result) {
|
||||||
|
// 无论 handleListBean 内部把 adapter.items 搞成什么样,这里用 allLoadedList
|
||||||
|
// 强制覆盖为「当前 Tab 的正确子集」,兜底纠正
|
||||||
|
val filtered = allLoadedList.filter { it.isPending == (currentTab.value == "pending") }
|
||||||
|
pageModel.rv?.commonAdapter()?.refresh(filtered)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onTabChangedPhone() {
|
||||||
|
val filtered = allLoadedList.filter { it.isPending == (currentTab.value == "pending") }
|
||||||
|
pageModel.rv?.commonAdapter()?.refresh(filtered) // 只是 items.clear()+addAll()+notifyDataSetChanged,无副作用
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`CommonAdapter.refresh()` 只是替换内部列表并 `notifyDataSetChanged()`,不影响
|
||||||
|
SmartRefreshLayout 的分页/完成状态,可以放心在 `handleListBean` 回调里再调用一次。
|
||||||
|
|
||||||
|
## Intent 传递 Serializable Bean:`@Transient` 字段反序列化后是 null
|
||||||
|
|
||||||
|
`GjcMaWb`/`GjcHaWb` 的 `checked`/`showMore`/`actionMenuVisible` 三个 UI 状态字段都标了
|
||||||
|
`@Transient`(本意是避免 Gson 把 `ObservableBoolean` 的内部结构序列化进网络请求体)。
|
||||||
|
但 Kotlin 的 `@Transient` 注解生成的就是 JVM 的 `transient` 修饰符,这个修饰符对 **Java
|
||||||
|
对象序列化**(`Intent.putExtra(String, Serializable)` 走的正是这条路径)有实际含义:
|
||||||
|
反序列化时会跳过 `transient` 字段的恢复,对象引用类型的字段结果就是 **null**。
|
||||||
|
|
||||||
|
新增手机专属页面时,如果要把 `List<GjcHaWb>` 通过 `ArrayList<GjcHaWb>` 塞进 `Intent`
|
||||||
|
传给下一个页面,接收方拿到的对象「看起来」字段都对(wbNo、pc、weight 这些正常字段没问题,
|
||||||
|
因为它们不是 `@Transient`),但只要调用 `bean.checked.set(...)` 就会立刻崩溃:
|
||||||
|
|
||||||
|
```
|
||||||
|
NullPointerException: Attempt to invoke virtual method
|
||||||
|
'void androidx.databinding.ObservableBoolean.set(boolean)' on a null object reference
|
||||||
|
```
|
||||||
|
|
||||||
|
出港运抵的「分单明细」页第一版全选按钮就是这样崩的。**修复只需一行**,在接收方
|
||||||
|
`initOnCreated` 里对拿到的列表整体 `.copy()` 一遍——`.copy()` 会重新触发一次真正的对象构造,
|
||||||
|
类体里 `val checked = ObservableBoolean(false)` 这类初始化逻辑跟着重新跑一遍,
|
||||||
|
把 null 补成全新实例:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
fun initOnCreated(intent: Intent) {
|
||||||
|
val list = intent.getSerializableExtra(Constant.Key.DATA) as? ArrayList<GjcHaWb>
|
||||||
|
// .copy() 补上被 Java 序列化跳过的 @Transient 字段
|
||||||
|
fullList = (list ?: emptyList()).map { it.copy() }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
这个坑只在「Intent 传递 Serializable Bean + 接收方要切换 checked/showMore 等状态」时才会
|
||||||
|
触发;纯只读展示(如回执页)不调用这些字段的 setter,不会崩,但补一道 `.copy()` 无害,
|
||||||
|
建议只要通过 Intent 传了 haWbList/maWbList 就统一加上,别等下次踩到才想起来。
|
||||||
|
|
||||||
|
## 已知的既有问题(不是你改坏的)
|
||||||
|
|
||||||
|
用 `am start` 直启页面时,若**先经过首页**再启目标页,会崩在
|
||||||
|
`LoadingModel.showLoading` → XPopup `popupInfo is null`。在**未改动**的页面上同样复现,
|
||||||
|
属于既有缺陷。**冷启动直启不受影响**(`force-stop` 后直接 `am start`)。
|
||||||
|
|
||||||
|
遇到崩溃先做这个对照实验再下结论:拿一个你没碰过的页面用同样方式打开,看是否同样崩。
|
||||||
80
.claude/skills/phone-adapt/references/proxyman.md
Normal file
80
.claude/skills/phone-adapt/references/proxyman.md
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
# Proxyman MCP:抓包 / 直调 / Mock(阶段 2、5、6 的调试利器)
|
||||||
|
|
||||||
|
Proxyman 桌面端 + `mcp__proxyman__*` 工具(会话内直接可用,缺 schema 时用 ToolSearch
|
||||||
|
`select:mcp__proxyman__get_flows,...` 加载)。**2026-07-31 已在出港查询页全链路实测**:
|
||||||
|
抓包核对请求体、Map Local mock 三种卡片形态(含真实数据不存在的「未入库」兜底态)一次跑通。
|
||||||
|
|
||||||
|
## 与 api-doc 的分工(先契约后事实)
|
||||||
|
|
||||||
|
| | api-doc MCP | Proxyman MCP |
|
||||||
|
|---|---|---|
|
||||||
|
| 回答什么 | **契约**:接口该有什么入参/出参、参数名叫什么 | **事实**:App 实际发了什么、后端实际回了什么 |
|
||||||
|
| 用在何时 | 阶段 2 开工前逐接口核对 | 阶段 5/6 实机验证与 corner case 补测 |
|
||||||
|
|
||||||
|
标准配合流程:
|
||||||
|
api-doc 拿权威参数名 → 前端实现 → Proxyman flow 核对请求体确实带上了 →
|
||||||
|
compose 改参 A/B 验证后端认不认 → 不认 → 记问题清单(附 `export_flow_curl` 证据)→
|
||||||
|
map local 造 mock 补 UI corner case 验证。
|
||||||
|
|
||||||
|
## 接入(一次性,实测步骤)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1) 确认 Proxyman 在跑(返回 Recording: Active + 端口,默认 9090)
|
||||||
|
# mcp__proxyman__get_proxy_status
|
||||||
|
# 2) 模拟器全局代理指向宿主机(模拟器视角宿主机 = 10.0.2.2)
|
||||||
|
adb -s <serial> shell settings put global http_proxy 10.0.2.2:9090
|
||||||
|
# 3) 验证完【必须】清掉,否则 Proxyman 一关模拟器就断网,下次验证莫名全挂
|
||||||
|
adb -s <serial> shell settings put global http_proxy :0
|
||||||
|
```
|
||||||
|
|
||||||
|
本项目内网服务是**纯 HTTP**(192.168.1.250:8093)→ 不需要装证书,明文直接可见。
|
||||||
|
(若未来切 HTTPS,才需要 `install_certificate` + `enable_ssl_proxying`。)
|
||||||
|
|
||||||
|
## 场景 1:核对请求/响应(替代 `ui_probe req`)
|
||||||
|
|
||||||
|
logcat 抓 OkHttp 多行 pretty JSON 脆弱且要人肉拼接;Proxyman 一步到位:
|
||||||
|
|
||||||
|
- `filter_flows`(key=url, value="IntExpSearch")→ 拿 flow ID 列表
|
||||||
|
- `get_flow_detail`(flow_id)→ 完整请求体 + 响应体 + headers(Authorization 自动脱敏)
|
||||||
|
|
||||||
|
**出参无文档定义时(如 `IntExpSearch/detail` 返回裸 Map),用真实 flow 的 responseBody
|
||||||
|
直接盘点字段清单**——判定「锁定状态/计费重量是否存在」这类问题的最快路径。
|
||||||
|
|
||||||
|
## 场景 2:直调后端 A/B 验证(替代 run-as 提 token + 手写 curl)
|
||||||
|
|
||||||
|
`create_compose_http_from_flow`(从真实 flow 复制请求,**token 自动带上,不用碰
|
||||||
|
shared_prefs**)→ `update_compose_http` 改一个参数 → `send_compose_http` 看结果对比。
|
||||||
|
isFclose 这类「参数是否生效」的 A/B 实验用这条链。给后端提缺口时用
|
||||||
|
`export_flow_curl` 导出可复现的 curl 附进问题清单。
|
||||||
|
|
||||||
|
## 场景 3:Map Local 造 mock 验证 corner case(替代代码注入样例 Bean)
|
||||||
|
|
||||||
|
老流程「Activity 临时注入 Bean → 截图 → 删码 → 重构建」彻底淘汰:**零代码改动、零重构建**。
|
||||||
|
|
||||||
|
- `create_map_local`:url 精确到接口路径,method=POST,response_body 直接写目标 JSON
|
||||||
|
(构造空字段/超长文本/罕见状态,比如出港查询的 fclose+opDate 双空「未入库」兜底态)
|
||||||
|
- 改真实响应个别字段更省事时用 `create_map_local_from_flow`
|
||||||
|
- 验证完 `delete_rule`(rule_type=maplocal)+ 清代理,**规则残留会污染后续真实数据验证**
|
||||||
|
|
||||||
|
响应结构照抄真实 flow 的顶层结构(如 pageQuery 是裸 PageInfo:`{total, list, pages, ...}`,
|
||||||
|
不要包 `{status, data}`)。
|
||||||
|
|
||||||
|
⚠️ 实测坑(2026-07-31 出港仓库):mock `BaseResultBean` 包装的接口(pageQueryTotal/detail 等)时,
|
||||||
|
**`status` 必须写 `"1"`**——`BaseResultBean.verifySuccess()` 判 `status == "1"`,写 "200" 会被当失败
|
||||||
|
静默丢弃(UI 保持默认值,无任何报错,排查靠 flow 已命中但 UI 不变这一矛盾现象)。
|
||||||
|
|
||||||
|
⚠️ 实测坑:mock 响应到达后 UI 渲染可能滞后(冷启动首帧 Davey 卡顿 2s+),
|
||||||
|
**截图断言前先 `ui_probe texts` 确认数据已上屏**——这次就因截图太早误判过一轮「mock 没生效」,
|
||||||
|
其实 `get_flow_detail` 里 `matchedTools: ["Map Local"]` 早已证明规则命中,UI 只是还没画完。
|
||||||
|
|
||||||
|
## 场景 4:环境模拟(按需)
|
||||||
|
|
||||||
|
- `create_network_condition`:弱网/高延迟,验证 loading 弹窗与超时提示
|
||||||
|
- `create_breakpoint`:单次拦截改包(比 map local 更临时的一次性实验)
|
||||||
|
- `create_map_remote`:把请求转发到另一环境(如后端修复验证用的测试实例)
|
||||||
|
|
||||||
|
## 验证收尾清单
|
||||||
|
|
||||||
|
- [ ] `list_rules` 确认无本次遗留规则(maplocal/breakpoint/network_condition)
|
||||||
|
- [ ] 模拟器代理已清(`settings get global http_proxy` 应为 `:0` 或空)
|
||||||
|
- [ ] 用真实数据再过一遍被 mock 过的页面,确认无假数据残影
|
||||||
181
.claude/skills/phone-adapt/references/verification.md
Normal file
181
.claude/skills/phone-adapt/references/verification.md
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
# 端到端验证手册
|
||||||
|
|
||||||
|
目标:在**真实接口**下把手机端走通,并确认平板端没退化。只看编译通过是不够的——
|
||||||
|
本次适配里"筛选条件被静默清空"和"后端不认新参数"两个问题,都只有跑真机才暴露。
|
||||||
|
|
||||||
|
## 环境
|
||||||
|
|
||||||
|
```bash
|
||||||
|
~/Library/Android/sdk/emulator/emulator -list-avds # Medium_Phone_API_36.1(手机) / Aerologic_Tablet(平板)
|
||||||
|
adb devices -l
|
||||||
|
adb -s <serial> shell wm size && adb -s <serial> shell wm density
|
||||||
|
```
|
||||||
|
|
||||||
|
判定形态:手机 1080×2400@420dpi → `PHONE(sw=411dp)`;平板 1280×800@160dpi → `TABLET(sw=800dp)`。
|
||||||
|
|
||||||
|
`ui_probe.sh` 封装了常用操作,比手写 adb 省事且更可靠:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
P=.claude/skills/phone-adapt/scripts/ui_probe.sh
|
||||||
|
$P <serial> form # 打印形态识别结果
|
||||||
|
$P <serial> texts # 当前界面所有可见文字(做断言用)
|
||||||
|
$P <serial> bounds "已交接" # 元素 bounds + 中心点
|
||||||
|
$P <serial> tap-text "确认" # 按文字点击(自动取中心点)
|
||||||
|
$P <serial> wait-text "待交接" # 等页面就绪
|
||||||
|
$P <serial> wait-gone "请稍候……" # 等加载弹窗消失
|
||||||
|
$P <serial> shot /tmp/a.png # 截图
|
||||||
|
$P <serial> req pageQuery # 抓请求/响应体
|
||||||
|
$P <serial> crash # 崩溃次数 + 栈
|
||||||
|
```
|
||||||
|
|
||||||
|
## 构建安装
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew assembleDebug 2>&1 | grep -E "^(BUILD|FAILURE)|error:"
|
||||||
|
adb -s <serial> install -r -d app/build/outputs/apk/debug/app-debug.apk
|
||||||
|
```
|
||||||
|
|
||||||
|
注意 gradle 输出里大量 `e: 注: ARouter::Compiler …` 是注解处理器的**提示**被误标成 `e:`,
|
||||||
|
不是错误;只看 `BUILD SUCCESSFUL` / `error:` 就行。
|
||||||
|
|
||||||
|
## 进入目标页面的两条路
|
||||||
|
|
||||||
|
### 正规路径(优先):登录 → 首页菜单
|
||||||
|
|
||||||
|
```bash
|
||||||
|
adb -s <serial> shell monkey -p com.lukouguoji.aerologic -c android.intent.category.LAUNCHER 1
|
||||||
|
```
|
||||||
|
|
||||||
|
测试环境账号在记忆文件 `test-env-login.md`(ADMIN / 用户已授权保存),可自主登录。
|
||||||
|
填表用 `input text`,**`#` 不需要转义**——新版 adb 的 input text 参数不经远端 shell 解析,
|
||||||
|
写 `\#` 反而会把 `\` 也输进去(实测多出一位)。
|
||||||
|
|
||||||
|
⚠️ **「记住密码」回填哈希坑(实测踩过)**:输入用户名后 App 会调 `queryUserByName`
|
||||||
|
把本地存储的 **bcrypt 哈希**回填进密码框,盖掉/混入你输入的明文 → 登录 200 但校验失败、
|
||||||
|
静默停在登录页(密码框点数对不上是判断信号:明文 9 位 vs 回填后 10 位显示)。
|
||||||
|
正确顺序:点密码框 → 等回填(sleep 1)→ `input keycombination 113 29`(CTRL+A)+
|
||||||
|
`KEYCODE_DEL` 清空 → 再输明文 → `KEYCODE_BACK` 收键盘 → 点登录。
|
||||||
|
键盘不收起时「登录」按钮可能点不到(tap 被吞),收起后再点。
|
||||||
|
|
||||||
|
底部有「首页 / 国内 / 国际 / 我的」Tab,国际业务页找对应入口
|
||||||
|
(底部 Tab 的「国际」与顶部筛选的「国际」同名,`tap-text "国际" 2` 指定第 2 处)。
|
||||||
|
|
||||||
|
**首页菜单是按权限过滤的**:当前账号角色没有该权限时,入口根本不显示(本次 ADMIN 登录后
|
||||||
|
国际业务只有「板箱过磅」「进港理货」,没有「出库交接」)。这时走下面的直启。
|
||||||
|
|
||||||
|
### 直启(权限缺失时的替代):冷启动 + am start
|
||||||
|
|
||||||
|
`app/src/debug/AndroidManifest.xml` 里把调试页临时 `exported="true"`,就能直接拉起。
|
||||||
|
**必须冷启动**(先 force-stop),否则会撞上既有的 LoadingModel 崩溃:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
adb -s <serial> shell am force-stop com.lukouguoji.aerologic
|
||||||
|
sleep 2
|
||||||
|
adb -s <serial> shell am start -n com.lukouguoji.aerologic/<完整类名>
|
||||||
|
```
|
||||||
|
|
||||||
|
登录态存在 SharedPreference 里,冷启动直启同样带 token,接口能正常返回真实数据。
|
||||||
|
|
||||||
|
> 先经首页再 `am start` 会崩在 `LoadingModel.showLoading` → XPopup `popupInfo is null`,
|
||||||
|
> 这是既有缺陷(未改动的页面也复现),不是本次改动引入的。
|
||||||
|
|
||||||
|
## 点击前先等就绪
|
||||||
|
|
||||||
|
加载弹窗("请稍候……")会盖住整屏并**吞掉 `input tap`**,表现为"点了没反应"。
|
||||||
|
本次验证就因此白跑了几轮。所以:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$P <serial> wait-text "待交接" # 等目标元素出现
|
||||||
|
$P <serial> tap-text "已交接"
|
||||||
|
$P <serial> texts | grep -c "全选" # 用文字变化确认点击确实生效
|
||||||
|
```
|
||||||
|
|
||||||
|
点完**一定要断言效果**(用 `texts` 或截图),别假设点中了。
|
||||||
|
|
||||||
|
## 逐项走查清单
|
||||||
|
|
||||||
|
每一步做完都跑一次 `crash`(必须为 0):
|
||||||
|
|
||||||
|
- [ ] 列表加载:卡片字段、各种状态形态(如待处理 / 已完成两种卡片)
|
||||||
|
- [ ] Tab 切换:指示条位置、角标数字、底部条按设计显隐
|
||||||
|
- [ ] 筛选弹层:打开、各控件取值、重置、确认后重新查询
|
||||||
|
- [ ] 下拉字典:真实取到数据(不是空列表)
|
||||||
|
- [ ] 多选:单选、全选联动、"已选 N 项"计数
|
||||||
|
- [ ] 详情页/二级页:字段绑定、条件显示的区块
|
||||||
|
- [ ] 扫码入口能拉起
|
||||||
|
|
||||||
|
## 核对请求参数是否真的生效
|
||||||
|
|
||||||
|
新增的查询字段要确认两件事:客户端**发出去了**,服务端**认**。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$P <serial> req pageQuery
|
||||||
|
```
|
||||||
|
|
||||||
|
OkHttp 日志是多行 pretty JSON。看到请求体里有你的字段(如 `"handoverState": "0"`)只说明客户端对了。
|
||||||
|
**服务端是否生效要用行为验证**:切到另一个 Tab,看返回数据是否真的变了。
|
||||||
|
|
||||||
|
⚠️ 行为验证失败时**先怀疑参数名,再怀疑后端**:出库交接第一版传 `hoState`,两个 Tab 返回同一批数据,
|
||||||
|
一度误判为「后端没做过滤」;实际是参数名错了(api-doc 里是 `handoverState`),后端对不认识的参数
|
||||||
|
**静默忽略**。正确顺序:查 `references/api-doc.md` 核对参数名 → 用 token 直调后端做 A/B 对比
|
||||||
|
(同条件只改一个参数看 total 变化)→ 仍不生效才定性为后端缺陷并记入
|
||||||
|
`documents/后端接口对接问题清单.xlsx`。
|
||||||
|
|
||||||
|
## 无数据时怎么核对 UI
|
||||||
|
|
||||||
|
服务端当天可能没数据(列表空)。放宽条件(清空日期)再查;仍为空时,临时注入样例 Bean:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
// 临时:覆盖各种形态各一条,验证后删除
|
||||||
|
binding.rv.postDelayed({
|
||||||
|
binding.rv.commonAdapter()?.refresh(listOf(/* 待处理 / 危险品 / 已完成 各一条 */))
|
||||||
|
}, 2500)
|
||||||
|
```
|
||||||
|
|
||||||
|
截图核对完**必须删除**,然后重新构建 + grep 确认无残留:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -rn "injectMockForVisualCheck\|TODO 临时" module_base/src module_gjc/src | wc -l # 应为 0
|
||||||
|
```
|
||||||
|
|
||||||
|
## 屏幕方向验证
|
||||||
|
|
||||||
|
新增/修改 Activity 后,确认手机端不会「先横屏再转竖屏」:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 冷启动时连续采样:应全程 mRotation=0
|
||||||
|
adb -s <phone> shell am force-stop com.lukouguoji.aerologic; sleep 2
|
||||||
|
adb -s <phone> shell monkey -p com.lukouguoji.aerologic -c android.intent.category.LAUNCHER 1
|
||||||
|
for i in $(seq 1 10); do adb -s <phone> shell dumpsys window | grep -m1 -oE "mRotation=[0-9]+"; sleep 0.4; done
|
||||||
|
```
|
||||||
|
|
||||||
|
平板则应首屏就是横屏(截图宽 > 高)。若手机出现横屏帧,检查该 Activity 的 Manifest
|
||||||
|
是否写成了别的值——**必须是 `android:screenOrientation="unspecified"`**(写死 `userLandscape`
|
||||||
|
或用 `@integer/...` 资源引用都会出问题,详见 SKILL.md 阶段 4)。
|
||||||
|
|
||||||
|
## Pad 端回归(必做)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
adb -s <tablet> install -r -d app/build/outputs/apk/debug/app-debug.apk
|
||||||
|
adb -s <tablet> shell am start -n com.lukouguoji.aerologic/<同一个类名>
|
||||||
|
$P <tablet> shot /tmp/tablet.png
|
||||||
|
$P <tablet> form # 应为 TABLET(sw=800dp…)
|
||||||
|
```
|
||||||
|
|
||||||
|
对比改造前后:搜索条数量与顺序、日期默认值、按钮(平板可能比手机多按钮)、底部统计文案。
|
||||||
|
改过 `module_base` 里的公共基类或 Pad 系组件时,这一步不能省,且要多看几个页面。
|
||||||
|
|
||||||
|
## 定位"值被神秘修改"类问题
|
||||||
|
|
||||||
|
在 setter 里打带堆栈的日志,一次就能看到调用来源:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
android.util.Log.d("DBG", "value '$field' -> '$v'", Throwable("trace"))
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
adb -s <serial> logcat -d -s DBG | grep -A14 "'旧值' -> ''" | grep "at com.lukouguoji\|at android"
|
||||||
|
```
|
||||||
|
|
||||||
|
本次靠这招定位到 `TextView.onRestoreInstanceState → EditText.setText → doOnTextChanged`,
|
||||||
|
即复合自定义 View 的 id 串档(见 `components.md`)。**排完删日志。**
|
||||||
137
.claude/skills/phone-adapt/scripts/design_shots.py
Executable file
137
.claude/skills/phone-adapt/scripts/design_shots.py
Executable file
@@ -0,0 +1,137 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
把 5.5 寸手持端设计稿(HTML 原型)渲染成截图,供逐像素比对。
|
||||||
|
|
||||||
|
设计稿是带 Tailwind + JS 的交互原型:列表页、Tab、详情页、筛选弹层往往挤在同一个
|
||||||
|
HTML 里,靠 JS 函数切换。只读源码容易漏掉视觉细节(间距、圆角、真实配色、
|
||||||
|
以及 JS 里 id 映射写错导致的字段错位),所以务必渲染成图来看。
|
||||||
|
|
||||||
|
用法:
|
||||||
|
# 1) 先列出 HTML 里可用的状态切换函数与元素 id,据此决定要截哪些状态
|
||||||
|
python3 design_shots.py --html 出库交接.html --list
|
||||||
|
|
||||||
|
# 2) 渲染:默认状态 + 注入 JS 触发的各个状态
|
||||||
|
python3 design_shots.py --html 出库交接.html --out /tmp/shots \
|
||||||
|
--state "01_列表:" \
|
||||||
|
--state "02_已交接Tab:switchTab('shipped');" \
|
||||||
|
--state "03_详情:showDetail({id:'PMC1',status:'已交接'});" \
|
||||||
|
--state "04_筛选弹层:toggleFilterDrawer(true);"
|
||||||
|
|
||||||
|
每个 --state 形如 "名称:JS",JS 可为空表示页面初始态。
|
||||||
|
输出 <out>/<名称>.png,同时保留注入后的 <名称>.html 便于复查。
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import urllib.parse
|
||||||
|
|
||||||
|
CHROME_CANDIDATES = [
|
||||||
|
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
||||||
|
"/Applications/Chromium.app/Contents/MacOS/Chromium",
|
||||||
|
shutil.which("google-chrome") or "",
|
||||||
|
shutil.which("chromium") or "",
|
||||||
|
shutil.which("chromium-browser") or "",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def find_chrome() -> str:
|
||||||
|
for path in CHROME_CANDIDATES:
|
||||||
|
if path and os.path.exists(path):
|
||||||
|
return path
|
||||||
|
sys.exit(
|
||||||
|
"找不到 Chrome/Chromium。请安装,或用 --chrome 指定可执行文件路径。"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def list_hooks(html: str) -> None:
|
||||||
|
"""列出可用于构造状态的 JS 函数和元素 id。"""
|
||||||
|
funcs = sorted(set(re.findall(r"function\s+([A-Za-z_$][\w$]*)\s*\(", html)))
|
||||||
|
onclicks = sorted(set(re.findall(r'onclick="([^"]+)"', html)))
|
||||||
|
ids = sorted(set(re.findall(r'id="([^"]+)"', html)))
|
||||||
|
|
||||||
|
print("== JS 函数(可直接注入调用)==")
|
||||||
|
for f in funcs:
|
||||||
|
print(f" {f}()")
|
||||||
|
print("\n== onclick 表达式(含真实参数,照抄最省事)==")
|
||||||
|
for o in onclicks[:40]:
|
||||||
|
print(f" {o}")
|
||||||
|
if len(onclicks) > 40:
|
||||||
|
print(f" ... 其余 {len(onclicks) - 40} 条略")
|
||||||
|
print("\n== 元素 id(判断有哪些页面/弹层)==")
|
||||||
|
print(" " + ", ".join(ids))
|
||||||
|
|
||||||
|
|
||||||
|
def render(chrome: str, html: str, name: str, js: str, out_dir: str,
|
||||||
|
width: int, height: int, scale: float, budget: int) -> str:
|
||||||
|
# 等 load 之后再触发,确保 CDN 的 Tailwind/Iconify 已生效
|
||||||
|
inject = (
|
||||||
|
"<script>window.addEventListener('load',function(){"
|
||||||
|
f"setTimeout(function(){{{js}}},300);}});</script>"
|
||||||
|
)
|
||||||
|
page_path = os.path.join(out_dir, f"{name}.html")
|
||||||
|
with open(page_path, "w", encoding="utf-8") as fp:
|
||||||
|
fp.write(html.replace("</body>", inject + "</body>"))
|
||||||
|
|
||||||
|
png_path = os.path.join(out_dir, f"{name}.png")
|
||||||
|
subprocess.run(
|
||||||
|
[
|
||||||
|
chrome,
|
||||||
|
"--headless=new",
|
||||||
|
"--disable-gpu",
|
||||||
|
"--hide-scrollbars",
|
||||||
|
f"--force-device-scale-factor={scale}",
|
||||||
|
f"--window-size={width},{height}",
|
||||||
|
f"--virtual-time-budget={budget}",
|
||||||
|
f"--screenshot={png_path}",
|
||||||
|
"file://" + urllib.parse.quote(os.path.abspath(page_path)),
|
||||||
|
],
|
||||||
|
capture_output=True,
|
||||||
|
)
|
||||||
|
return png_path
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
ap = argparse.ArgumentParser()
|
||||||
|
ap.add_argument("--html", required=True, help="设计稿 HTML 路径")
|
||||||
|
ap.add_argument("--out", default="/tmp/design_shots", help="输出目录")
|
||||||
|
ap.add_argument("--state", action="append", default=[],
|
||||||
|
help='形如 "名称:JS",可重复;JS 为空表示初始态')
|
||||||
|
ap.add_argument("--list", action="store_true",
|
||||||
|
help="只列出可用的 JS 函数 / onclick / id,不截图")
|
||||||
|
ap.add_argument("--chrome", default="", help="Chrome 可执行文件路径")
|
||||||
|
# 原型容器一般是 375×812 的手机壳,留出边距后 460×900 刚好完整收进去
|
||||||
|
ap.add_argument("--width", type=int, default=460)
|
||||||
|
ap.add_argument("--height", type=int, default=900)
|
||||||
|
ap.add_argument("--scale", type=float, default=2.0, help="缩放倍数,2 便于看清细节")
|
||||||
|
ap.add_argument("--budget", type=int, default=9000,
|
||||||
|
help="虚拟时间预算(ms),需覆盖 CDN 脚本加载")
|
||||||
|
args = ap.parse_args()
|
||||||
|
|
||||||
|
with open(args.html, encoding="utf-8") as fp:
|
||||||
|
html = fp.read()
|
||||||
|
|
||||||
|
if args.list:
|
||||||
|
list_hooks(html)
|
||||||
|
return
|
||||||
|
|
||||||
|
chrome = args.chrome or find_chrome()
|
||||||
|
os.makedirs(args.out, exist_ok=True)
|
||||||
|
|
||||||
|
states = args.state or ["01_default:"]
|
||||||
|
for spec in states:
|
||||||
|
name, _, js = spec.partition(":")
|
||||||
|
png = render(chrome, html, name.strip(), js, args.out,
|
||||||
|
args.width, args.height, args.scale, args.budget)
|
||||||
|
ok = os.path.exists(png) and os.path.getsize(png) > 0
|
||||||
|
size = os.path.getsize(png) if ok else 0
|
||||||
|
print(f"{'✓' if ok else '✗'} {name.strip():<24} {png} ({size} bytes)")
|
||||||
|
|
||||||
|
print(f"\n用 Read 工具逐张查看 {args.out}/*.png,再开始写布局。")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
119
.claude/skills/phone-adapt/scripts/ui_probe.sh
Executable file
119
.claude/skills/phone-adapt/scripts/ui_probe.sh
Executable file
@@ -0,0 +1,119 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# 实机验证辅助:读取界面文字 / 按文字点击 / 截图 / 抓请求体。
|
||||||
|
#
|
||||||
|
# 为什么需要它:手机端验证要反复点 Tab、弹层按钮、卡片链接。靠肉眼估坐标点击
|
||||||
|
# 极易点空(本次适配就因此白跑了几轮),而 uiautomator 能拿到元素真实 bounds。
|
||||||
|
# tap-text 直接按文字定位并点中心,比手算坐标可靠得多。
|
||||||
|
#
|
||||||
|
# 用法:
|
||||||
|
# ui_probe.sh <serial> texts 列出当前界面所有可见文字
|
||||||
|
# ui_probe.sh <serial> bounds "已交接" 打印该文字元素的 bounds 与中心点
|
||||||
|
# ui_probe.sh <serial> tap-text "确认" [序号] 按文字点击(取中心点);同名多处时默认第 1 处
|
||||||
|
# ui_probe.sh <serial> wait-text "待交接" [秒] 等文字出现(默认 20 秒),点击前先等页面就绪
|
||||||
|
# ui_probe.sh <serial> wait-gone "请稍候……" [秒] 等文字消失(如等加载弹窗关闭)
|
||||||
|
# ui_probe.sh <serial> shot /tmp/a.png 截图到本地
|
||||||
|
# ui_probe.sh <serial> req <关键字> 从 logcat 抓含关键字的请求/响应体
|
||||||
|
# ui_probe.sh <serial> crash 统计并打印最近一次崩溃栈
|
||||||
|
# ui_probe.sh <serial> form 打印形态识别结果 PHONE/TABLET
|
||||||
|
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
SERIAL="${1:?用法: ui_probe.sh <serial> <命令> [参数]}"
|
||||||
|
CMD="${2:?缺少命令}"
|
||||||
|
ARG="${3:-}"
|
||||||
|
PKG="com.lukouguoji.aerologic"
|
||||||
|
A="adb -s $SERIAL"
|
||||||
|
|
||||||
|
dump() {
|
||||||
|
$A shell uiautomator dump /sdcard/_probe.xml >/dev/null 2>&1
|
||||||
|
# 注意:dump 出来的 XML 是一整行,必须按 '<' 拆成一节点一行才能按节点过滤。
|
||||||
|
# (`tr '>' '>\n'` 是字符映射不是字符串替换,等于空操作,别踩这个坑。)
|
||||||
|
$A shell cat /sdcard/_probe.xml | tr '<' '\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
# 打印所有 text 完全等于 $1 的节点的 bounds 与中心点
|
||||||
|
centers_of() {
|
||||||
|
dump | grep -F "text=\"$1\"" \
|
||||||
|
| grep -oE 'bounds="\[[0-9]+,[0-9]+\]\[[0-9]+,[0-9]+\]"' \
|
||||||
|
| sed -E 's/bounds="\[([0-9]+),([0-9]+)\]\[([0-9]+),([0-9]+)\]"/\1 \2 \3 \4/' \
|
||||||
|
| awk '{printf "bounds=[%d,%d][%d,%d] center=%d,%d\n", $1,$2,$3,$4, ($1+$3)/2, ($2+$4)/2}'
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$CMD" in
|
||||||
|
texts)
|
||||||
|
dump | tr '<' '\n' | grep -oE 'text="[^"]+"' | sed 's/text=//;s/"//g' | awk '!seen[$0]++'
|
||||||
|
;;
|
||||||
|
|
||||||
|
bounds)
|
||||||
|
[ -z "$ARG" ] && { echo "需要文字参数"; exit 1; }
|
||||||
|
centers_of "$ARG"
|
||||||
|
;;
|
||||||
|
|
||||||
|
tap-text)
|
||||||
|
[ -z "$ARG" ] && { echo "需要文字参数"; exit 1; }
|
||||||
|
idx="${4:-1}"
|
||||||
|
all=$(centers_of "$ARG")
|
||||||
|
[ -z "$all" ] && { echo "界面上找不到文字:$ARG"; exit 1; }
|
||||||
|
total=$(echo "$all" | wc -l | tr -d ' ')
|
||||||
|
# 同一文字可能在多处出现(如底部 Tab「国际」与列表里的「国际」),
|
||||||
|
# 默认点第 1 个;命中多个时提示,必要时用第 4 个参数指定序号。
|
||||||
|
if [ "$total" -gt 1 ]; then
|
||||||
|
echo "注意:${ARG} 命中 $total 处,正在点第 $idx 处(可用第 4 个参数指定序号)"
|
||||||
|
echo "$all" | nl -w2 -s' '
|
||||||
|
fi
|
||||||
|
line=$(echo "$all" | sed -n "${idx}p")
|
||||||
|
[ -z "$line" ] && { echo "序号 $idx 超出范围(共 $total 处)"; exit 1; }
|
||||||
|
cx=${line#*center=}; cx=${cx%%,*}
|
||||||
|
cy=${line##*,}
|
||||||
|
# 变量必须写成 ${ARG}:紧跟中文标点时 $ARG 会被当成变量名的一部分
|
||||||
|
echo "tap ${ARG} @ $cx,$cy"
|
||||||
|
$A shell input tap "$cx" "$cy"
|
||||||
|
;;
|
||||||
|
|
||||||
|
# 等某段文字出现 / 消失。点击前先等页面就绪很重要:
|
||||||
|
# 加载弹窗("请稍候……")会盖住整屏并吞掉 input tap,导致点击"静默失效"。
|
||||||
|
wait-text)
|
||||||
|
[ -z "$ARG" ] && { echo "需要文字参数"; exit 1; }
|
||||||
|
for _ in $(seq 1 "${4:-20}"); do
|
||||||
|
if dump | grep -qF "text=\"$ARG\""; then echo "出现: ${ARG}"; exit 0; fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
echo "超时未出现: ${ARG}"; exit 1
|
||||||
|
;;
|
||||||
|
|
||||||
|
wait-gone)
|
||||||
|
[ -z "$ARG" ] && { echo "需要文字参数"; exit 1; }
|
||||||
|
for _ in $(seq 1 "${4:-20}"); do
|
||||||
|
if ! dump | grep -qF "text=\"$ARG\""; then echo "已消失: ${ARG}"; exit 0; fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
echo "超时仍存在: ${ARG}"; exit 1
|
||||||
|
;;
|
||||||
|
|
||||||
|
shot)
|
||||||
|
out="${ARG:-/tmp/shot.png}"
|
||||||
|
$A exec-out screencap -p > "$out"
|
||||||
|
echo "$out ($(wc -c < "$out") bytes)"
|
||||||
|
;;
|
||||||
|
|
||||||
|
req)
|
||||||
|
# OkHttp 日志是多行 pretty JSON,用 -v raw 拿干净文本再按关键字取上下文
|
||||||
|
$A logcat -d -v raw | grep -B24 -A24 -- "${ARG:-POST}" | grep -E '^\s*"|POST|<-- [0-9]{3}' | tail -60
|
||||||
|
;;
|
||||||
|
|
||||||
|
crash)
|
||||||
|
n=$($A logcat -d | grep -c "FATAL EXCEPTION" || true)
|
||||||
|
echo "FATAL EXCEPTION 次数: $n"
|
||||||
|
if [ "$n" -gt 0 ]; then
|
||||||
|
$A logcat -d | grep -A25 "FATAL EXCEPTION" | tail -30
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
form)
|
||||||
|
$A logcat -d -s BaseActivity:D | grep -oE "(PHONE|TABLET)\(sw=[0-9]+dp[^)]*\)" | tail -3
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "未知命令: $CMD"; exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
49
.claude/skills/sync-air-cargo/SKILL.md
Normal file
49
.claude/skills/sync-air-cargo/SKILL.md
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
---
|
||||||
|
name: sync-air-cargo
|
||||||
|
description: 将 aerologic-app 项目中未提交的变更(已修改、新增、已删除、包括未跟踪的文件)以文件级 cp/rm 方式同步到同级目录下的 air-cargo 项目——两者是同一份源码的两个独立 git 仓库副本,分别推送到不同的远程地址。只做文件复制/删除,不对内容做任何二次编辑或转换。每当用户提到"同步到 air-cargo"、"同步到另一个仓库/项目"、"推送/复制到 cargo 项目"、"两个项目要保持一致",或者在 aerologic-app 里改完代码后问要不要同步/推送到另一个仓库时,应主动使用此 skill,而不是手动逐个 cp 文件。
|
||||||
|
---
|
||||||
|
|
||||||
|
# 同步变更到 air-cargo
|
||||||
|
|
||||||
|
## 背景
|
||||||
|
|
||||||
|
`aerologic-app` 和同级目录下的 `air-cargo` 是同一份项目源码的两个独立 git 仓库副本,目录结构完全一致,分别推送到不同的远程仓库地址。日常开发只在 `aerologic-app` 中进行,完成后需要把未提交的变更原样同步一份到 `air-cargo`,再由用户在 `air-cargo` 里自行提交、推送。
|
||||||
|
|
||||||
|
同步的判定完全基于 `git status`:在 `aerologic-app` 里,工作区中存在的文件(无论是修改、新增还是未跟踪)就复制覆盖到 `air-cargo` 对应路径;工作区中已不存在的文件(即被删除的)就在 `air-cargo` 里删除对应路径。这样天然覆盖了修改/新增/删除/未跟踪/重命名(重命名会被当作"删除旧路径 + 新增新路径"处理)等所有情况,不需要逐个状态码去分支判断。
|
||||||
|
|
||||||
|
**只同步工程项目本身的文件**:`CLAUDE.md` 以及 `.claude/` 目录(包括其下的 `skills/`、`commands/`、`settings.local.json`、`mcp.json` 等)属于 Claude Code 的工具配置/记忆,两个仓库各自独立维护,不属于"项目源码",因此始终排除在同步范围之外,不会被复制也不会被删除。脚本会在输出里单独列出"已忽略,不参与同步"的清单,方便核对。
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
脚本位于 `scripts/sync.sh`,用法:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/sync.sh [SOURCE_DIR] [TARGET_DIR] [preview|apply]
|
||||||
|
```
|
||||||
|
|
||||||
|
- `SOURCE_DIR` 默认为当前目录(一般就是 aerologic-app 项目根目录)
|
||||||
|
- `TARGET_DIR` 默认为 `SOURCE_DIR` 同级的 `air-cargo` 目录,一般不需要手动指定
|
||||||
|
- 第三个参数默认 `preview`(只打印清单,不做任何改动),传 `apply` 才会真正执行复制/删除
|
||||||
|
|
||||||
|
### 步骤
|
||||||
|
|
||||||
|
1. **先预览**,让用户看到将要发生什么:
|
||||||
|
```bash
|
||||||
|
bash /Users/kid/Development/Fusion/Projects/aerologic-app/.claude/skills/sync-air-cargo/scripts/sync.sh
|
||||||
|
```
|
||||||
|
输出会分别列出"待复制/覆盖"和"待删除"的文件清单。
|
||||||
|
|
||||||
|
2. **用 `AskUserQuestion` 工具向用户确认**,不要只是在文字里问一句让用户打字回复。这是一个会覆盖 `air-cargo` 中已有文件、且删除操作不可逆的操作,必须先把预览清单(待复制、待删除的文件数量和列表)放进问题描述里,让用户能一眼看到影响范围,选项至少包含"确认同步"和"取消"。得到确认后才能继续执行 `apply`(这遵循整体规则:覆盖性/破坏性操作需要用户确认,不要因为 skill 本身能直接跑就跳过确认)。
|
||||||
|
|
||||||
|
3. **用户确认后执行同步**:
|
||||||
|
```bash
|
||||||
|
bash /Users/kid/Development/Fusion/Projects/aerologic-app/.claude/skills/sync-air-cargo/scripts/sync.sh . /Users/kid/Development/Fusion/Projects/air-cargo apply
|
||||||
|
```
|
||||||
|
执行完会输出"复制/更新 N 个文件,删除 M 个文件"的汇总。
|
||||||
|
|
||||||
|
4. **同步之后不要自动 commit/push**。脚本只做文件复制,`air-cargo` 那边的 `git add` / `commit` / `push` 由用户自行决定和操作——两个仓库指向不同的远程地址,提交推送这类会影响远程共享状态的操作应始终由用户主导确认。
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
- 脚本只识别 git 能感知到的变更(`git status` 看得到的),`.gitignore` 忽略的文件(如构建产物 `build/`、`.gradle/`)不会被同步,这也是符合预期的——不应该把本地构建缓存同步过去。
|
||||||
|
- 如果 `air-cargo` 里对应路径本身也有未提交的本地修改,会被直接覆盖覆盖掉,预览阶段要留意这一点并提醒用户。
|
||||||
98
.claude/skills/sync-air-cargo/scripts/sync.sh
Executable file
98
.claude/skills/sync-air-cargo/scripts/sync.sh
Executable file
@@ -0,0 +1,98 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# 将 SOURCE_DIR 中未提交的变更(修改/新增/删除)以 cp/rm 的方式同步到 TARGET_DIR。
|
||||||
|
# 两个目录是同一份项目源码的独立 git 仓库副本,只做文件级复制/删除,不做任何内容编辑。
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SOURCE_DIR="${1:-$(pwd)}"
|
||||||
|
SOURCE_DIR="$(cd "$SOURCE_DIR" && pwd)"
|
||||||
|
TARGET_DIR="${2:-$(dirname "$SOURCE_DIR")/air-cargo}"
|
||||||
|
MODE="${3:-preview}" # preview | apply
|
||||||
|
|
||||||
|
if [ ! -d "$SOURCE_DIR/.git" ]; then
|
||||||
|
echo "错误:$SOURCE_DIR 不是一个 git 仓库根目录" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ ! -d "$TARGET_DIR" ]; then
|
||||||
|
echo "错误:目标目录不存在:$TARGET_DIR" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 只同步工程项目本身的文件,Claude Code 相关的配置/记忆文件(CLAUDE.md、.claude/ 目录,
|
||||||
|
# 包括其中的 skills/commands 等)两个仓库各自独立维护,不参与同步。
|
||||||
|
is_excluded() {
|
||||||
|
local path="$1"
|
||||||
|
case "$path" in
|
||||||
|
.claude/*|.claude) return 0 ;;
|
||||||
|
CLAUDE.md|*/CLAUDE.md) return 0 ;;
|
||||||
|
esac
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# --no-renames:把 rename 拆成"删除旧路径 + 新增新路径"两条记录,避免解析组合格式
|
||||||
|
# --untracked-files=all:新增的整个目录也会逐个文件列出,而不是折叠成一行目录
|
||||||
|
# -z:以 NUL 分隔,规避文件名转义/含空格的问题
|
||||||
|
copy_list=()
|
||||||
|
delete_list=()
|
||||||
|
excluded_list=()
|
||||||
|
|
||||||
|
while IFS= read -r -d '' entry; do
|
||||||
|
status="${entry:0:2}"
|
||||||
|
path="${entry:3}"
|
||||||
|
[ -z "$path" ] && continue
|
||||||
|
if is_excluded "$path"; then
|
||||||
|
excluded_list+=("$status|$path")
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ -e "$SOURCE_DIR/$path" ]; then
|
||||||
|
copy_list+=("$status|$path")
|
||||||
|
else
|
||||||
|
delete_list+=("$status|$path")
|
||||||
|
fi
|
||||||
|
done < <(git -C "$SOURCE_DIR" status --porcelain=v1 -z --no-renames --untracked-files=all)
|
||||||
|
|
||||||
|
echo "源目录: $SOURCE_DIR"
|
||||||
|
echo "目标目录: $TARGET_DIR"
|
||||||
|
echo ""
|
||||||
|
echo "=== 待复制/覆盖(${#copy_list[@]})==="
|
||||||
|
for item in "${copy_list[@]+"${copy_list[@]}"}"; do
|
||||||
|
echo " [${item%%|*}] ${item#*|}"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== 待删除(${#delete_list[@]})==="
|
||||||
|
for item in "${delete_list[@]+"${delete_list[@]}"}"; do
|
||||||
|
echo " [${item%%|*}] ${item#*|}"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== 已忽略,不参与同步(${#excluded_list[@]})==="
|
||||||
|
for item in "${excluded_list[@]+"${excluded_list[@]}"}"; do
|
||||||
|
echo " [${item%%|*}] ${item#*|}"
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$MODE" != "apply" ]; then
|
||||||
|
echo ""
|
||||||
|
echo "(预览模式,未执行任何操作。确认无误后加 apply 参数执行同步)"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
copied=0
|
||||||
|
deleted=0
|
||||||
|
|
||||||
|
for item in "${copy_list[@]+"${copy_list[@]}"}"; do
|
||||||
|
path="${item#*|}"
|
||||||
|
mkdir -p "$(dirname "$TARGET_DIR/$path")"
|
||||||
|
cp -f "$SOURCE_DIR/$path" "$TARGET_DIR/$path"
|
||||||
|
copied=$((copied+1))
|
||||||
|
done
|
||||||
|
|
||||||
|
for item in "${delete_list[@]+"${delete_list[@]}"}"; do
|
||||||
|
path="${item#*|}"
|
||||||
|
if [ -e "$TARGET_DIR/$path" ]; then
|
||||||
|
rm -f "$TARGET_DIR/$path"
|
||||||
|
deleted=$((deleted+1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "同步完成:复制/更新 $copied 个文件,删除 $deleted 个文件。"
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -113,7 +113,7 @@ captures/
|
|||||||
*.swp
|
*.swp
|
||||||
|
|
||||||
# Keystore files
|
# Keystore files
|
||||||
*.jks
|
# *.jks
|
||||||
*.keystore
|
*.keystore
|
||||||
|
|
||||||
# Google Services (e.g. APIs or Firebase)
|
# Google Services (e.g. APIs or Firebase)
|
||||||
@@ -192,6 +192,7 @@ fabric.properties
|
|||||||
|
|
||||||
# End of https://www.toptal.com/developers/gitignore/api/androidstudio,gradle,java,kotlin
|
# End of https://www.toptal.com/developers/gitignore/api/androidstudio,gradle,java,kotlin
|
||||||
.vfox/
|
.vfox/
|
||||||
|
.vfox/sdks/java
|
||||||
|
|
||||||
# Auto Claude data directory
|
# Auto Claude data directory
|
||||||
.auto-claude/
|
.auto-claude/
|
||||||
@@ -203,3 +204,4 @@ fabric.properties
|
|||||||
.worktrees/
|
.worktrees/
|
||||||
.security-key
|
.security-key
|
||||||
logs/security/
|
logs/security/
|
||||||
|
.playwright-mcp/
|
||||||
|
|||||||
14
.mcp.json
14
.mcp.json
@@ -1,14 +1,10 @@
|
|||||||
{
|
{
|
||||||
"mcpServers": {
|
"mcpServers": {
|
||||||
"apifox": {
|
"api-doc": {
|
||||||
"command": "npx",
|
"type": "http",
|
||||||
"args": [
|
"url": "https://www.agentfoxapp.com/mcp/976caff7-5f98-4487-bccf-3aa20c92cf1f",
|
||||||
"-y",
|
"headers": {
|
||||||
"apifox-mcp-server@latest",
|
"Authorization": "Bearer afk_G_VKmHTdXUi3GjQdg5AeHeH-0BSYQEPP"
|
||||||
"--project-id=7382863"
|
|
||||||
],
|
|
||||||
"env": {
|
|
||||||
"APIFOX_ACCESS_TOKEN": "APS-S2aVVwqasbdByzPLgSqryRC8BB0ZFqhQ"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
[tools]
|
[tools]
|
||||||
java = "17.0.17+10-amzn"
|
java = "17+35-amzn"
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
/Users/kid/.version-fox/cache/java/v-17.0.17+10-amzn/java-17.0.17+10-amzn
|
|
||||||
490
CHANGELOG.md
490
CHANGELOG.md
@@ -1,101 +1,389 @@
|
|||||||
# 版本变更日志 (Changelog)
|
# 版本变更日志 (Changelog)
|
||||||
|
|
||||||
本文档记录 AirLogistics 项目的所有重要变更。
|
本文档记录 AirLogistics 项目的所有重要变更。
|
||||||
|
|
||||||
格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/),
|
格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/),
|
||||||
版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
|
版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
|
||||||
|
|
||||||
## [1.8.4] - 2024-12-02
|
## [Unreleased]
|
||||||
|
|
||||||
### 新增 (Added)
|
### 变更 (Changed)
|
||||||
- 完善 Claude Code 配置,添加 Android 开发权限
|
- 【进港移库归属更正 · 2026-08-03】设计稿 11「进港移库」经确认归属**国内进港移库
|
||||||
- 创建 8 个快捷命令 (/build-debug, /install, /logs 等)
|
(DomImpMove,后端 8 接口齐全,Pad 首页「国内进港→进港移库」既有页面)**,此前误判为
|
||||||
- 定制 CLAUDE.md 为 Android 项目专用开发指南
|
国际进港并按 IntExpMove 约定预接不存在的 IntImpMove 模块(原问题清单 #31 作废)。处置:
|
||||||
- 添加 CONTRIBUTING.md 贡献指南文档
|
① 删除 module_gjj 的 IntImpMove 全套前端实现(3 Activity + 3 ViewModel + Holder + 4 布局 +
|
||||||
- 添加 CHANGELOG.md 版本变更日志
|
`IntImpMoveBean` + Api 4 方法 + 国际 Tab 菜单项 + 权限串/路由/双 Manifest 注册);
|
||||||
|
② 按 phone-adapt 流程重新适配到 `GnjMoveStashListActivity`(app 模块):主列表双形态
|
||||||
### 改进 (Changed)
|
(Pad 布局移 layout-sw600dp 零改动;手机版 = PhoneSearchBar + 待移库/已移库 Tab
|
||||||
- 优化首页菜单交互体验
|
(`DomImpMove/search`/`searchMoved` 双端点,`searchMoved` 无移库标识按端点打 `isMoved`)+
|
||||||
- 改进 UI 界面显示效果
|
角标(双端点 limit=1 取 total,仅手机发起)+ 筛选弹层 4 项 + 全选/已选计数 + 批量移库
|
||||||
|
(复用平板 `move` 链路)+ 卡片长按「拍照」浮层);新增手机专属页
|
||||||
### 技术栈
|
`GnjMoveStashDetailActivity`(Intent 传 bean 零请求,三卡片)与
|
||||||
- Kotlin 1.6.21
|
`GnjMoveStashPhotoActivity`(先调 `detail` 回填已有照片,提交走 `modify` 最小体
|
||||||
- Android Gradle Plugin 7.2.0
|
三字段规范,与平板移交编辑页同链路);`MoveStashBean` 增 `agentName`/`isMoved`/
|
||||||
- Gradle 7.3.3
|
`actionMenuVisible`/`agentDisplay`/`orDash`;手机首页入口改挂**国内 Tab**(`GnViewModel`
|
||||||
- minSdk 24, targetSdk 30, compileSdk 31
|
补通用 route 跳转,权限串 `GnjYiKu=AppDomImpMove` 与 Pad 一致,新路由
|
||||||
|
`/app/GnjMoveStashListActivity`)。
|
||||||
---
|
2026-08-03 内网真实数据双端验证通过(登录→国内 Tab→列表/Tab/详情/筛选/全选/长按拍照全链路
|
||||||
|
crash=0;平板回归原行为零变化);Proxyman A/B:`wbNo`/`awbType` 过滤生效,
|
||||||
## [1.8.x] - 之前版本
|
`fdate`/`fno`/`spCode` 被后端静默忽略(新缺口 #32)、`searchMoved`/`detail` 出参
|
||||||
|
`opId`/`opDate` 恒 null 且无姓名字段(#33)、`searchMoved` 无 pic 三字段(#34,前端已规避)
|
||||||
### 主要功能
|
|
||||||
- 国内出港业务模块 (货物收运、复磅称重、转运管理、出库装机)
|
### 新增 (Added)
|
||||||
- 国内进港业务模块 (舱单管理、卸机入库、出库提货、移库管理)
|
- 「进港查询」5.5 寸手机端适配(设计稿 10_进港查询,06 出港查询的进港镜像;详情页与运单追踪
|
||||||
- 国际出港业务模块 (国际货物收运、板箱组装、ULD容器管理)
|
复用 08/06 已适配页零新增):列表 `IntImpQueryActivity`(module_gjj,首页菜单实际跳转页;
|
||||||
- 国际进港业务模块 (国际舱单管理、报文解析、理货管理)
|
旧版 `GjjQueryListActivity` 路由已注释弃用)手机布局 = PhoneSearchBar(运单号+扫码+筛选)+
|
||||||
- 航班管理模块 (航班查询、航班统计)
|
三格统计(总票数/已入库/已出库,已入库/已出库为已加载数据客户端计数,`pageQueryTotal` 无分项
|
||||||
- 货物追踪模块 (货物状态追踪、运输日志)
|
出参,缺口 #30)+ 状态标签卡片(前端推断:`dlvTime` 非空=已出库绿 / `inDate` 非空=已入库橙 /
|
||||||
- 监装监卸模块 (监装监卸管理)
|
兜底未入库灰)+ 卡片字段件数(inPc)/重量(inWeight)/代理人/特码;筛选弹层 9 项
|
||||||
- PDA功能模块 (PDA专用功能)
|
(航班日期起止/航班号/代理/特码/始发站/运单类型/业务类型/品名中,**全部经 api-doc 核对为
|
||||||
- 蓝牙打印模块 (佳博打印机集成)
|
pageQuery 真实入参**,无缺口);平板侧滑筛选面板代码判空守卫,Pad 端行为零变化
|
||||||
|
- 「进港移库」5.5 寸手机端全新页面(设计稿 11_进港移库;**首个后端整模块缺失的适配页**:
|
||||||
### 核心架构
|
api-doc 确认无 IntImpMove 模块、权限体系无对应 key,缺口 #31):
|
||||||
- MVVM 架构模式
|
`IntImpMoveActivity`(待移库/已移库 Tab + 角标、搜索/扫码、筛选弹层 4 项(航班日期/航班号/
|
||||||
- 组件化模块设计 (11个业务模块 + 1个基础库)
|
特码/运单类型)、多选 + 全选 + 批量移库(ConfirmDialogModel 确认)、卡片长按浮层「拍照」)+
|
||||||
- DataBinding 双向绑定
|
`IntImpMoveDetailActivity`(运单详情三卡片:蓝头基本信息/绿头移库信息(仅已移库)/橙头异常照片,
|
||||||
- Kotlin Coroutines + Flow 异步处理
|
Intent 传 bean 零请求)+ `IntImpMovePhotoActivity`(拍照上传:图片网格复用 module_base
|
||||||
- ARouter 模块间通信
|
`ImageSelectNewViewHolder`,提交走 pic/originalPic/picNumber 三字段规范);
|
||||||
- Retrofit + OkHttp 网络请求
|
接口按 IntExpMove 同名约定预接四个(pageQuery/pageQueryTotal/move/uploadPic),权限串
|
||||||
- Glide 图片加载
|
`AppIntImpMove` 预定义,后端交付后前端零改动生效(权限串下发前手机首页无入口,debug 直启验证)
|
||||||
- MPAndroidChart 图表展示
|
- 新增 `IntImpMoveBean`(镜像 GjcMove + 航班/照片字段 + isMoved/flightInfo/orDash 计算属性);
|
||||||
|
`IntImpQueryBean` 新增 isQueryOutbound/isQueryStored/orDash/agentDisplay 计算属性;
|
||||||
### 开发基础设施
|
手机首页「国际」Tab 增加「进港查询」(图标 gjj_query_icon)与「进港移库」(图标复用
|
||||||
- BaseActivity/BaseBindingActivity 基类
|
gjc_yi_ku_icon)入口
|
||||||
- BaseViewModel/BasePageViewModel 基类
|
- 新增手机版资源:`bg_phone_btn_green`(绿色主按钮)、`bg_phone_card_header_orange`(橙色详情卡
|
||||||
- CommonAdapter + BaseViewHolder 列表适配
|
表头)、`bg_phone_photo_add`(虚线加号槽位)、色值 `phone_amber`
|
||||||
- PadSearchLayout/PadDataLayout 自定义组件
|
|
||||||
- 完整的 Kotlin 扩展函数库
|
### 修复 (Fixed)
|
||||||
- DataBinding 适配器集合
|
- 【11 模块全量设计稿走查】修正 4 类差异(2026-07-31,3 个并行审计 + 逐态渲染比对):
|
||||||
|
① 运单追踪手机竖排时间线补齐已发生节点的状态 pill(绿底标签展示该环节日志 content,
|
||||||
---
|
如「放行状态:01」,超长省略,设计稿 06/08 运单追踪均有此元素);
|
||||||
|
② 11 个页面手机端标题对齐设计稿短标题(出库交接/出港待计重/计重记录/计重明细/开始计重/
|
||||||
## 版本说明
|
出港运抵/出港移库/出港查询/出港货物/进港查询/进港货物),平板保持原长标题零变化;
|
||||||
|
③ ULD 编辑表单「来源」字段移至「所在港」之后(设计稿顺序);
|
||||||
### 版本号规则
|
④ 出港计重列表卡片(日期/航程/代理/特码)与计重记录卡片(代理)补齐字段小图标
|
||||||
- **Major.Minor.Patch** (例: 1.8.4)
|
(复用 ic_phone_airplane/location/person/tag,与其余模块卡片风格统一)
|
||||||
- **Major**: 重大架构变更或不兼容的 API 修改
|
- 出港查询/进港查询卡片「代理人」空值兜底失效:转换器把 JSON null 归一成空串,DataBinding
|
||||||
- **Minor**: 新功能添加,向下兼容
|
`??` 只判 null 不判空串导致 agentCode 回退永不生效;改用 Bean 计算属性 `agentDisplay`
|
||||||
- **Patch**: Bug 修复和小的改进
|
(isNullOrEmpty 双兜底),已同步修正 06 出港查询(`item_gjc_query.xml`)
|
||||||
|
|
||||||
### 变更类型
|
### 验证 (Verified)
|
||||||
- **Added**: 新增功能
|
- 进港查询手机端:Map Local mock 验证三格统计计数、三种状态标签、空值 "--" 兜底、筛选弹层
|
||||||
- **Changed**: 功能改进或变更
|
9 项收缩滚动;平板端回归横排搜索条/侧滑筛选面板/底部统计栏零变化;全程崩溃数 0
|
||||||
- **Deprecated**: 即将废弃的功能
|
- 进港移库手机端:Map Local mock 验证双 Tab 角标、双形态卡片、单选/全选联动计数、空选拦截、
|
||||||
- **Removed**: 已移除的功能
|
移库确认弹框、长按拍照浮层、运单详情、拍照上传页;全程崩溃数 0(后端模块缺失,接口联调待
|
||||||
- **Fixed**: Bug 修复
|
后端交付,见问题清单 #31)
|
||||||
- **Security**: 安全性修复
|
- 「提取出库」5.5 寸手机端适配(设计稿 09_提取出库):列表 `IntImpPickUpDLVActivity`(module_gjj)
|
||||||
|
手机布局 = PhoneSearchBar(运单号+扫码+筛选)+ **PhoneStatusTab 待出库/已出库**(`outState`
|
||||||
---
|
为 pageQuery 文档定义入参 0/1,Tab 真实过滤 + 角标双 pageQueryTotal,抓包证实携带)+
|
||||||
|
双形态卡片(待出库:圆形勾选框+橙标签+库位行;已出库:绿 √ 标签+出库人·出库时间行,
|
||||||
## 未来计划
|
`isPickedUp` = dlvTime 非空)+ 卡片内 PhoneStatBox 三列(代理人/件数/重量)+「查看详情」链接 +
|
||||||
|
PhoneBottomBar(全选+已选 N 项+出库,仅待出库 Tab 显示,复用既有 confirmOutbound);
|
||||||
### 待开发功能
|
筛选弹层 4 项(航班日期为 pageQuery 未定义入参预留;航班号 fno;代理人/特码下拉);
|
||||||
- [ ] 优化数据同步机制
|
手机端进入时清空平板默认「当天缴费日期」查全量(initPhoneExtras,平板默认值不变)
|
||||||
- [ ] 增强离线模式支持
|
- 手机专属新页「运单详情」`IntImpPickUpDetailActivity`:蓝头运单卡(红标签国际进港+品名大标题+
|
||||||
- [ ] 改进用户权限管理
|
两列 KV+库位橙标签)+ 绿头提货信息卡(柜台办理人/时间,已出库追加出库人/出库时间行),
|
||||||
- [ ] 优化蓝牙打印稳定性
|
数据直接 Intent 传列表 bean(Serializable),零新增请求
|
||||||
- [ ] 添加数据导出功能
|
- `IntImpPickUpDLVBean` 新增 `isPickedUp` 计算属性;手机首页「国际」Tab 增加「提取出库」入口
|
||||||
- [ ] 性能监控和分析
|
(权限 AppIntImpPickUpDLV 对应权限串,图标复用 Pad 端 gjj_chu_ku_icon)
|
||||||
|
- 后端缺口 2 项登记问题清单 #28~#29(pageQuery 无 fdate 入参、出参无车牌/目的港/业务类型;
|
||||||
### 技术改进
|
outState 过滤与 dlvName=出库人语义待内网实测)
|
||||||
- [ ] 升级到 Kotlin 2.0
|
|
||||||
- [ ] 迁移到 Jetpack Compose
|
- 「进港仓库」5.5 寸手机端适配(设计稿 08_进港仓库,07 出港仓库的进港镜像 + 进港详情页首次适配):
|
||||||
- [ ] 优化构建速度
|
列表 `IntImpStorageUseActivity`(module_gjj,首页菜单实际跳转页;旧版 `GjjWareHouseActivity`
|
||||||
- [ ] 完善单元测试覆盖
|
路由已注释弃用)手机布局 = PhoneSearchBar(placeholder「搜索运单号/航班号」,`phoneSearchClick`
|
||||||
- [ ] 添加 UI 自动化测试
|
分流:含字母→fno、其余→wbNo,实机抓包证实)+ 三格统计(总票数/未清仓/已清仓,clearNormal=0/1
|
||||||
|
双 total)+ 卡片四操作按钮(清仓/修改库位/出库/入库,已清仓置灰)+ 卡片字段件数/重量/航班号/
|
||||||
---
|
**始发站**(bean.dep,出港为目的站);筛选弹层 8 项(始发站走 fdep 入参;代理/特码/运单类型/
|
||||||
|
业务类型/品名中 5 项为后端未定义入参,预留传参)
|
||||||
**维护**: 本文档应在每次版本发布时更新。
|
- 进港详情页 `IntImpQueryDetailsActivity` + 3 Fragment(运单/仓库/库位信息)首次手机适配:
|
||||||
**负责人**: 项目维护团队
|
移植 06 出港详情手机布局,报文区按设计稿 3 项(原始舱单 mftStatus/理货报告 tallyStatus/
|
||||||
**最后更新**: 2024-12-02
|
海关放行 command),件重区直取 detail 出参 awbPc/awbWeight/cashWeight/inPc/inWeight
|
||||||
|
(进港自带无需求和),库位卡片优先显示中文姓名(inOpName/outOpName);
|
||||||
|
ViewModel 增加 str/strOr/dec 取值帮助(与出港同口径)
|
||||||
|
- 进港版 3 个操作弹框双变体化(清仓/入库/修改库位,手机底部弹层);修改库位手机版增加
|
||||||
|
「原库位」单选且**只列未出库库位**(沿用平板「已出库不允许修改」校验,卡片级操作时全部已出库
|
||||||
|
toast 拦截),单库位默认选中
|
||||||
|
- 手机首页「国际」Tab 增加「进港仓库」入口(权限 AppGjjWareHouse=Constant.AuthName.GjjWareHouseActivity 对应权限串,图标复用出港仓库同款)
|
||||||
|
- 后端缺口 3 项登记问题清单 #25~#27(pageQuery 无代理/特码/运单类型/业务类型/品名中 5 项筛选
|
||||||
|
入参;clearNormal 分项统计待实测;detail 出参 dep/dest1/dest/unNumber/opDate 字段待实测确认)
|
||||||
|
- 「出港仓库」5.5 寸手机端适配(设计稿 07_出港仓库,详情/运单追踪复用已适配页零新增):
|
||||||
|
列表 `IntExpStorageUseActivity` 手机布局 = PhoneSearchBar(运单号 + 扫码 + 筛选)+ 三格统计
|
||||||
|
(总票数/未清仓/已清仓,彩色左边条卡片;分项计数按同条件 + `clearNormal=0/1` 各调一次
|
||||||
|
`pageQueryTotal`,仅手机形态发起)+ 状态标签卡片(已清仓绿/未清仓橙,`clearNormal=="1"` 判定);
|
||||||
|
**卡片级四操作按钮**(清仓/修改库位/出库/入库,已清仓时清仓置灰拦截)取代平板的勾选+底部批量条,
|
||||||
|
语义等价于「勾选该主单+全部库位」复用既有 `performClear/performModifyStorage/performOutStorage/
|
||||||
|
performInStorage` 请求链路;卡片点击进详情(复用出港查询详情 `GjcQueryDetailsActivity` 3 Tab
|
||||||
|
运单/仓库/库位信息,运单追踪同样复用 `LogDetailActivity`);筛选弹层 8 项按设计稿完整实现
|
||||||
|
(航班日期/航班号/代理/特码/目的站/运单类型/业务类型/品名中,后三项为后端未定义入参,预留传参)
|
||||||
|
- 清仓/入库/修改库位三个操作弹框(`IntExpMoveClearDialogModel`/`IntExpInStorageDialogModel`/
|
||||||
|
`IntExpModifyStorageDialogModel`)双变体化:手机底部弹层(PhoneDataLayout)+ 平板居中弹框不变,
|
||||||
|
弹出位置按 `DeviceUtil.isPhone()` 切换;修改库位弹框手机版新增「原库位」单选
|
||||||
|
(卡片级操作时运单可能有多个库位,构造参数 `sourceStorageList` 传入,单库位默认选中,平板路径不受影响)
|
||||||
|
- 出库二次确认由系统 `AlertDialog` 改为项目规范的 `ConfirmDialogModel`(平板批量出库与手机卡片出库共用)
|
||||||
|
- 手机首页「国际」Tab 增加「出港仓库」入口(权限 AppIntExpStorageUse,图标复用 Pad 端 gjc_cang_ku_icon)
|
||||||
|
- `GjcMaWb` 新增 `isCleared` 手机版计算属性;新增手机版资源 `bg_phone_btn_disabled`(灰底禁用按钮)
|
||||||
|
- 后端缺口 2 项登记问题清单 #23~#24(pageQuery/pageQueryTotal 无 awbType/businessType/goodsCn
|
||||||
|
筛选入参;pageQueryTotal 的 clearNormal 分项统计过滤待内网 A/B 实测确认)
|
||||||
|
- 「出港查询」5.5 寸手机端适配(设计稿 06_出港查询,含列表/详情/运单追踪三页):
|
||||||
|
列表 `GjcQueryActivity` 手机布局 = PhoneSearchBar(运单号 + 扫码 + 筛选)+ 三格统计
|
||||||
|
(总票数/已入库/已离港,彩色左边条卡片)+ 状态标签卡片(已离港绿/已入库橙/未入库灰,
|
||||||
|
前端推断口径:fclose 非空=已离港,否则 opDate 非空=已入库);筛选弹层 9 项(平板搜索行的
|
||||||
|
日期起止/代理并入弹层,特码按设计稿改下拉,字典 `getSpecialCodeList(flag=1, ieFlag="")`,
|
||||||
|
仅手机形态经 `initPhoneExtras()` 加载);详情 `GjcQueryDetailsActivity` 3 Tab 全部复用
|
||||||
|
ViewPager2 + Fragment,手机变体以 PhoneKvItem 网格呈现「基本信息/件重信息/回执信息」,
|
||||||
|
比平板多展示承运人/始发站/中转站/目的站/UN编号,入库件数/入库重量 = warehouseList 各批次求和;
|
||||||
|
仓库/库位 Tab 改批次/库位卡片;「运单追踪」为公共页 `LogDetailActivity` 双变体首例——
|
||||||
|
手机竖排流转时间线(Activity `buildVerticalSteps` 动态构建,节点绿=已达/灰=未达 + 环节时间),
|
||||||
|
平板横向步骤条零改动,手机标题按形态显示「运单追踪」
|
||||||
|
- 手机首页「国际」Tab 增加「出港查询」入口(权限 AppIntExpSearch,图标复用 Pad 端 gjc_query_icon)
|
||||||
|
- `PhoneKvItem` 新增 `tagColor` 属性("green" 绿色高亮,海关放行正常态;默认 "orange"),
|
||||||
|
且占位符 "-"/"--" 不再套高亮标签底
|
||||||
|
- `GjcMaWb` 新增 `isQueryDeparted`/`isQueryStored`/`orDash` 手机版计算属性
|
||||||
|
- 新增手机版资源:`ic_phone_package`(件数)、`ic_phone_tag`(特码)、`bg_phone_dot_blue/gray`
|
||||||
|
- 后端缺口 2 项登记问题清单 #21~#22(isFclose 入参实测被 pageQuery/pageQueryTotal 静默忽略且
|
||||||
|
无已入库/已离港分项统计出参;detail 出参无锁定状态/计费重量字段)
|
||||||
|
|
||||||
|
### 修复 (Fixed)
|
||||||
|
- 提取出库手机版底部条「已选 N 项」在点全选后不更新:`checkAllClick` 只改勾选状态未同步
|
||||||
|
`selectedCountText`(卡片单选走 FlowBus→updateCheckAllStatus 正常),补同步后实测「已选 3 项」正确
|
||||||
|
- **`PhoneFilterPanel` 底部按钮被挤出屏幕**:面板高度 wrap_content 且内容插槽无滚动,筛选项多
|
||||||
|
(出港查询 9 项)时「重置/确认」按钮直接超出屏幕外且无任何报错。修复:内容插槽外包
|
||||||
|
ScrollView(weight=1),筛选项少时行为不变,超屏时内容区收缩滚动、按钮始终可见
|
||||||
|
(已回归出港计重 4 项弹层,行为不变)
|
||||||
|
|
||||||
|
### 验证 (Verified)
|
||||||
|
- 提取出库双端验证通过(2026-07-31,Proxyman Map Local mock 口径):手机端菜单入口、
|
||||||
|
Tab 角标(双 total)、双形态卡片(含库位空值兜底)、单选/全选与「已选 N 项」联动、
|
||||||
|
出库 ConfirmDialogModel、待出库/已出库两种详情页形态(出库人行按需显隐)、筛选弹层 4 项、
|
||||||
|
Tab 切换请求体抓包证实 outState=1 正确携带、冷启动方向恒竖屏、崩溃 0;
|
||||||
|
平板端回归:缴费日期默认当天/5 搜索条/全选/底部统计/确认出库与改造前一致,崩溃 0。
|
||||||
|
**待内网补测**:outState 过滤 A/B、dlvName=出库人语义、出库真实提交链路
|
||||||
|
- 进港仓库双端验证通过(2026-07-31,同出港仓库为 Proxyman Map Local mock 口径):
|
||||||
|
手机端登录→国际 Tab→进港仓库菜单入口、三格统计、三种卡片形态(含空值 "--" 兜底)、
|
||||||
|
详情 3 Tab 全字段(锁定状态转中文、库位中文姓名、时间截断、空值兜底)、四操作弹框、
|
||||||
|
已出库库位过滤(双库位卡片原库位仅列未出库项并默认选中)、无库位/已清仓拦截、
|
||||||
|
筛选弹层 8 项、搜索分流实机抓包证实(输入 MU1111 → 请求体 fno="MU1111"、wbNo=null)、
|
||||||
|
冷启动方向恒竖屏、崩溃 0;平板端回归:5 搜索条/全选/底部统计/4 批量按钮与改造前一致,崩溃 0。
|
||||||
|
**待内网补测**:clearNormal 分项统计 A/B、detail 推断字段(dep/dest1/dest/unNumber/opDate)、
|
||||||
|
四操作真实提交链路
|
||||||
|
- 出港仓库双端验证通过(2026-07-31,开发机不在内网 → 全程 Proxyman Map Local mock 口径):
|
||||||
|
手机端登录→国际 Tab→出港仓库菜单入口、三格统计渲染、三种卡片形态(已清仓置灰清仓/未清仓/
|
||||||
|
全空字段 "--" 兜底)、四操作按钮(清仓/入库底部弹层、修改库位弹层含原库位默认选中、
|
||||||
|
出库 ConfirmDialogModel 文案带运单号与库位数、无库位卡片 toast 拦截、已清仓清仓点击拦截)、
|
||||||
|
筛选弹层 8 项滚动 + 底部按钮可见、卡片点击进详情(Proxyman flow 证实 maWbId 正确传参且
|
||||||
|
detail mock 命中)、详情右上运单追踪跳转、冷启动方向恒竖屏(ROTATION_0×3 采样)、崩溃 0;
|
||||||
|
平板端同页面回归:5 搜索条/全选/底部统计/4 批量按钮与改造前一致,崩溃 0。
|
||||||
|
**待内网补测**:clearNormal 分项统计 A/B、agentCode/spCode/dest 筛选实测、四操作真实提交链路
|
||||||
|
- 出港查询双端实机验证通过(2026-07-31,内网真实数据 2026-06-09 共 14 票):
|
||||||
|
手机端登录→国际 Tab→出港查询菜单入口、列表加载/状态标签/三格统计(10+4=14 与卡片一致)、
|
||||||
|
筛选弹层(日期滚轮、特码/代理下拉真实取数、重置、确认后重新查询)、运单号搜索、扫码拉起、
|
||||||
|
详情 3 Tab(含仓库批次卡与库位空态)、运单追踪时间线、冷启动方向恒竖屏(mRotation=0×8 采样)、
|
||||||
|
全程 FATAL 0;平板端回归:列表 5 搜索条 + 底部统计 + 侧滑筛选面板 + 详情表格样式均与改造前一致
|
||||||
|
- 「出港运抵」5.5 寸手机端适配(主列表 + 3 个手机专属新页,设计稿 04_出港运抵):
|
||||||
|
主列表 `IntExpArriveActivity` 新增「待运抵/已运抵」Tab(客户端按 declareStatus 是否为空拆分数据集,
|
||||||
|
接口无此查询参数)+ 卡片长按浮层(待运抵→补充、已运抵→重置+回执,纯 UI 长按)+ 底部全选/已选/申报
|
||||||
|
(仅待运抵 Tab 显示,选中范围独立于 Pad 全量选择逻辑);新增「分单明细」`IntExpArriveSubOrderActivity`
|
||||||
|
(数据直接复用主列表已加载的 haWbList,零新增请求,长按单条重置 + 底部批量申报);新增「回执内容」
|
||||||
|
`IntExpArriveReceiptActivity`(只读页,复用 haWbList[].response + arrivalOpDate);新增「补充信息」
|
||||||
|
`IntExpArriveSupplementActivity`(参照 Pad 端国际进港「收发货人信息」批量应用模式,对整个运单的
|
||||||
|
haWbList 批量应用同一份表单,后端接口不存在,已实机确认 404,见问题清单 #19)
|
||||||
|
- 手机首页「国际」Tab 增加「出港运抵」入口
|
||||||
|
- `GjcMaWb`/`GjcHaWb` 新增 `isPending`/`declareTagColor`/`haWbTagColor`/`arrivalOpDateText` 等
|
||||||
|
手机版专属计算属性;`GjcHaWb` 补充 `Serializable` 实现(供 Intent 跨页传递分单列表)
|
||||||
|
- 新增手机版资源:`bg_phone_tag_indigo`/`bg_phone_tag_amber`(申报状态三色标签)、
|
||||||
|
`bg_phone_fab_purple`/`bg_phone_fab_amber`/`bg_phone_fab_green`(长按浮层圆形操作按钮)
|
||||||
|
- 后端缺口 2 项登记问题清单 #19~#20(分单补充信息保存接口不存在、Tab 无申报状态查询参数)
|
||||||
|
- 「出港运抵」对照设计稿 review 修正:状态重置弹框手机端改为设计稿底部弹层
|
||||||
|
(**弹框适配首个先例**:`dialog_int_exp_arrive_reset.xml` 同名布局双变体,Pad 版移至
|
||||||
|
`layout-sw600dp/`,`IntExpArriveResetDialogModel` 构造参数按 `DeviceUtil.isPhone()` 切
|
||||||
|
`DIALOG_TYPE_BOTTOM`/`CENTER`);主列表补空态(图标 + 文案按 Tab 切换「暂无待/已运抵的运单」);
|
||||||
|
回执页补空态兜底「暂无回执内容」(单分单入口常无回执,避免纯白屏);分单明细长按浮层按设计稿
|
||||||
|
补「回执」按钮(单分单跳回执页);分单页底部统计加分母「已选 N / M 项」;Tab 角标初始显示 0
|
||||||
|
|
||||||
|
### 修复 (Fixed)
|
||||||
|
- **RecyclerView + Tab 过滤新坑**:给 item 根节点加 `visibility="@{...}"` 切 Tab 会在列表里
|
||||||
|
留下空白——RecyclerView/LinearLayoutManager 不像普通 ViewGroup 那样让 GONE 子项自动塌陷为
|
||||||
|
0 高度。改为在 ViewModel 数据层维护完整列表,Tab 切换时把过滤后的子集整体 `refresh()` 给
|
||||||
|
adapter(已实机截图验证空白消失、卡片数与角标一致)
|
||||||
|
- **Serializable Intent + @Transient 崩溃新坑**:`GjcMaWb`/`GjcHaWb` 的 `checked` 等 UI 状态
|
||||||
|
字段标了 `@Transient`(避免 Gson 序列化 ObservableBoolean),但这同时是 JVM `transient`
|
||||||
|
修饰符,Java 序列化(Intent 传递机制)会跳过其恢复,反序列化后为 null,切换选中状态时
|
||||||
|
NullPointerException 崩溃。修复:接收方 `initOnCreated` 对列表 `.map { it.copy() }` 重新
|
||||||
|
触发类体初始化补上(已实机崩溃复现并验证修复)
|
||||||
|
- `PhoneStatusTab`/`PhoneFilterPanel` 补上遗漏的 `dispatchSaveInstanceState`/
|
||||||
|
`dispatchRestoreInstanceState` 屏蔽覆写(其余 5 个手机版复合组件均已重写,这两个是历史遗漏;
|
||||||
|
同页多实例时子控件状态可能按 id 跨实例串档)
|
||||||
|
|
||||||
|
### 验证 (Verified)
|
||||||
|
- 出港运抵双端实机验证通过:手机端 Tab 切换(角标/卡片双向正确)/全选/单选/长按菜单/查看分单
|
||||||
|
/分单明细全选与长按重置/补充信息(真实数据回填+下拉字典+提交请求体完整+后端404如实呈现)/
|
||||||
|
回执页 全链路 crash=0、方向无闪屏;平板端布局与交互(4 搜索条+分单内嵌展开+底部 5 元素操作栏)
|
||||||
|
与改造前逐项一致
|
||||||
|
- 出港运抵 review 修正双端实机验证通过:手机端重置底部弹层(长按→重置→下拉展开选项)/主列表空态
|
||||||
|
/回执页空态/分单浮层重置+回执双按钮/「已选 0 / 2 项」分母 全部与设计稿一致且 crash=0;
|
||||||
|
平板端回归:列表、批量「状态重置」弹框仍为居中 Pad 样式,行为与改造前一致
|
||||||
|
- 「出港计重」5.5 寸手机端适配(首个全链路 4+1 页模块,设计稿 03_出港计重):
|
||||||
|
待计重列表(三格统计 总票数/待计重/计重中 + 卡片状态标签 未计重/计重中 + 卡片内单票「提前运抵」+
|
||||||
|
FAB 进计重记录 + 筛选弹层 通道号/承运人/运单类型/代理人)、开始计重(头部预配统计卡 + PhoneFormRow 表单,
|
||||||
|
托盘数量/托盘自重按设计稿手输)、计重记录(三格统计 + 卡片地磅图标进明细/「查看详情」进运单详情 +
|
||||||
|
筛选弹层 入库日期起止/代理人/特码/目的站/计重人)、计重明细(汇总卡含托盘总重 + 记录卡「修改」→
|
||||||
|
全屏「修改记录」覆层,复用平板 isEditMode 编辑链路,保存后留在本页)、手机专属新页「运单详情」
|
||||||
|
`GjcWeighingWbDetailActivity`(12 字段只读网格);手机首页「国际」Tab 增「出港计重」入口
|
||||||
|
- 新增手机版公共资源:`bg_phone_btn_weak`(浅蓝弱按钮)、`bg_phone_card_top_accent`(卡片顶部主色描边条)、
|
||||||
|
`ic_phone_clipboard`、`ic_phone_weight`
|
||||||
|
- `GjcMaWb` 预留 `palletNumber`/`carWeight` 字段、`GjcCheckInRecord` 增 `carWeightStr` 双向绑定属性
|
||||||
|
(均为手机版专属,平板请求体零变化);后端缺口 7 项登记问题清单 #12~#18
|
||||||
|
(checkIn 过滤不生效、主列表筛选三入参、入库日期范围、通道号出参、计重人姓名、arriveFlag 不回填、
|
||||||
|
托盘数量/自重入参)
|
||||||
|
|
||||||
|
### 修复 (Fixed)
|
||||||
|
- 出港计重手机版搜索分流按实测修正:`likeNo` 并非任意模糊(按 8 位 no 匹配),
|
||||||
|
11 位全号改走 `wbNo` 精确查询,含字母走 `fno`
|
||||||
|
|
||||||
|
### 验证 (Verified)
|
||||||
|
- 出港计重双端实机验证通过:手机端 待计重列表/筛选/开始计重(必填校验)/计重记录/记录筛选/运单详情/
|
||||||
|
计重明细/修改覆层保存/单票提前运抵 全链路 crash=0、方向无闪屏、请求体新参数全部正确携带;
|
||||||
|
平板端 待计重/计重记录/开始计重 三页回归无变化(横屏、5 搜索条、日期默认今天、地磅区/托盘车号/浮动按钮组均在)
|
||||||
|
- 「ULD管理」5.5 寸手机端适配(app 模块首个适配页):列表卡片(三色状态标签)+ 筛选弹层(入库时间/进港航班号/所属航司/来源)+
|
||||||
|
右下角浮动新增 + 底部全选/批量删除(循环调用单条删除接口)+ 一套 `activity_uld_edit` 手机布局覆盖 新增/修改/详情 三态
|
||||||
|
(详情态右上铅笔进入修改、状态底部选择面板、所在港默认 HFE、必填校验仅手机生效)
|
||||||
|
- 新增手机版公共组件 `PhoneFormRow`(行式表单项,INPUT/SELECT/DATE/TEXT 四形态,SELECT 内置底部选择面板);
|
||||||
|
`PhoneBottomBar` 增加 `actionDanger` 危险按钮样式;新增 `bg_phone_fab`、`bg_phone_btn_danger`、`bg_phone_tag_red_light`、
|
||||||
|
`ic_phone_trash`、`ic_phone_edit` 等资源
|
||||||
|
- `ULDBean` 补解析接口既有出参 `ifNo`/`efNo`/`checkInDate`/`checkOutDate` 并预留 `source`;后端缺口 5 项
|
||||||
|
(状态三态、来源字段、筛选入参、批量删除接口、字段语义)登记问题清单 #7~#11
|
||||||
|
|
||||||
|
### 验证 (Verified)
|
||||||
|
- ULD管理双端实机验证通过:手机端列表/筛选/详情/修改/新增/单选全选/批删确认全链路 crash=0、方向无闪屏;
|
||||||
|
平板端列表与详情回归无变化
|
||||||
|
|
||||||
|
### 修复 (Fixed)
|
||||||
|
- 出库交接手机版「待/已交接」Tab 与角标计数的过滤参数名修正:`hoState` → `handoverState`
|
||||||
|
(以 api-doc 接口文档为准;此前误传 `hoState` 被后端静默忽略,两个 Tab 返回同一批数据)。
|
||||||
|
2026-07-29 内网实机验证通过:fdate=2026-07-16 下待交接/已交接 Tab 分别精确返回对应板箱,与后端直调结果一致。
|
||||||
|
验证中发现 `IntExpOutHandover/pageQueryTotal` 出参恒 0(后端缺陷,致 Tab 角标与平板底部统计为 0,已记录问题清单 #6)
|
||||||
|
|
||||||
|
### 新增 (Added)
|
||||||
|
- 新增《后端接口对接问题清单》(`documents/后端接口对接问题清单.xlsx`):手机端适配走查发现的接口缺口
|
||||||
|
(移库列表缺航班字段、缺操作人姓名、`opId/opdate/businessType` 不回填、出库交接查询缺「交接人」入参),
|
||||||
|
按模块/页面/接口定义/接口地址索引,作为与后端对接的持续维护文档
|
||||||
|
- phone-adapt skill 新增 `references/api-doc.md`:api-doc MCP 连接与逐接口核对流程,接口对齐从「问用户」升级为「先查接口文档」
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [1.9.0] - 2026-07-29
|
||||||
|
|
||||||
|
### 新增 (Added)
|
||||||
|
- 5.5 寸手持端双形态适配框架:同名布局 + 资源限定符(`layout/` 手机、`layout-sw600dp/` 平板)自动切换,业务逻辑(ViewModel/ViewHolder)零改动
|
||||||
|
- 新增 `DeviceUtil` 设备形态判定工具,及手机版公共组件库(`PhoneSearchBar`、`PhoneStatusTab`、`PhoneDataLayout`、`PhoneFilterPanel`、`PhoneBottomBar`、`PhoneStatBox`、`PhoneKvItem`)
|
||||||
|
- 完成「国际出港移库」「国际出港出库交接」两个页面的手机端适配,含各自的详情页(`IntExpMoveDetailActivity`、`IntExpOutHandoverDetailActivity`)
|
||||||
|
- 手机端首页菜单接入「出港移库」「出库交接」入口
|
||||||
|
|
||||||
|
### 修复 (Fixed)
|
||||||
|
- 修复手机端进入页面时「先横屏、约 1 秒后转竖屏」的闪屏问题:Manifest 统一改为 `android:screenOrientation="unspecified"`(全项目 192 处),由 `BaseActivity.applyDeviceOrientation()` 按设备形态在运行时锁定方向,避免系统建窗口时用错误方向
|
||||||
|
- 修复平板端因中间方案(`@integer/screen_orientation` 资源限定符)引入的回归:先竖屏再转横屏,且交互后 UI 整体放大约 1.6 倍(AutoSize 误选平板竖屏基准所致);验证系统解析 Manifest 属性不套用设备限定符,恢复为 `unspecified` 方案后两端方向与缩放均恢复正常
|
||||||
|
- AutoSize 增加手机竖屏专用设计基准 390×844dp,避免手机端沿用平板竖屏 720dp 基准导致 UI 压缩
|
||||||
|
|
||||||
|
### 技术栈
|
||||||
|
- Kotlin 1.6.21
|
||||||
|
- Android Gradle Plugin 7.2.0
|
||||||
|
- Gradle 7.3.3
|
||||||
|
- minSdk 24, targetSdk 30, compileSdk 31
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [1.8.4] - 2024-12-02
|
||||||
|
|
||||||
|
### 新增 (Added)
|
||||||
|
- 完善 Claude Code 配置,添加 Android 开发权限
|
||||||
|
- 创建 8 个快捷命令 (/build-debug, /install, /logs 等)
|
||||||
|
- 定制 CLAUDE.md 为 Android 项目专用开发指南
|
||||||
|
- 添加 CONTRIBUTING.md 贡献指南文档
|
||||||
|
- 添加 CHANGELOG.md 版本变更日志
|
||||||
|
|
||||||
|
### 改进 (Changed)
|
||||||
|
- 优化首页菜单交互体验
|
||||||
|
- 改进 UI 界面显示效果
|
||||||
|
|
||||||
|
### 技术栈
|
||||||
|
- Kotlin 1.6.21
|
||||||
|
- Android Gradle Plugin 7.2.0
|
||||||
|
- Gradle 7.3.3
|
||||||
|
- minSdk 24, targetSdk 30, compileSdk 31
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [1.8.x] - 之前版本
|
||||||
|
|
||||||
|
### 主要功能
|
||||||
|
- 国内出港业务模块 (货物收运、复磅称重、转运管理、出库装机)
|
||||||
|
- 国内进港业务模块 (舱单管理、卸机入库、出库提货、移库管理)
|
||||||
|
- 国际出港业务模块 (国际货物收运、板箱组装、ULD容器管理)
|
||||||
|
- 国际进港业务模块 (国际舱单管理、报文解析、理货管理)
|
||||||
|
- 航班管理模块 (航班查询、航班统计)
|
||||||
|
- 货物追踪模块 (货物状态追踪、运输日志)
|
||||||
|
- 监装监卸模块 (监装监卸管理)
|
||||||
|
- PDA功能模块 (PDA专用功能)
|
||||||
|
- 蓝牙打印模块 (佳博打印机集成)
|
||||||
|
|
||||||
|
### 核心架构
|
||||||
|
- MVVM 架构模式
|
||||||
|
- 组件化模块设计 (11个业务模块 + 1个基础库)
|
||||||
|
- DataBinding 双向绑定
|
||||||
|
- Kotlin Coroutines + Flow 异步处理
|
||||||
|
- ARouter 模块间通信
|
||||||
|
- Retrofit + OkHttp 网络请求
|
||||||
|
- Glide 图片加载
|
||||||
|
- MPAndroidChart 图表展示
|
||||||
|
|
||||||
|
### 开发基础设施
|
||||||
|
- BaseActivity/BaseBindingActivity 基类
|
||||||
|
- BaseViewModel/BasePageViewModel 基类
|
||||||
|
- CommonAdapter + BaseViewHolder 列表适配
|
||||||
|
- PadSearchLayout/PadDataLayout 自定义组件
|
||||||
|
- 完整的 Kotlin 扩展函数库
|
||||||
|
- DataBinding 适配器集合
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 版本说明
|
||||||
|
|
||||||
|
### 版本号规则
|
||||||
|
- **Major.Minor.Patch** (例: 1.8.4)
|
||||||
|
- **Major**: 重大架构变更或不兼容的 API 修改
|
||||||
|
- **Minor**: 新功能添加,向下兼容
|
||||||
|
- **Patch**: Bug 修复和小的改进
|
||||||
|
|
||||||
|
### 变更类型
|
||||||
|
- **Added**: 新增功能
|
||||||
|
- **Changed**: 功能改进或变更
|
||||||
|
- **Deprecated**: 即将废弃的功能
|
||||||
|
- **Removed**: 已移除的功能
|
||||||
|
- **Fixed**: Bug 修复
|
||||||
|
- **Security**: 安全性修复
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 未来计划
|
||||||
|
|
||||||
|
### 待开发功能
|
||||||
|
- [ ] 优化数据同步机制
|
||||||
|
- [ ] 增强离线模式支持
|
||||||
|
- [ ] 改进用户权限管理
|
||||||
|
- [ ] 优化蓝牙打印稳定性
|
||||||
|
- [ ] 添加数据导出功能
|
||||||
|
- [ ] 性能监控和分析
|
||||||
|
|
||||||
|
### 技术改进
|
||||||
|
- [ ] 升级到 Kotlin 2.0
|
||||||
|
- [ ] 迁移到 Jetpack Compose
|
||||||
|
- [ ] 优化构建速度
|
||||||
|
- [ ] 完善单元测试覆盖
|
||||||
|
- [ ] 添加 UI 自动化测试
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**维护**: 本文档应在每次版本发布时更新。
|
||||||
|
**负责人**: 项目维护团队
|
||||||
|
**最后更新**: 2026-07-29
|
||||||
|
|||||||
693
CLAUDE.md
693
CLAUDE.md
@@ -124,11 +124,12 @@ class XxxViewModel : BasePageViewModel() {
|
|||||||
<LinearLayout orientation="vertical">
|
<LinearLayout orientation="vertical">
|
||||||
<include layout="@layout/title_tool_bar" />
|
<include layout="@layout/title_tool_bar" />
|
||||||
|
|
||||||
<!-- 搜索区:PadSearchLayout 横排 -->
|
<!-- 搜索区:PadSearchLayout 横排 + 操作按钮(如有) -->
|
||||||
<LinearLayout orientation="horizontal">
|
<LinearLayout orientation="horizontal">
|
||||||
<PadSearchLayout type="@{SearchLayoutType.DATE}" value="@={viewModel.flightDate}" />
|
<PadSearchLayout type="@{SearchLayoutType.DATE}" value="@={viewModel.flightDate}" />
|
||||||
<PadSearchLayout type="@{SearchLayoutType.INPUT}" value="@={viewModel.flightNo}" />
|
<PadSearchLayout type="@{SearchLayoutType.INPUT}" value="@={viewModel.flightNo}" />
|
||||||
<ImageView style="@style/iv_search_action" android:onClick="@{()-> viewModel.searchClick()}" />
|
<ImageView style="@style/iv_search_action" android:onClick="@{()-> viewModel.searchClick()}" />
|
||||||
|
<!-- 如需新增/删除按钮,尺寸规范见「开发原则」工具栏图标尺寸规范 -->
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- 分页列表 -->
|
<!-- 分页列表 -->
|
||||||
@@ -382,6 +383,78 @@ fun toggleAllExpand() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
4. **子列表项 checkbox 样式**(必须使用 `_style` 系列,禁止使用 `_gray` 系列):
|
||||||
|
```xml
|
||||||
|
<!-- 子列表项 item_xxx_sub.xml 中的 iv_checkbox -->
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_checkbox"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_weight="0.5"
|
||||||
|
loadImage="@{bean.checked.get() ? @drawable/radiobtn_checked_style : @drawable/radiobtn_unchecked_style}"
|
||||||
|
android:src="@drawable/radiobtn_unchecked_style" />
|
||||||
|
```
|
||||||
|
|
||||||
|
| 资源 | 含义 | 外观 |
|
||||||
|
|------|------|------|
|
||||||
|
| `radiobtn_checked_style` | 选中 | colorPrimary 蓝色实心圆 + 白色内环 |
|
||||||
|
| `radiobtn_unchecked_style` | 未选中 | 透明 + 黑色边框圆 |
|
||||||
|
| ~~`radiobtn_checked_gray`~~ | ❌ 禁用 | 灰色实心圆(错误样式) |
|
||||||
|
|
||||||
|
#### 含子列表的列表项 UI 规范(以 `item_int_exp_storage_use.xml` 为基准)
|
||||||
|
|
||||||
|
**主列表项卡片**:
|
||||||
|
|
||||||
|
| 部位 | 属性 | 标准值 |
|
||||||
|
|------|------|--------|
|
||||||
|
| 外层容器 | marginHorizontal / marginTop | 10dp / 10dp |
|
||||||
|
| 卡片背景 | background | `@drawable/bg_white_radius_8` |
|
||||||
|
| 内容区 | padding | **10dp** |
|
||||||
|
| 选中图标 | 尺寸 / marginEnd / marginTop | 40×40dp / 10dp / **0.5px**(像素级对齐)|
|
||||||
|
| 选中图标 | 切换资源 | `img_plane_s`(选中)/ `img_plane`(未选中)|
|
||||||
|
| KV 文字 | textSize | **15sp**(Key 和 Value 均需显式设置)|
|
||||||
|
| 首要字段值(运单号)| textColor | `@color/colorPrimary` |
|
||||||
|
| 其他字段 | textColor | 无需设置(继承默认 text_normal)|
|
||||||
|
| 两行间距 | layout_marginTop | 10dp |
|
||||||
|
|
||||||
|
**展开/折叠按钮(`iv_show`)**:
|
||||||
|
|
||||||
|
| 属性 | 标准值 |
|
||||||
|
|------|--------|
|
||||||
|
| layout_width | `match_parent` |
|
||||||
|
| layout_height | **10dp** |
|
||||||
|
| layout_marginTop | **-10dp**(向上收紧,紧贴卡片底边)|
|
||||||
|
| scaleType | **centerInside**(保证箭头不被压扁/截断)|
|
||||||
|
| src | `@mipmap/img_down` |
|
||||||
|
| 显示控制 | `visible="@{bean.subList != null && !bean.subList.empty}"` |
|
||||||
|
| 不设 padding,不设 layout_marginBottom | — |
|
||||||
|
|
||||||
|
> 旧版本(18dp + padding=4dp + marginBottom=5dp)已统一替换为上述新标准,参考 `item_int_exp_arrive.xml`。组装类列表若需展开后翻转箭头,附加 `android:rotation="@{bean.showMore.get() ? 180f : 0f}"`(参考 `item_int_exp_assemble.xml`)。
|
||||||
|
|
||||||
|
**子列表区域**:
|
||||||
|
|
||||||
|
- 容器:`layout_marginTop="5dp"`,`background="#e3f6e0"`
|
||||||
|
- 表头行:`layout_marginVertical="10dp"`,`paddingHorizontal="10dp"`
|
||||||
|
- 表头文字:`textSize="14sp"`,`textColor="@color/text_normal"`,`textStyle="bold"`,`gravity="center"`
|
||||||
|
- 表头下方分隔线:`MaterialDivider` 高度 1px,`background="@color/c999999"`
|
||||||
|
- 子列表项 padding:`paddingHorizontal="10dp"`,`paddingVertical="8dp"`
|
||||||
|
- 子列表文字:`textSize="14sp"`,`textColor="@color/text_normal"`,`gravity="center"`,`layout_gravity="center_vertical"`
|
||||||
|
|
||||||
|
**子列表复选框(关键)**:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_weight="0.5"
|
||||||
|
loadImage="@{bean.checked.get() ? @drawable/radiobtn_checked_style : @drawable/radiobtn_unchecked_style}"
|
||||||
|
android:src="@drawable/radiobtn_unchecked_style" />
|
||||||
|
```
|
||||||
|
|
||||||
|
> `loadImage` 和 `android:src` **均须**使用 `_style` 系列,**禁止**使用 `_gray` 系列(参见上方复选框样式表)
|
||||||
|
|
||||||
**参考文件**: `module_gjc/.../IntExpStorageUseActivity.kt`、`IntExpStorageUseViewModel.kt`
|
**参考文件**: `module_gjc/.../IntExpStorageUseActivity.kt`、`IntExpStorageUseViewModel.kt`
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -618,6 +691,8 @@ fun resetClick() {
|
|||||||
|
|
||||||
基于 `BaseDialogModel`(XPopup 封装),支持 5 种弹窗类型。
|
基于 `BaseDialogModel`(XPopup 封装),支持 5 种弹窗类型。
|
||||||
|
|
||||||
|
> ⚠️ **强制规则**:所有二次确认弹框**必须**使用 `ConfirmDialogModel`(`com.lukouguoji.module_base.model.ConfirmDialogModel`),**禁止**使用系统 `AlertDialog`。
|
||||||
|
|
||||||
### 基础模板
|
### 基础模板
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
@@ -644,7 +719,7 @@ XxxDialogModel(onConfirm = { refresh() }).show()
|
|||||||
|------|------|------|------|
|
|------|------|------|------|
|
||||||
| 底部 | `DIALOG_TYPE_BOTTOM` | 操作选项 | 默认类型 |
|
| 底部 | `DIALOG_TYPE_BOTTOM` | 操作选项 | 默认类型 |
|
||||||
| 中间 | `DIALOG_TYPE_CENTER` | 确认框、表单输入 | `ConfirmDialogModel` |
|
| 中间 | `DIALOG_TYPE_CENTER` | 确认框、表单输入 | `ConfirmDialogModel` |
|
||||||
| 抽屉 | `DIALOG_TYPE_DRAWER` | 筛选条件 | `GjcQueryFilterDialogModel` |
|
| 抽屉 | `DIALOG_TYPE_DRAWER` | 通用右侧抽屉 | 见下方模板 |
|
||||||
| 全屏 | `DIALOG_TYPE_FULL` | 列表展示 | `NoticeMessageDialogModel` |
|
| 全屏 | `DIALOG_TYPE_FULL` | 列表展示 | `NoticeMessageDialogModel` |
|
||||||
|
|
||||||
### 抽屉弹窗(筛选场景)
|
### 抽屉弹窗(筛选场景)
|
||||||
@@ -743,6 +818,406 @@ adb logcat | grep "com.lukouguoji.aerologic" # 日志
|
|||||||
|
|
||||||
`completeSpace="@{5}"` 设置 Key 文本宽度(以"一"字宽度为单位),用于 Key-Value 布局对齐。
|
`completeSpace="@{5}"` 设置 Key 文本宽度(以"一"字宽度为单位),用于 Key-Value 布局对齐。
|
||||||
|
|
||||||
|
### AutoQuery 自动查询(PadSearchLayout / PadDataLayoutNew)
|
||||||
|
|
||||||
|
两个组件均支持输入时自动联想查询,只需在 XML 添加属性,无需修改 Kotlin:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<PadSearchLayout
|
||||||
|
autoQueryEnabled="@{true}"
|
||||||
|
autoQueryUrl="@{`/IntExpSearch/queryWbNoList`}"
|
||||||
|
autoQueryParamKey="@{`wbNo`}"
|
||||||
|
autoQueryMinLength="@{4}"
|
||||||
|
autoQueryMaxLength="@{8}"
|
||||||
|
autoQueryTitle="@{`选择运单号`}"
|
||||||
|
... />
|
||||||
|
```
|
||||||
|
|
||||||
|
- 1条结果 → 直接填充;多条结果 → 弹出选择列表;0条结果 → 无处理
|
||||||
|
- 通用 API 方法:`Api.getWbNoList(@Url url, @Body data)` 返回 `BaseResultBean<List<String>>`
|
||||||
|
- 关键文件:`module_base/.../ui/weight/data/layout/AutoQueryManager.kt`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5.5 寸手持端(手机版)双形态适配规范
|
||||||
|
|
||||||
|
项目需同时支持 **10 寸平板横屏** 与 **5.5 寸手机竖屏**。核心原则:**业务逻辑层完全复用,只重写布局**。
|
||||||
|
|
||||||
|
### 核心机制:布局按资源限定符自动切换
|
||||||
|
|
||||||
|
```
|
||||||
|
res/layout-sw600dp/activity_xxx.xml ← 平板(最小宽度 >= 600dp)
|
||||||
|
res/layout/activity_xxx.xml ← 手机(兜底,5.5 寸约 360~411dp)
|
||||||
|
```
|
||||||
|
|
||||||
|
两个变体**同名**,DataBinding 会生成同一个 Binding 基类 + 两个变体实现:
|
||||||
|
|
||||||
|
```
|
||||||
|
ActivityXxxBinding.java 公共基类(Activity 中引用的就是它)
|
||||||
|
ActivityXxxBindingImpl.java 手机变体
|
||||||
|
ActivityXxxBindingSw600dpImpl.java 平板变体
|
||||||
|
```
|
||||||
|
|
||||||
|
因此 **Activity / ViewModel / ViewHolder 的 `layoutId()`、`itemLayoutId` 全部保持原样,无需任何设备判断**。
|
||||||
|
|
||||||
|
### ⛔ 严禁:用「不同文件名 + 代码判断」切换布局
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
// ❌ 错误:会生成两个不同的 Binding 类
|
||||||
|
override fun layoutId() =
|
||||||
|
if (DeviceUtil.isPhone()) R.layout.activity_xxx_phone else R.layout.activity_xxx
|
||||||
|
```
|
||||||
|
|
||||||
|
`activity_xxx_phone.xml` 生成的是 `ActivityXxxPhoneBinding`,而 `binding` 字段声明的类型是 `ActivityXxxBinding`。
|
||||||
|
泛型擦除导致**编译期不报错**,但一进入该页面就 `ClassCastException` 崩溃。**必须用同名文件 + 资源限定符。**
|
||||||
|
|
||||||
|
### 布局变体的强制约束
|
||||||
|
|
||||||
|
| 约束 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| **DataBinding 变量必须完全一致** | 两个变体 `<data>` 中的 `<variable>` 名称与类型必须相同,否则编译失败 |
|
||||||
|
| **共用控件 id 必须双方都有** | Activity / ViewHolder 中引用的 id(如 `srl`/`rv`/`checkIcon`/`iv_icon`)两个变体都要保留 |
|
||||||
|
| **单侧独有的 id 自动变 `@Nullable`** | 只在一个变体存在的 id,Binding 基类中会是可空字段,Kotlin 侧强制 null 检查(编译器自动保障,不用担心漏改) |
|
||||||
|
|
||||||
|
### 已改造的基础设施
|
||||||
|
|
||||||
|
| 文件 | 作用 |
|
||||||
|
|------|------|
|
||||||
|
| `module_base/.../util/DeviceUtil.kt` | 设备形态判定。按 `smallestScreenWidthDp >= 600` 区分平板/手机;读 `Resources.getSystem()` 以绕开 AutoSize 对 density 的改写,保证判定稳定 |
|
||||||
|
| `module_base/BaseActivity.kt` | `applyDeviceOrientation()` 按形态锁方向(手机竖屏 / 平板横屏)。Manifest 统一写 `unspecified` 配合它使用。子类覆写 `lockOrientationByDevice()` 返回 false 可跳过 |
|
||||||
|
| `module_base/base/BaseBindingActivity.kt` | 注释固化变体约定(`layoutId()` 不做设备分支) |
|
||||||
|
| `module_base/MyApplication.kt` | **AutoSize 增加手机竖屏基准 390×844**(见下节) |
|
||||||
|
| `module_base/res/values/colors.xml` | 手机端配色 `phone_*` 系列 |
|
||||||
|
| `module_base/res/drawable/bg_phone_*.xml` | 手机端卡片、搜索框、状态标签、主按钮背景 |
|
||||||
|
| `module_base/res/layout/title_tool_bar.xml` | 手机版公共标题栏(平板版已移至 `layout-sw600dp/`) |
|
||||||
|
|
||||||
|
`DeviceUtil` 用法:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
DeviceUtil.isPhone() // 是否手机
|
||||||
|
DeviceUtil.isTablet() // 是否平板
|
||||||
|
DeviceUtil.describe() // "PHONE(sw=411dp, force=AUTO)",日志排查用
|
||||||
|
DeviceUtil.forceMode = DeviceUtil.ForceMode.PHONE // 调试:在平板上强制走手机布局
|
||||||
|
```
|
||||||
|
|
||||||
|
> `DeviceUtil.layout(padId, phoneId)` 仅用于**极少数**确实需要代码级判断的场景(如非 DataBinding 的布局)。
|
||||||
|
> **常规页面一律用资源限定符,不要调用它。**
|
||||||
|
|
||||||
|
### ⚠️ 屏幕方向:Manifest 一律写 `unspecified`,由 `BaseActivity` 按形态锁定
|
||||||
|
|
||||||
|
**症状(改造前)**:手机上打开页面(开屏页最明显)先显示横屏,约 1 秒后才转竖屏,伴随 Activity 重建。
|
||||||
|
|
||||||
|
**原因**:`android:screenOrientation` 由系统在**创建 Activity 窗口时**生效,此时业务代码还没执行。
|
||||||
|
Manifest 写死 `userLandscape` 时,即使 `BaseActivity` 在 `super.onCreate` 之前
|
||||||
|
`setRequestedOrientation(PORTRAIT)`,也只能在横屏窗口已建好之后再纠正 → 必然闪一下。
|
||||||
|
|
||||||
|
**做法**:Manifest 统一写 `unspecified`,让系统按设备**当前物理方向**建窗口
|
||||||
|
(平板横屏摆放 → 横屏起,手机 → 竖屏起,两端起始方向本就正确),
|
||||||
|
`BaseActivity.applyDeviceOrientation()` 再按形态锁定,不产生二次纠正:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<activity android:name="…"
|
||||||
|
android:configChanges="orientation|keyboardHidden"
|
||||||
|
android:screenOrientation="unspecified" />
|
||||||
|
```
|
||||||
|
|
||||||
|
全项目 192 处已统一(`module_p` 等 24 处本就是 `portrait` 的 PDA 页面保持不变)。
|
||||||
|
|
||||||
|
#### ⛔ 别用 `@integer/screen_orientation` 这类资源引用(已验证行不通)
|
||||||
|
|
||||||
|
一度改成 `android:screenOrientation="@integer/screen_orientation"` + `values/`=portrait、
|
||||||
|
`values-sw600dp/`=userLandscape,**看似优雅,实测是错的**:
|
||||||
|
|
||||||
|
系统解析 Manifest 属性时**用的是默认配置,不套用设备限定符**,所以 `values-sw600dp/` 永远不会被选中,
|
||||||
|
所有 Activity 实际都拿到了 `values/` 的竖屏值。后果是平板端:
|
||||||
|
|
||||||
|
1. 先竖屏、随后被 `BaseActivity` 纠正成横屏 —— 反而把闪屏问题搬到了平板上
|
||||||
|
2. **AutoSize 在竖屏配置下选了平板竖屏基准 720dp**(density=1280/720≈1.78,正常应为 1280/1152≈1.11)
|
||||||
|
→ 交互几次后整个 UI 放大约 1.6 倍
|
||||||
|
|
||||||
|
> 验证方法(可复现):把 `values/` 与 `values-sw600dp/` 的值**互换**,并临时让
|
||||||
|
> `lockOrientationByDevice()` 返回 false(排除运行时纠正),装到平板上看首屏方向。
|
||||||
|
> 结果是平板取了 `values/` 的值 → 证明限定符被忽略。
|
||||||
|
|
||||||
|
### ⚠️ AutoSize 设计基准必须区分手机(易漏且后果严重)
|
||||||
|
|
||||||
|
项目使用 AndroidAutoSize,`MyApplication.initAutoSizeConfig()` 按方向+设备切换设计尺寸:
|
||||||
|
|
||||||
|
| 场景 | 设计基准 |
|
||||||
|
|------|----------|
|
||||||
|
| 横屏(平板) | 1152 × 720 dp |
|
||||||
|
| 竖屏 + 手机 | **390 × 844 dp**(对应 5.5 寸设计稿画布) |
|
||||||
|
| 竖屏 + 平板 | 720 × 1280 dp |
|
||||||
|
| PictureSelector | 360 × 480 dp |
|
||||||
|
|
||||||
|
**若手机沿用平板竖屏的 720dp 基准,手机上所有 dp 会被压缩约一半,布局全部错位。**
|
||||||
|
|
||||||
|
### 手机版 UI 规范(依据 `documents/5.5寸手持端设计文件/` 设计稿)
|
||||||
|
|
||||||
|
| 部位 | 规范 |
|
||||||
|
|------|------|
|
||||||
|
| 画布基准 | 390 × 844 dp |
|
||||||
|
| 顶栏 | 高 48dp,`@color/phone_primary`(#2563EB),左侧「‹ 返回」,标题居中 18sp 加粗 |
|
||||||
|
| 页面背景 | `@color/phone_bg` (#F3F4F6) |
|
||||||
|
| 列表卡片 | `@drawable/bg_phone_card`,圆角 12dp,`marginHorizontal=16dp`,`marginTop=12dp`,`padding=14dp` |
|
||||||
|
| 卡片头行 | 圆形勾选框 20dp(`radiobtn_checked_style`/`radiobtn_unchecked_style`)+ 运单号 15sp 加粗 + 右侧状态标签 |
|
||||||
|
| 卡片字段 | 两列网格,13sp,`@color/phone_text_body`,行距 8dp |
|
||||||
|
| 状态标签 | `bg_phone_tag_green`(已完成)/ `bg_phone_tag_gray`(未完成),11sp |
|
||||||
|
| 搜索行 | 搜索框 40dp 高 + `bg_phone_search`,内含放大镜 + 输入 + 扫码;右侧筛选按钮 40dp |
|
||||||
|
| 状态 Tab | 高 42dp,选中文字 `phone_primary` + 底部 28×3dp 指示条 |
|
||||||
|
| 底部操作条 | 白底 + `elevation=8dp`,全选 + 统计(13sp/11sp 两行)+ 主按钮 `bg_phone_btn_primary` |
|
||||||
|
| 筛选弹层 | `FrameLayout` 遮罩 `#80000000` + 底部白色面板,重置 / 确定各占一半 |
|
||||||
|
|
||||||
|
### 手机版页面改造步骤
|
||||||
|
|
||||||
|
1. **移动平板布局**:`git mv res/layout/activity_xxx.xml res/layout-sw600dp/activity_xxx.xml`(item 布局同理)
|
||||||
|
2. **新建手机布局**:在 `res/layout/` 下创建**同名**文件,保持相同 `<variable>` 与共用控件 id
|
||||||
|
3. **Kotlin 侧不动**:`layoutId()`、`itemLayoutId`、ViewHolder 全部保持原样
|
||||||
|
4. **纯 UI 交互**(Tab 切换、弹层显隐)写在 Activity,不污染 ViewModel;状态过滤优先复用 ViewModel 既有字段
|
||||||
|
5. 手机布局顶部 `<include layout="@layout/title_tool_bar" />` 不变(变体自动切换)
|
||||||
|
6. **弹框(BaseDialogModel)同样要适配**:dialog 布局照样走同名双变体(Pad 版移 `layout-sw600dp/`、
|
||||||
|
手机版在 `layout/` 写设计稿的底部弹层样式),弹出位置在构造参数按形态切换:
|
||||||
|
`BaseDialogModel<XxxBinding>(if (DeviceUtil.isPhone()) DIALOG_TYPE_BOTTOM else DIALOG_TYPE_CENTER)`
|
||||||
|
(参考 `IntExpArriveResetDialogModel` + `dialog_int_exp_arrive_reset.xml` 双变体)。
|
||||||
|
页面适配完要**逐个排查该页所有 DialogModel**,漏掉的会在手机上弹出 Pad 居中样式
|
||||||
|
7. **回到手机端首页加菜单入口**(最易遗忘,见下节)——不加的话页面在手机上根本进不去
|
||||||
|
|
||||||
|
### 手机端首页菜单入口(适配完必须加,否则没入口)
|
||||||
|
|
||||||
|
手机端首页是 `module_p` 的 `PDAEnterActivity`(手持机首页),底部四个 Tab 对应:
|
||||||
|
|
||||||
|
| Tab | ViewModel | 位置 |
|
||||||
|
|-----|-----------|------|
|
||||||
|
| 国内 | `GnViewModel` | `module_p/.../ui/enter/gn/` |
|
||||||
|
| 国际 | `GjViewModel` | `module_p/.../ui/enter/gj/` |
|
||||||
|
|
||||||
|
**菜单项是手写清单,不是接口下发**。权限机制只做过滤:登录返回的权限串存在
|
||||||
|
`SharedPreferenceUtil.getString(Constant.Share.authList)`(一个逗号分隔的长字符串),
|
||||||
|
菜单项按 `authList.contains(bean.key)` 决定显不显示。
|
||||||
|
|
||||||
|
所以「适配完页面但手机首页看不到入口」的原因通常**不是没权限,而是清单里没加**。
|
||||||
|
排查顺序:先确认权限串里有对应 key,再去看清单。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 看当前登录账号实际拥有的权限串
|
||||||
|
adb -s <serial> shell "run-as com.lukouguoji.aerologic \
|
||||||
|
cat /data/data/com.lukouguoji.aerologic/shared_prefs/data.xml" | tr ',' '\n' | grep -oE "App[A-Za-z]+" | sort -u
|
||||||
|
```
|
||||||
|
|
||||||
|
加一项就是加一行 —— `ActionBean` 的第 4 个参数填 ARouter 路由即可,无需写 when 分支
|
||||||
|
(`module_p` 只依赖 `module_base`,看不到 `module_gjc` 等业务模块,跨模块只能走路由):
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
ActionBean(
|
||||||
|
"出港移库",
|
||||||
|
R.drawable.gjc_yi_ku_icon, // 图标复用 Pad 端同款
|
||||||
|
Constant.AuthName.GjcYiKuListActivity, // 权限串,与 Pad 端菜单保持一致
|
||||||
|
ARouterConstants.ACTIVITY_URL_INT_EXP_MOVE // 有 route 就走通用跳转
|
||||||
|
),
|
||||||
|
```
|
||||||
|
|
||||||
|
两点注意:
|
||||||
|
|
||||||
|
- **权限串与路由都要和 Pad 端菜单对齐**:以 `app/.../HomeFragment.kt` 里该权限对应的
|
||||||
|
`ARouter.build(...)` 为准。同一业务常有新旧两个 Activity(如移库的 `GjcYiKuListActivity`
|
||||||
|
与 `IntExpMoveActivity`),Pad 菜单实际跳的才是要适配的那个
|
||||||
|
- **图标**:`module_p` 看不到 `module_gjc` 的资源,把 Pad 图标 PNG 复制一份到
|
||||||
|
`module_p/src/main/res/drawable-xxhdpi/`(该模块既有 4 个图标就是这么放的,同名不同密度桶可共存)
|
||||||
|
|
||||||
|
**示例:状态 Tab 零 ViewModel 改动**(`IntExpMoveActivity` 已实现)
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
// Activity 中新增纯 UI 方法,写入 ViewModel 既有的 moveState 字段("" 全部 / "0" 未移库 / "1" 已移库)
|
||||||
|
fun switchTab(state: String) {
|
||||||
|
if (viewModel.moveState.value == state) return
|
||||||
|
viewModel.moveState.value = state
|
||||||
|
viewModel.searchClick() // 复用原有查询链路
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<!-- XML 中判等要把字面量放前面,避免 LiveData 为 null 时崩溃 -->
|
||||||
|
android:textColor="@{`0`.equals(viewModel.moveState) ? @color/phone_primary : @color/phone_text_body}"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 手机版公共组件库(`module_base/.../ui/weight/phone/`)
|
||||||
|
|
||||||
|
7 个组件覆盖设计稿中反复出现的部件,**新页面优先复用,不要重写 XML**。属性均为无命名空间写法,
|
||||||
|
DataBinding 适配器统一放在 `PhoneWidgetKtx.kt`(同名属性按控件类型解析,与平板端 Pad* 组件互不冲突)。
|
||||||
|
|
||||||
|
| 组件 | 用途 | 关键属性 |
|
||||||
|
|------|------|----------|
|
||||||
|
| `PhoneSearchBar` | 顶部搜索行:搜索框 + 扫码 + 圆形筛选按钮 | `hint`、`value`(双向)、`showScan`、`showFilter`、`upperCase`、`setOnScanClickListener`、`setOnFilterClickListener`、`setRefreshCallBack` |
|
||||||
|
| `PhoneStatusTab` | 状态 Tab 条(文字 + 角标,选中态下划线) | `tabs`(List\<KeyValue\>)、`counts`(List\<String\>)、`value`(双向)、`setOnTabChanged` |
|
||||||
|
| `PhoneDataLayout` | 表单/筛选项,`PhoneDataLayoutType` = `INPUT`/`DATE`/`SPINNER` | `title`、`hint`、`type`、`value`(双向)、`list`、`required`、`enable`、`setRefreshCallBack` |
|
||||||
|
| `PhoneFilterPanel` | 底部筛选弹层(遮罩 + 面板 + 重置/确认) | `title`、`panelVisible`、`setOnResetClick`、`setOnConfirmClick`、`setOnDismissClick` |
|
||||||
|
| `PhoneBottomBar` | 底部操作条:全选 + 已选统计 + 主按钮 | `allChecked`、`countText`、`actionText`、`setOnAllCheckClick`、`setOnActionClick` |
|
||||||
|
| `PhoneStatBox` | 卡片内 2~4 列统计框(未传 label 的列自动隐藏) | `label1..4`、`value1..4` |
|
||||||
|
| `PhoneKvItem` | 详情页字段项(灰标签 + 数值),`tag=true` 转高亮标签(占位符 "-"/"--" 不套底) | `title`、`value`、`tag`、`tagColor`("orange" 默认/"green") |
|
||||||
|
| `PhoneFormRow` | 行式表单项(左标签+右值+分隔线),`PhoneFormRowType` = `INPUT`/`SELECT`(内置底部选择面板)/`DATE`/`TEXT`(只读右对齐,空值 "--") | `title`、`hint`、`type`、`value`(双向)、`list`、`required`、`enable`、`numeric`、`setRefreshCallBack` |
|
||||||
|
|
||||||
|
`PhoneBottomBar` 追加 `actionDanger` 属性:true 时主按钮转浅红底红字 + 垃圾桶图标(ULD 管理批量删除)。
|
||||||
|
新增资源:`bg_phone_btn_danger`、`bg_phone_fab`(圆形浮动 + 按钮)、`bg_phone_tag_red_light`(浅红标签)、
|
||||||
|
`ic_phone_trash`、`ic_phone_edit`、色值 `phone_danger_bg/text`。
|
||||||
|
出港计重追加:`bg_phone_btn_weak`(浅蓝弱按钮,卡片内提前运抵)、`bg_phone_card_top_accent`
|
||||||
|
(卡片顶部主色描边条)、`ic_phone_clipboard`(FAB 剪贴板)、`ic_phone_weight`(砝码图标,可 tint)。
|
||||||
|
出港查询追加:`ic_phone_package`(件数)、`ic_phone_tag`(特码)、`bg_phone_dot_blue/gray`(状态圆点);
|
||||||
|
`PhoneFilterPanel` 内容插槽已内置 ScrollView(筛选项超屏时收缩滚动,底部按钮始终可见——
|
||||||
|
9 个筛选项曾把「重置/确认」挤出屏幕)。
|
||||||
|
出港仓库追加:`bg_phone_btn_disabled`(灰底禁用按钮,与 `bg_phone_btn_weak` 同 10dp 圆角,
|
||||||
|
卡片操作按钮禁用态配 `phone_tag_gray_text` 文字)。
|
||||||
|
进港移库追加:`bg_phone_btn_green`(绿色主按钮,拍照上传「确认提交」)、`bg_phone_card_header_orange`
|
||||||
|
(橙色详情卡表头,异常照片)、`bg_phone_photo_add`(虚线加号槽位)、色值 `phone_amber`。
|
||||||
|
|
||||||
|
⚠️ **弹层与浮动按钮的层级**:`PhoneFilterPanel` 默认无 elevation,页面里有带 elevation 的浮动按钮(FAB)时
|
||||||
|
会穿透到弹层之上——给弹层实例加 `android:elevation="8dp"`(大于 FAB 的 6dp)。
|
||||||
|
|
||||||
|
**`PhoneFilterPanel` 自带内容插槽**:把 `PhoneDataLayout` 直接写在其标签内即可,组件会自动移入面板中部
|
||||||
|
并施加 20dp 项间距,无需关心内部层级:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneFilterPanel
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
panelVisible="@{activity.filterPanelVisible}"
|
||||||
|
setOnResetClick="@{(v)-> activity.resetFilter()}"
|
||||||
|
setOnConfirmClick="@{(v)-> activity.confirmFilter()}"
|
||||||
|
setOnDismissClick="@{(v)-> activity.toggleFilterPanel()}">
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayout
|
||||||
|
android:layout_width="match_parent" android:layout_height="wrap_content"
|
||||||
|
title='@{"航班日期"}' hint='@{"请选择航班日期"}'
|
||||||
|
type="@{PhoneDataLayoutType.DATE}" value="@={viewModel.flightDate}" />
|
||||||
|
|
||||||
|
</com.lukouguoji.module_base.ui.weight.phone.PhoneFilterPanel>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### ⚠️ 复合自定义 View 必须屏蔽子控件状态恢复(已踩坑)
|
||||||
|
|
||||||
|
同一页面放多个 `PhoneDataLayout`/`PhoneStatBox` 时,它们的内部子控件(`et`/`tv`/`spinner`…)**共用同一套 id**。
|
||||||
|
系统按 id 保存/恢复视图状态会跨实例串档 —— 实测表现为:DATE 项的默认日期被邻近输入框恢复的空文本清空,
|
||||||
|
并通过双向绑定把 ViewModel 字段也写成了空值(筛选条件静默丢失)。
|
||||||
|
|
||||||
|
因此每个含内部 id 的手机版组件都重写了:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
override fun dispatchSaveInstanceState(container: SparseArray<Parcelable>) = dispatchFreezeSelfOnly(container)
|
||||||
|
override fun dispatchRestoreInstanceState(container: SparseArray<Parcelable>) = dispatchThawSelfOnly(container)
|
||||||
|
```
|
||||||
|
|
||||||
|
**新增同类组件时必须照做**(取值由 ViewModel + DataBinding 持有,本就不需要视图级恢复)。
|
||||||
|
|
||||||
|
### 已完成 / 待办
|
||||||
|
|
||||||
|
- ✅ **已完成**:适配框架 + 手机端公共资源 + 7 个手机版公共组件
|
||||||
|
- ✅ **已完成页面**:
|
||||||
|
- 「国际出港移库」`IntExpMoveActivity` + 「运单详情」`IntExpMoveDetailActivity`(框架参考页)
|
||||||
|
- 「国际出港出库交接」`IntExpOutHandoverActivity` + 「板箱详情」`IntExpOutHandoverDetailActivity`
|
||||||
|
(公共组件首个完整落地页,双端实机验证通过)
|
||||||
|
- 「ULD管理」`UldListActivity` + `UldEditActivity`(app 模块首个适配页;一套编辑布局覆盖
|
||||||
|
新增/修改/详情三态;批量删除为前端循环调用单条接口;状态三态/来源等 5 项后端缺口见问题清单 #7~#11)
|
||||||
|
- 「出港计重」全链路 4+1 页:`GjcWeighingListActivity`(待计重列表,三格统计 + 卡片单票提前运抵 +
|
||||||
|
FAB 进记录)、`GjcWeighingStartActivity`(开始计重,托盘数量/自重按设计稿手输)、
|
||||||
|
`GjcWeighingRecordListActivity`(计重记录)、`GjcWeighingRecordDetailsActivity`(计重明细,
|
||||||
|
isEditMode 复用为手机全屏「修改记录」覆层)+ 手机专属新页 `GjcWeighingWbDetailActivity`(运单详情)。
|
||||||
|
搜索分流规则(实测):含字母→fno、11 位数字→wbNo、其余→likeNo(likeNo 按 8 位 no 匹配并非模糊);
|
||||||
|
checkIn 过滤等 7 项后端缺口见问题清单 #12~#18
|
||||||
|
- 「出港运抵」主列表 + 3 个手机专属新页:`IntExpArriveActivity`(待运抵/已运抵 Tab,客户端按
|
||||||
|
`declareStatus` 是否为空拆分数据集,卡片长按浮层:待运抵→补充、已运抵→重置+回执)、
|
||||||
|
`IntExpArriveSubOrderActivity`(分单明细,数据直接复用主列表已加载的 `haWbList`,零新增请求)、
|
||||||
|
`IntExpArriveReceiptActivity`(回执内容只读页,复用 `haWbList[].response`)、
|
||||||
|
`IntExpArriveSupplementActivity`(补充信息,参照 Pad 端国际进港「收发货人信息」批量应用模式,
|
||||||
|
后端接口不存在,实机 404 已确认,见问题清单 #19)。
|
||||||
|
Tab 过滤两个坑:① **RecyclerView 里 `View.GONE` 不会让 item 塌陷为 0 高度**(不同于普通
|
||||||
|
ViewGroup),必须在数据层整体 `refresh()` 过滤后的子集给 adapter,不能给 item 根节点加
|
||||||
|
visibility 绑定(实机截图验证过,见「常见编译错误速查」);② 通过 `Intent.putExtra(Serializable)`
|
||||||
|
传递的 `GjcHaWb`/`GjcMaWb`,其 `checked`/`showMore`/`actionMenuVisible` 字段标了
|
||||||
|
`@Transient`(= JVM `transient`,Java 序列化会跳过),反序列化后为 null,直接
|
||||||
|
`.checked.set(...)` 会崩溃——接收方 `initOnCreated` 必须对列表 `.map { it.copy() }` 补上。
|
||||||
|
2026-07-30 review 修正:状态重置弹框改手机底部弹层(弹框双变体首例,见改造步骤第 6 条)、
|
||||||
|
主列表/回执页补空态、分单浮层补「回执」、分单统计加分母、Tab 角标初始 0
|
||||||
|
- 「提取出库」`IntImpPickUpDLVActivity`(module_gjj,类型2 多选批量页 + 手机专属详情新页
|
||||||
|
`IntImpPickUpDetailActivity`(Intent 传 Serializable bean 零请求)。待出库/已出库 Tab 绑
|
||||||
|
**文档定义入参 `outState`**(0/1,抓包证实携带,效果待内网 #29)+ 角标双 pageQueryTotal;
|
||||||
|
双形态卡片按 `isPickedUp`(dlvTime 非空)切换;手机进入时清空平板默认「当天缴费日期」查全量;
|
||||||
|
缺口 #28:无 fdate 入参、出参无车牌(提货车辆)/目的港/业务类型。
|
||||||
|
⚠️ 踩坑:`checkAllClick` 全选后底部「已选 N 项」不更新——批量勾选不走 FlowBus 单卡事件,
|
||||||
|
必须在 checkAllClick 里同步 selectedCountText)
|
||||||
|
- 「进港查询」`IntImpQueryActivity`(module_gjj;06 出港查询的进港镜像:三格统计
|
||||||
|
总票数/已入库/已出库为已加载数据客户端计数(`pageQueryTotal` 无分项出参,缺口 #30),
|
||||||
|
卡片状态前端推断:`dlvTime` 非空=已出库(绿)/`inDate` 非空=已入库(橙)/兜底未入库(灰);
|
||||||
|
筛选弹层 9 项**入参全部经 api-doc 核对真实存在**(分页参数名 `page`/`limit`,品名参数名
|
||||||
|
`goods`);详情页与运单追踪复用 08/06 已适配页零新增;平板侧滑筛选面板代码已判空守卫。
|
||||||
|
⚠️ 踩坑:代理人绑定不能写 `bean.agentName ?? bean.agentCode`——转换器把 JSON null 归一成
|
||||||
|
空串,`??` 只判 null 不判空串,须用 Bean 计算属性 `agentDisplay`(06 出港查询同步修正))
|
||||||
|
- 「进港移库」`GnjMoveStashListActivity`(app 模块,**2026-08-03 归属更正后重做**:设计稿 11
|
||||||
|
实际归属**国内进港移库 DomImpMove**(后端 8 接口齐全、Pad 首页「国内进港→进港移库」既有页面),
|
||||||
|
最初误判为国际进港并按 IntExpMove 约定预接了不存在的 IntImpMove 模块(原缺口 #31),该套
|
||||||
|
module_gjj 前端实现已整体删除。现行实现:主列表双形态(Pad 布局移 layout-sw600dp 零改动),
|
||||||
|
待移库/已移库 Tab 走 **`search`/`searchMoved` 双端点**(`searchMoved` 出参无移库标识,前端按
|
||||||
|
端点给 bean 打 `isMoved`),Tab 角标 = 两端点各调一次 limit=1 取分页 total(`initPhoneExtras`
|
||||||
|
开关,仅手机发起);手机专属新页 `GnjMoveStashDetailActivity`(Intent 传 bean 零请求,三卡片:
|
||||||
|
基本信息/移库信息(仅已移库)/异常照片)+ `GnjMoveStashPhotoActivity`(进入先调 `detail` 回填
|
||||||
|
已有照片——`searchMoved` 出参无 pic 三字段 #34,提交走 **`modify` 最小体**
|
||||||
|
`{mawbId,remark,picNumber,pic,originalPic}`,与平板移交编辑页同链路);批量移库复用平板
|
||||||
|
`moveStashClick`(`move`:fid+ids)。手机首页入口在**国内 Tab**(`GnViewModel`,权限串
|
||||||
|
`GnjYiKu=AppDomImpMove`,需补通用 route 跳转逻辑,图标从 module_gnj 复制);
|
||||||
|
GnjMoveStashListActivity 补 @Route `/app/GnjMoveStashListActivity`。
|
||||||
|
2026-08-03 内网真实数据双端验证通过;筛选 A/B:`wbNo`/`awbType` 生效,
|
||||||
|
`fdate`/`fno`/`spCode` 被后端静默忽略(#32)、`opId`/`opDate` 恒 null(#33))
|
||||||
|
- 「进港仓库」`IntImpStorageUseActivity`(module_gjj,07 出港仓库的进港镜像;**首页菜单实际跳转页,
|
||||||
|
旧版 `GjjWareHouseActivity` 路由已注释弃用**。差异:卡片/筛选用始发站(fdep 入参)替代目的站;
|
||||||
|
搜索框「运单号/航班号」分流(含字母→fno、其余→wbNo,抓包证实);筛选 5 项无入参(缺口 #25,
|
||||||
|
比出港多 2 项);连带首次适配进港详情 `IntImpQueryDetailsActivity` + 3 Fragment(报文区 3 项:
|
||||||
|
原始舱单/理货报告/海关放行,件重区直取 inPc/inWeight 无需求和,detail keys 以平板绑定为准 +
|
||||||
|
dep/dest1/dest/unNumber/opDate 按出港推断待实测 #27);修改库位手机弹层「原库位」只列未出库
|
||||||
|
库位(沿用平板校验);**前端接口前缀是 `IntImpStorage` 不是 `IntImpStorageUse`**,api-doc 按
|
||||||
|
后者搜不到)
|
||||||
|
- 「出港仓库」`IntExpStorageUseActivity`(嵌套多选列表页型的首个适配:平板「勾选主/子列表 +
|
||||||
|
底部批量操作」在手机上改为**卡片级四按钮**(清仓/修改库位/出库/入库,已清仓置灰),语义等价
|
||||||
|
「勾选该主单+全部库位」直接复用既有 performXxx 链路,ViewHolder 对双侧独有 id 全判空;
|
||||||
|
三格统计 总票数/未清仓/已清仓(后两格 = 同条件 + `clearNormal=0/1` 各调一次 pageQueryTotal,
|
||||||
|
过滤是否生效待内网 A/B,缺口 #24);筛选弹层 8 项中运单类型/业务类型/品名(中) 为后端未定义
|
||||||
|
入参(缺口 #23,预留传参);三个操作弹框双变体化 + 手机版修改库位弹层加「原库位」单选;
|
||||||
|
出库确认 AlertDialog → ConfirmDialogModel;详情与运单追踪完全复用出港查询已适配页,零新增页面)
|
||||||
|
- 「出港查询」`GjcQueryActivity`(列表:三格统计 总票数/已入库/已离港 + 卡片状态标签,
|
||||||
|
状态为前端推断:`fclose` 非空=已离港/`opDate` 非空=已入库;筛选弹层 9 项,日期起止与代理
|
||||||
|
从平板搜索行并入,特码改下拉 `getSpecialCodeList(flag=1, ieFlag="")`;分项统计为已加载
|
||||||
|
数据客户端计数,`isFclose` 实测被后端忽略,缺口 #21)+ `GjcQueryDetailsActivity`(3 Tab
|
||||||
|
复用 ViewPager2+Fragment,手机变体 PhoneKvItem 网格;入库件数/重量= warehouseList 求和;
|
||||||
|
锁定状态/计费重量后端无字段,缺口 #22)+ 「运单追踪」`LogDetailActivity`(app 模块公共页
|
||||||
|
双变体首例:手机竖排时间线由 Activity `buildVerticalSteps` 动态构建,平板横向步骤条不动;
|
||||||
|
手机标题按形态切「运单追踪」)。平板侧滑筛选面板代码已判空守卫(手机变体无 filter_panel
|
||||||
|
include,Binding 字段为 @Nullable)
|
||||||
|
- ✅ **设计稿 11 个入口(01~11)已于 2026-07-31 全部适配完成**
|
||||||
|
- ⏳ **待办**:
|
||||||
|
- `PhoneSearchBar` 接入 AutoQuery 联想(`AutoQueryManager` 目前只对接了 Pad 系组件)
|
||||||
|
- 进港移库筛选三项(航班日期/航班号/特码)待后端实装 `fdate`/`fno`/`spCode` 入参(缺口 #32)、
|
||||||
|
移库人/移库时间待后端回填 `opId`/`opDate` 并补姓名出参(缺口 #33)后自动生效
|
||||||
|
- 出库交接 Tab 角标恒 0:`IntExpOutHandover/pageQueryTotal` 出参恒 0(后端缺陷,问题清单 #6),
|
||||||
|
后端修复后角标自动恢复(`handoverState` 过滤本身已于 2026-07-29 实机验证通过)生效
|
||||||
|
- 📋 **接口对接**:适配中发现的后端接口缺口统一记录在 `documents/后端接口对接问题清单.xlsx`
|
||||||
|
(按模块/页面/接口定义/接口地址索引,与后端对接的正式文档,每页适配完必须维护);
|
||||||
|
接口入参/出参一律以 api-doc MCP 为准核对,流程见
|
||||||
|
`.claude/skills/phone-adapt/references/api-doc.md`——**后端对不认识的参数静默忽略**,
|
||||||
|
猜参数名会得出「后端不支持」的误判(出库交接 `hoState`→`handoverState` 已踩过)
|
||||||
|
|
||||||
|
### 调试便利:直接拉起页面
|
||||||
|
|
||||||
|
`app/src/debug/AndroidManifest.xml`(**仅 Debug 生效,不进 Release 包**)通过 `tools:replace` 将适配调试页临时置为 `exported="true"`,免去每次登录再逐级点入:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
adb shell am start -n com.lukouguoji.aerologic/com.lukouguoji.gjc.page.move.IntExpMoveActivity
|
||||||
|
adb shell am start -n com.lukouguoji.aerologic/com.lukouguoji.gjc.activity.IntExpOutHandoverActivity
|
||||||
|
```
|
||||||
|
|
||||||
|
新增调试页时在该文件追加对应 `<activity>` 即可。
|
||||||
|
|
||||||
|
> 模拟器通常连不上内网服务(提示「接口访问失败」),列表为空。若需验证卡片/详情的还原度,
|
||||||
|
> 可在 Activity 里临时注入几条样例 Bean(`binding.rv.commonAdapter()?.refresh(list)`)截图比对,**验证后务必删除**。
|
||||||
|
|
||||||
|
**参考文件**:`module_base/.../util/DeviceUtil.kt`、`module_gjc/res/layout/activity_int_exp_move.xml`(手机)、`module_gjc/res/layout-sw600dp/activity_int_exp_move.xml`(平板)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Import 路径速查
|
## Import 路径速查
|
||||||
@@ -769,7 +1244,21 @@ adb logcat | grep "com.lukouguoji.aerologic" # 日志
|
|||||||
|
|
||||||
### 扩展函数(均在 `com.lukouguoji.module_base.ktx` 包下)
|
### 扩展函数(均在 `com.lukouguoji.module_base.ktx` 包下)
|
||||||
|
|
||||||
`launchCollect`、`launchLoadingCollect`、`showToast`、`toRequestBody`、`verifyNullOrEmpty`、`noNull`、`formatDate`
|
`launchCollect`、`launchLoadingCollect`、`showToast`、`toRequestBody`、`verifyNullOrEmpty`、`noNull`、`formatDate`、`setUpperCaseAlphanumericFilter`
|
||||||
|
|
||||||
|
### 工具类
|
||||||
|
|
||||||
|
| 类 | 正确路径 |
|
||||||
|
|----|----------|
|
||||||
|
| `DictUtils` | `com.lukouguoji.module_base.util.DictUtils` |
|
||||||
|
| `DeviceUtil` | `com.lukouguoji.module_base.util.DeviceUtil` |
|
||||||
|
| `MediaUtil` | `com.lukouguoji.module_base.util.MediaUtil` |
|
||||||
|
| `UploadUtil` | `com.lukouguoji.module_base.util.UploadUtil` |
|
||||||
|
| `KeyValue` | `dev.utils.app.info.KeyValue` |
|
||||||
|
| `DateUtils` | `dev.utils.common.DateUtils` |
|
||||||
|
| `SharedPreferenceUtil` | `com.lukouguoji.module_base.db.perference.SharedPreferenceUtil` |
|
||||||
|
| `ScanModel` | `com.lukouguoji.module_base.model.ScanModel` |
|
||||||
|
| `ConfirmDialogModel` | `com.lukouguoji.module_base.model.ConfirmDialogModel` |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -789,6 +1278,70 @@ adb logcat | grep "com.lukouguoji.aerologic" # 日志
|
|||||||
| 资源引用不存在 | drawable/color/string 缺失 | 先检查资源是否存在,不存在则创建或用已有资源 |
|
| 资源引用不存在 | drawable/color/string 缺失 | 先检查资源是否存在,不存在则创建或用已有资源 |
|
||||||
| `View.VISIBLE` 报错 | 未导入 | XML `<data>` 中加 `<import type="android.view.View" />` |
|
| `View.VISIBLE` 报错 | 未导入 | XML `<data>` 中加 `<import type="android.view.View" />` |
|
||||||
| `textStyle` DataBinding 报错 | 不支持 | 用固定值 `android:textStyle="bold"` |
|
| `textStyle` DataBinding 报错 | 不支持 | 用固定值 `android:textStyle="bold"` |
|
||||||
|
| 手机版页面一进入就 `ClassCastException` | 用了「不同文件名 + 代码判断」切换布局,生成了两个 Binding 类 | 改用同名布局 + 资源限定符(`layout/` 与 `layout-sw600dp/`),见「5.5 寸手持端双形态适配规范」 |
|
||||||
|
| 布局变体编译报 `variable not found` | 两个变体的 `<data>` 中 `<variable>` 不一致 | 手机与平板变体的变量名/类型必须完全相同 |
|
||||||
|
| 手机上元素小一半 / 布局错位 | AutoSize 仍按平板 720dp 基准换算 | 确认 `MyApplication.initAutoSizeConfig()` 中手机竖屏走 390×844 分支 |
|
||||||
|
| 手机版筛选项默认值(如日期)自动被清空 | 多个复合自定义 View 内部子控件 id 相同,系统按 id 恢复状态时跨实例串档 | 组件重写 `dispatchSaveInstanceState`/`dispatchRestoreInstanceState` 为 `dispatchFreezeSelfOnly`/`dispatchThawSelfOnly`(见「手机版公共组件库」) |
|
||||||
|
| 手机上页面先横屏再转竖屏(闪一下) | Manifest 写死 `screenOrientation="userLandscape"`,系统建窗口时已按横屏,代码纠正为时已晚 | 改成 `android:screenOrientation="unspecified"`,由 `BaseActivity` 按形态锁定(见「屏幕方向」小节) |
|
||||||
|
| 平板先竖屏再转横屏 + 交互后 UI 放大约 1.6 倍 | Manifest 用了 `@integer/screen_orientation` 资源引用;系统解析 Manifest 不套用限定符,全部取到竖屏值,AutoSize 随之选了平板竖屏 720dp 基准 | Manifest 改回 `unspecified`(见「屏幕方向」小节的 ⛔ 说明) |
|
||||||
|
| Tab/分类切换后列表顶部留一大块空白,卡片数量却不对 | 给 item 根节点加了 `visibility="@{tab条件 ? VISIBLE : GONE}"`——RecyclerView/LinearLayoutManager 不会像普通 ViewGroup 那样让 GONE 的子项自动塌陷为 0 高度,仍按测量高度参与滚动区域计算 | 不要用 item 级 visibility 做过滤;在 ViewModel 里自行维护完整列表,Tab 切换时把过滤后的子集整体 `commonAdapter()?.refresh(filteredList)` 给 adapter |
|
||||||
|
| 通过 `Intent.putExtra(Serializable)` 传递的 Bean,切换其 `checked`/`showMore` 等状态时崩溃 `NullPointerException: ... on a null object reference` | 这些字段标了 `@Transient`(= JVM `transient`,本意是避免 Gson 网络请求序列化 `ObservableBoolean`),但 Java 对象序列化(Intent 传递走的机制)会跳过 `transient` 字段的恢复,反序列化后是 null | 接收方 `initOnCreated` 里对列表做 `.map { it.copy() }`——`.copy()` 会重新走一遍类体初始化逻辑,用全新 `ObservableBoolean(false)` 补上 |
|
||||||
|
| 布局构建报 `Error: The string "--" is not permitted within comments` | XML 注释中出现连续双横线(如写"兜底 \"--\""),XML 规范禁止 | 注释里改用文字描述(如「兜底双横线」),代码绑定表达式中的 `"--"` 不受影响 |
|
||||||
|
| 多选页手机版点「全选」后底部「已选 N 项」不更新(单卡勾选正常) | 批量勾选在 `checkAllClick` 里直接 set,不走 FlowBus 的单卡 EVENT_CHECK_CHANGED 事件,`selectedCountText` 只在事件回调里更新 | `checkAllClick` 末尾自行同步 `selectedCountText`(平板布局不绑定该字段,无影响) |
|
||||||
|
| XML 里 `bean.a ?? bean.b` 兜底不生效,字段明明有值却显示占位符 | 网络层转换器把 JSON null 归一成空串 `""`,DataBinding 的 `??` 只判 null 不判空串,永远取到左侧的空串 | 在 Bean 上加计算属性做 `isNullOrEmpty` 双兜底(如 `agentDisplay`),XML 绑计算属性(进港查询/出港查询代理人已踩过) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 编辑表单下拉框(SPINNER)回填规范
|
||||||
|
|
||||||
|
编辑页面(DetailsPageType.Modify)中,下拉框需要根据已有数据自动选中对应项。**必须使用 `DictUtils` 的 `checkedValue` 参数**,禁止依赖组件自动匹配 value。
|
||||||
|
|
||||||
|
### 原理
|
||||||
|
|
||||||
|
`DictUtils` 的 `handleCallBack` 会将 `checkedValue` 匹配的 `KeyValue` 置于列表首位。`PadDataLayoutNew` 的 SPINNER 默认显示列表第 0 项,因此匹配项自动成为选中项,无需额外设置 selectedIndex。
|
||||||
|
|
||||||
|
### 标准做法(参考 `GjjManifestDetailsViewModel`、`GjjManifestAddViewModel`)
|
||||||
|
|
||||||
|
1. **字典加载必须在编辑数据加载之后**(不能放在 `init` 中),确保 `checkedValue` 可用
|
||||||
|
2. **编辑模式传入 `checkedValue`**,新增模式传 `null`
|
||||||
|
3. **编辑模式不预置空 `KeyValue("", "")`**(否则空项会占据首位,覆盖 checkedValue 排序)
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
fun initOnCreated(intent: Intent) {
|
||||||
|
// 1. 先解析页面类型和编辑数据
|
||||||
|
if (pageType.value == DetailsPageType.Modify) {
|
||||||
|
loadManifestFromBean(bean) // 设置 agent.value、specialCode.value 等
|
||||||
|
}
|
||||||
|
// 2. 再加载字典列表(此时 checkedValue 已可用)
|
||||||
|
loadDictLists()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadDictLists() {
|
||||||
|
val isModify = pageType.value == DetailsPageType.Modify
|
||||||
|
|
||||||
|
DictUtils.getXxxList(
|
||||||
|
addAll = false,
|
||||||
|
checkedValue = if (isModify) field.value else null // 编辑模式传值,新增传 null
|
||||||
|
) {
|
||||||
|
xxxList.postValue(if (isModify) it else listOf(KeyValue("", "")) + it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### checkedValue 取值规则
|
||||||
|
|
||||||
|
提交时用的哪个字段值,`checkedValue` 就传哪个。对照 `toKeyValue()` 的 `value` 字段确认匹配:
|
||||||
|
|
||||||
|
| DictUtils 方法 | KeyValue.value 来源 | checkedValue 示例 |
|
||||||
|
|---|---|---|
|
||||||
|
| 通用(`handleCallBack`) | `DictBean.code` | `manifest.agentCode`(如 "SFINT") |
|
||||||
|
| `getShouYunPackageTypeList` | `PackageBean.name` | `manifest.packageType`(如 "木框") |
|
||||||
|
|
||||||
|
### 禁止做法
|
||||||
|
|
||||||
|
- ❌ 在 `init` 中加载字典(编辑数据尚未可用,无法传 `checkedValue`)
|
||||||
|
- ❌ 依赖 `PadDataLayoutNew` 的 `value` 属性自动匹配列表(Spinner adapter 重建时 `onItemSelected` 回调会覆盖已有值)
|
||||||
|
- ❌ 编辑模式下在列表前添加 `KeyValue("", "")`(会干扰 `checkedValue` 置顶排序)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -801,10 +1354,16 @@ adb logcat | grep "com.lukouguoji.aerologic" # 日志
|
|||||||
```xml
|
```xml
|
||||||
<activity android:name="com.lukouguoji.gjc.activity.XxxActivity"
|
<activity android:name="com.lukouguoji.gjc.activity.XxxActivity"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:exported="false" android:screenOrientation="userLandscape" />
|
android:exported="false"
|
||||||
|
android:screenOrientation="unspecified" />
|
||||||
```
|
```
|
||||||
|
> `screenOrientation` **必须写 `unspecified`**,不要写死 `userLandscape`、也不要用资源引用。
|
||||||
|
> 写死横屏会让手机端「先横屏、约 1 秒后转竖屏」闪一下;资源引用则会让平板端出问题
|
||||||
|
> (详见下方「屏幕方向」小节)。
|
||||||
|
|
||||||
3. 在 `ARouterConstants` 注册路由(如需)
|
3. 在 `ARouterConstants` 注册路由(如需)
|
||||||
4. 标题栏统一用 `<include layout="@layout/title_tool_bar" />`,Activity 中 `setBackArrow("标题")`
|
4. 标题栏统一用 `<include layout="@layout/title_tool_bar" />`,Activity 中 `setBackArrow("标题")`
|
||||||
|
5. **双形态布局**:需同时支持手机的页面,平板布局放 `res/layout-sw600dp/`、手机布局放 `res/layout/`,两者**同名**且变量与共用 id 一致。详见「5.5 寸手持端双形态适配规范」
|
||||||
|
|
||||||
### 常见业务操作
|
### 常见业务操作
|
||||||
|
|
||||||
@@ -834,6 +1393,109 @@ companion object {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### API 接口目录对应规则
|
||||||
|
|
||||||
|
为某页面查找接口时,**必须按业务路径匹配对应 API 目录**,不能跨模块借用。
|
||||||
|
|
||||||
|
| API 前缀 | 所属模块 |
|
||||||
|
|----------|---------|
|
||||||
|
| `IntImpManiFest/` | 国际进港-进港舱单(增删改查) |
|
||||||
|
| `IntImpAirManifest/` | 国际进港-原始舱单(申报、补充信息等) |
|
||||||
|
|
||||||
|
不同前缀代表不同业务,即使功能语义相似(如"更新"),也不能混用。不确定时询问用户。
|
||||||
|
|
||||||
|
### 页面定位规则
|
||||||
|
|
||||||
|
修改代码前,必须确认目标文件是**首页菜单实际跳转到的 Activity/ViewModel**,而非同名旧版文件。同一业务有多个实现时,以首页菜单入口链路为准。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 图片上传与展示规范
|
||||||
|
|
||||||
|
### 图片上传三字段规范
|
||||||
|
|
||||||
|
上传图片后提交表单时,**必须同时传 `pic`、`originalPic`、`picNumber` 三个字段**,缺一不可。
|
||||||
|
|
||||||
|
**`UploadUtil.upload()` 返回值**(注意:**与字面意思相反**):
|
||||||
|
- `data?.newName` — **原图**文件名(较大)
|
||||||
|
- `data?.zipFileName` — **缩略图/压缩图**文件名(较小)
|
||||||
|
|
||||||
|
**提交时字段映射**(参考事故签证 `AccidentVisaDetailsViewModel`、`IntImpAccidentVisaEditViewModel`):
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
// FileBean 字段含义(约定用途,与 UploadBean 字段名不一致):
|
||||||
|
// - FileBean.url 作缩略图标识(提交到 bean.pic)
|
||||||
|
// - FileBean.originalPic 作原图标识(提交到 bean.originalPic)
|
||||||
|
|
||||||
|
// 上传新图片(注意 UploadBean 字段名的误导性,按实际含义赋值)
|
||||||
|
val data = UploadUtil.upload(fileBean.path).data
|
||||||
|
fileBean.url = data?.zipFileName ?: "" // 缩略图
|
||||||
|
fileBean.originalPic = data?.newName ?: "" // 原图
|
||||||
|
|
||||||
|
// 提交时设置三个字段
|
||||||
|
bean.picNumber = list.size.toString()
|
||||||
|
bean.pic = list.joinToString(",") { MediaUtil.removeUrl(it.url) } // 缩略图
|
||||||
|
bean.originalPic = list.joinToString(",") { MediaUtil.removeUrl(it.originalPic) } // 原图
|
||||||
|
```
|
||||||
|
|
||||||
|
**常见错误**:
|
||||||
|
- ❌ 只传 `images` 或 `originalPic` 单个字段 — 接口不认或数据不完整
|
||||||
|
- ❌ 只取 `newName` 不取 `zipFileName` — 丢失缩略图/原图之一
|
||||||
|
- ❌ 按 `UploadBean` 字段字面含义赋值(`url = newName`)— 会导致 pic/originalPic 内容和字段语义颠倒(缩略图字段装原图、原图字段装缩略图)
|
||||||
|
- ❌ 用 `fileBean.path.startsWith("http")` 判断已上传 — 应该用 `fileBean.url.isNotEmpty()`
|
||||||
|
|
||||||
|
### 编辑页加载已有图片
|
||||||
|
|
||||||
|
从详情接口获取图片后,需要同时解析 `pic`(缩略图)和 `originalPic`(原图),构建完整的 `FileBean`:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
val picList = bean.pic.split(",").filter { it.isNotEmpty() }
|
||||||
|
val originalPicList = bean.originalPic.split(",").filter { it.isNotEmpty() }
|
||||||
|
val images = picList.mapIndexed { index, picUrl ->
|
||||||
|
val originalFile = originalPicList.getOrElse(index) { picUrl }
|
||||||
|
FileBean(
|
||||||
|
path = MediaUtil.fillUrl(picUrl), // 完整URL,用于显示
|
||||||
|
url = picUrl, // 相对路径,提交时用
|
||||||
|
originalPic = MediaUtil.fillUrl(originalFile) // 原图完整URL
|
||||||
|
)
|
||||||
|
}.toMutableList()
|
||||||
|
```
|
||||||
|
|
||||||
|
### 图片加载必须带 Authorization Header
|
||||||
|
|
||||||
|
`/file/getImg/` 接口需要鉴权,Glide 默认不带 token,直接用 `loadImage` BindingAdapter 会 **403 Forbidden**。
|
||||||
|
|
||||||
|
**正确做法** — 在 ViewHolder 中使用 `GlideUrl` + `LazyHeaders`:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
// 缩略图加载(ViewHolder 中)
|
||||||
|
val glideUrl = GlideUrl(
|
||||||
|
bean.path,
|
||||||
|
LazyHeaders.Builder()
|
||||||
|
.addHeader("Authorization", SharedPreferenceUtil.getString(Constant.Share.token))
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
Glide.with(itemView.context).load(glideUrl).into(binding.ivThumbnail)
|
||||||
|
```
|
||||||
|
|
||||||
|
**同时必须去掉 XML 布局中的 `loadImage` 属性**,否则 BindingAdapter 会触发不带 token 的请求覆盖手动加载:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<!-- ❌ 错误:会触发不带 token 的 Glide 请求 -->
|
||||||
|
<ImageView loadImage="@{bean.path}" />
|
||||||
|
|
||||||
|
<!-- ✅ 正确:只保留 id,由 ViewHolder 手动加载 -->
|
||||||
|
<ImageView android:id="@+id/iv_thumbnail" />
|
||||||
|
```
|
||||||
|
|
||||||
|
**大图预览同理** — `PreviewImageViewHolder` 也需要用 `GlideUrl` 带 token 加载网络图片。
|
||||||
|
|
||||||
|
**参考文件**:
|
||||||
|
- 缩略图加载: `module_gjj/.../GjjManifestPicViewHolder.kt`
|
||||||
|
- 大图预览: `module_base/.../PreviewImageViewHolder.kt`
|
||||||
|
- 图片上传提交: `app/.../AccidentVisaDetailsViewModel.kt`
|
||||||
|
- 带 token 的 Glide 加载: `module_mit/.../PictureAdapter.kt`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 开发原则
|
## 开发原则
|
||||||
@@ -842,7 +1504,16 @@ companion object {
|
|||||||
- 标题栏统一用 `title_tool_bar` — 禁止手动编写 Toolbar
|
- 标题栏统一用 `title_tool_bar` — 禁止手动编写 Toolbar
|
||||||
- 优先使用 PadDataLayoutNew 和 PadSearchLayout 组件
|
- 优先使用 PadDataLayoutNew 和 PadSearchLayout 组件
|
||||||
- 在每个页面布局时,如有截图,务必尽可能还原图片上的页面设计,而不是推测假想。如有困难一律要询问,禁止自己想象
|
- 在每个页面布局时,如有截图,务必尽可能还原图片上的页面设计,而不是推测假想。如有困难一律要询问,禁止自己想象
|
||||||
|
- 工具栏图标尺寸规范:
|
||||||
|
- `img_search` 36dp + padding 2dp
|
||||||
|
- `img_add` 40dp 无 padding(使用 `drawable/img_add.xml` 矢量图,`drawable-xhdpi/img_add.png` 已废弃删除)
|
||||||
|
- `img_delete` 36dp + padding 4dp
|
||||||
|
- `ic_new_expand`(全部展开/收起)36dp + padding 4dp
|
||||||
|
- **图标之间间距统一 `marginStart=16dp`**(禁止使用 8dp,会导致视觉过近)
|
||||||
- 常用资源: `bg_white_radius_8`、`colorPrimary`、`text_normal`、`text_gray`、`color_bottom_layout`
|
- 常用资源: `bg_white_radius_8`、`colorPrimary`、`text_normal`、`text_gray`、`color_bottom_layout`
|
||||||
|
- **双形态适配:逻辑与 UI 严格分离** — 手机版只重写布局,业务逻辑一律复用现有 ViewModel / ViewHolder;纯 UI 交互(Tab 切换、弹层显隐)写在 Activity,不下沉到 ViewModel
|
||||||
|
- **禁止用不同文件名切换布局** — 手机/平板布局必须同名 + 资源限定符,否则 `ClassCastException`(详见「5.5 寸手持端双形态适配规范」)
|
||||||
|
- 手机版资源统一使用 `phone_*` 颜色与 `bg_phone_*` drawable,禁止直接写死色值
|
||||||
|
|
||||||
### 环境配置
|
### 环境配置
|
||||||
|
|
||||||
@@ -856,4 +1527,16 @@ companion object {
|
|||||||
2. 资源引用错误 → 检查 drawable/color/string 是否存在
|
2. 资源引用错误 → 检查 drawable/color/string 是否存在
|
||||||
3. DataBinding 错误 → 检查 import、枚举值、View 类导入
|
3. DataBinding 错误 → 检查 import、枚举值、View 类导入
|
||||||
4. suspend function 错误 → 在 `viewModelScope.launch` 中调用
|
4. suspend function 错误 → 在 `viewModelScope.launch` 中调用
|
||||||
5. 仍有问题 → `./gradlew clean` 后重新构建
|
5. 双形态布局问题 → 查「常见编译错误速查」中 3 条布局变体相关条目;可用 `DeviceUtil.describe()` 打日志确认当前形态
|
||||||
|
6. 仍有问题 → `./gradlew clean` 后重新构建
|
||||||
|
|
||||||
|
### 双端验证命令
|
||||||
|
|
||||||
|
```bash
|
||||||
|
~/Library/Android/sdk/emulator/emulator -list-avds # 可用:Medium_Phone_API_36.1(手机)、Aerologic_Tablet(平板)
|
||||||
|
adb -s <设备> shell wm size && adb -s <设备> shell wm density # 确认屏幕参数
|
||||||
|
adb -s <设备> logcat -d -s BaseActivity:D # 查看形态识别结果 PHONE(sw=411dp) / TABLET(sw=800dp)
|
||||||
|
adb -s <设备> exec-out screencap -p > /tmp/shot.png # 截图比对
|
||||||
|
```
|
||||||
|
|
||||||
|
> 改动 `BaseActivity` / `BaseBindingActivity` / 公共组件后,**必须在平板上回归**,确认现有平板版行为不变。
|
||||||
|
|||||||
627
README.md
627
README.md
@@ -1,301 +1,326 @@
|
|||||||
# AirLogistics - 航空物流信息管理系统
|
# AirLogistics - 航空物流信息管理系统
|
||||||
|
|
||||||
一款专业的航空物流管理Android应用,为机场货运站提供全流程数字化解决方案,涵盖国内外货物进出港、仓储管理、车辆调度等核心业务。
|
一款专业的航空物流管理Android应用,为机场货运站提供全流程数字化解决方案,涵盖国内外货物进出港、仓储管理、车辆调度等核心业务。
|
||||||
|
|
||||||
## 📋 项目信息
|
## 📋 项目信息
|
||||||
|
|
||||||
- **版本**: 1.7.9 (versionCode 79)
|
- **版本**: 1.7.9 (versionCode 79)
|
||||||
- **包名**: com.lukouguoji.aerologic
|
- **包名**: com.lukouguoji.aerologic
|
||||||
- **最低支持**: Android 7.0 (API 24)
|
- **最低支持**: Android 7.0 (API 24)
|
||||||
- **目标版本**: Android 10 (API 30)
|
- **目标版本**: Android 10 (API 30)
|
||||||
- **开发语言**: Kotlin + Java
|
- **开发语言**: Kotlin + Java
|
||||||
- **架构模式**: MVVM + 组件化
|
- **架构模式**: MVVM + 组件化
|
||||||
|
|
||||||
## 🏗️ 架构设计
|
## 🏗️ 架构设计
|
||||||
|
|
||||||
### 核心架构
|
### 核心架构
|
||||||
|
|
||||||
```
|
```
|
||||||
┌─────────────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────────────┐
|
||||||
│ 应用层 (App) │
|
│ 应用层 (App) │
|
||||||
├─────────────────────────────────────────────────────┤
|
├─────────────────────────────────────────────────────┤
|
||||||
│ 国内出港 │ 国内进港 │ 国际出港 │ 国际进港 │
|
│ 国内出港 │ 国内进港 │ 国际出港 │ 国际进港 │
|
||||||
│ (GNC) │ (GNJ) │ (GJC) │ (GJJ) │
|
│ (GNC) │ (GNJ) │ (GJC) │ (GJJ) │
|
||||||
├─────────────────────────────────────────────────────┤
|
├─────────────────────────────────────────────────────┤
|
||||||
│ 基础服务层 (module_base) │
|
│ 基础服务层 (module_base) │
|
||||||
│ • MVVM基类 • 网络框架 • UI组件 • 工具类 │
|
│ • MVVM基类 • 网络框架 • UI组件 • 工具类 │
|
||||||
├─────────────────────────────────────────────────────┤
|
├─────────────────────────────────────────────────────┤
|
||||||
│ 蓝牙打印 │ 图表库 │ 航班管理 │ 货物追踪 │
|
│ 蓝牙打印 │ 图表库 │ 航班管理 │ 货物追踪 │
|
||||||
│ (Printer) │ (Chart) │ (Hangban) │ (Cargo) │
|
│ (Printer) │ (Chart) │ (Hangban) │ (Cargo) │
|
||||||
└─────────────────────────────────────────────────────┘
|
└─────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
### MVVM模式
|
### MVVM模式
|
||||||
|
|
||||||
- **View层**: Activity/Fragment + DataBinding
|
- **View层**: Activity/Fragment + DataBinding
|
||||||
- **ViewModel层**: BaseViewModel / BasePageViewModel
|
- **ViewModel层**: BaseViewModel / BasePageViewModel
|
||||||
- **Model层**: Repository + Retrofit API
|
- **Model层**: Repository + Retrofit API
|
||||||
- **数据流**: 协程(Coroutines) + Flow
|
- **数据流**: 协程(Coroutines) + Flow
|
||||||
|
|
||||||
### 组件化架构
|
### 组件化架构
|
||||||
|
|
||||||
- **模块独立**: 通过`isBuildModule`参数控制模块独立运行或集成
|
- **模块独立**: 通过`isBuildModule`参数控制模块独立运行或集成
|
||||||
- **路由通信**: ARouter实现模块间页面跳转和通信
|
- **路由通信**: ARouter实现模块间页面跳转和通信
|
||||||
- **事件总线**: FlowBus(基于Flow) + EventBus
|
- **事件总线**: FlowBus(基于Flow) + EventBus
|
||||||
- **依赖注入**: 基于ServiceLoader的服务发现机制
|
- **依赖注入**: 基于ServiceLoader的服务发现机制
|
||||||
|
|
||||||
### 基础设施
|
### 基础设施
|
||||||
|
|
||||||
#### 核心基类
|
#### 核心基类
|
||||||
- `BaseActivity`: 协程支持、Loading管理、扫码功能、键盘控制
|
- `BaseActivity`: 协程支持、Loading管理、扫码功能、键盘控制
|
||||||
- `BaseBindingActivity`: DataBinding自动绑定、ViewModel生命周期管理
|
- `BaseBindingActivity`: DataBinding自动绑定、ViewModel生命周期管理
|
||||||
- `BaseViewModel`: Loading管理、Activity结果处理
|
- `BaseViewModel`: Loading管理、Activity结果处理
|
||||||
- `BasePageViewModel`: 分页列表专用,集成PageModel自动处理分页
|
- `BasePageViewModel`: 分页列表专用,集成PageModel自动处理分页
|
||||||
- `CommonAdapter + BaseViewHolder`: 统一列表适配器封装
|
- `CommonAdapter + BaseViewHolder`: 统一列表适配器封装
|
||||||
|
|
||||||
#### 网络请求层
|
#### 网络请求层
|
||||||
- **ServiceCreator**: Retrofit实例创建,动态IP配置
|
- **ServiceCreator**: Retrofit实例创建,动态IP配置
|
||||||
- **拦截器**: 自动添加Token、时间戳,统一错误处理
|
- **拦截器**: 自动添加Token、时间戳,统一错误处理
|
||||||
- **扩展函数**:
|
- **扩展函数**:
|
||||||
- `launchCollect`: 无Loading的后台请求
|
- `launchCollect`: 无Loading的后台请求
|
||||||
- `launchLoadingCollect`: 带Loading的关键操作
|
- `launchLoadingCollect`: 带Loading的关键操作
|
||||||
- `toRequestBody`: Map/Bean自动转JSON
|
- `toRequestBody`: Map/Bean自动转JSON
|
||||||
|
|
||||||
#### 统一UI组件
|
#### 统一UI组件
|
||||||
- **PadSearchLayout**: 搜索输入框组合控件(支持文本/数字/下拉/日期)
|
- **PadSearchLayout**: 搜索输入框组合控件(支持文本/数字/下拉/日期)
|
||||||
- **PadDataLayout**: 数据展示/编辑组合控件(标题对齐)
|
- **PadDataLayout**: 数据展示/编辑组合控件(标题对齐)
|
||||||
- **StatusView**: 状态栏占位View
|
- **StatusView**: 状态栏占位View
|
||||||
- **统一样式**: 颜色、字体、圆角、间距的全局规范
|
- **统一样式**: 颜色、字体、圆角、间距的全局规范
|
||||||
|
|
||||||
## 🚀 技术栈
|
#### 双形态适配(平板 / 手机)
|
||||||
|
同时支持 **10 寸平板横屏** 与 **5.5 寸手机竖屏**,业务逻辑层完全复用,只重写布局。
|
||||||
### 核心框架
|
|
||||||
- **Kotlin**: 1.6.21 + Coroutines 1.6.0
|
- **DeviceUtil**: 设备形态判定(按 `smallestScreenWidthDp >= 600` 区分),提供调试用强制形态开关
|
||||||
- **Jetpack**: ViewModel、LiveData、DataBinding
|
- **布局自动切换**: 通过 Android 资源限定符实现,`res/layout-sw600dp/`(平板)与 `res/layout/`(手机)下放**同名**布局,DataBinding 生成同一个 Binding 类,Activity / ViewModel / ViewHolder 无需任何设备判断
|
||||||
- **网络**: Retrofit 2.6.1 + OkHttp 3.12.12
|
- **屏幕方向**: Manifest 统一写 `android:screenOrientation="unspecified"`,系统按设备当前物理方向建窗口,`BaseActivity.applyDeviceOrientation()` 再按形态锁定(手机竖屏 / 平板横屏),两端均无「先横屏再转竖屏」闪屏。**不要改用资源引用**——系统解析 Manifest 不套用限定符,会导致平板取到竖屏值并触发 AutoSize 放大
|
||||||
- **JSON**: FastJSON 1.2.73 + Gson 2.10.1
|
- **AutoSize 基准**: 横屏 1152×720 / 手机竖屏 390×844 / 平板竖屏 720×1280
|
||||||
|
- **手机端资源**: `phone_*` 配色 + `bg_phone_*` drawable + 手机版公共标题栏
|
||||||
### UI相关
|
|
||||||
- **Material Design**: Material Components
|
> ⚠️ 禁止用「不同文件名 + 代码判断」切换布局,会生成两个 Binding 类导致运行时 `ClassCastException`。
|
||||||
- **屏幕适配**: AutoSize 1.2.+ (横屏1152dp × 720dp)
|
> 详见 [`documents/5.5寸手持端适配技术方案.md`](documents/5.5寸手持端适配技术方案.md) 与 `CLAUDE.md` 对应章节。
|
||||||
- **下拉刷新**: SmartRefreshLayout 2.0.3
|
|
||||||
- **图表**: MPAndroidChart (定制版)
|
## 🚀 技术栈
|
||||||
- **弹窗**: XPopup 2.9.19
|
|
||||||
- **图片**: Glide 4.15.1 + PictureSelector v3.11.2
|
### 核心框架
|
||||||
|
- **Kotlin**: 1.6.21 + Coroutines 1.6.0
|
||||||
### 功能组件
|
- **Jetpack**: ViewModel、LiveData、DataBinding
|
||||||
- **路由**: ARouter 1.5.2
|
- **网络**: Retrofit 2.6.1 + OkHttp 3.12.12
|
||||||
- **扫码**: ZXing 2.2.9
|
- **JSON**: FastJSON 1.2.73 + Gson 2.10.1
|
||||||
- **权限**: AndPermission 2.0.2
|
|
||||||
- **打印**: 佳博SDK 2.0.4
|
### UI相关
|
||||||
- **日志**: Timber 5.0.1
|
- **Material Design**: Material Components
|
||||||
|
- **屏幕适配**: AutoSize 1.2.+ (横屏1152dp × 720dp)
|
||||||
## 💼 核心业务模块
|
- **下拉刷新**: SmartRefreshLayout 2.0.3
|
||||||
|
- **图表**: MPAndroidChart (定制版)
|
||||||
### 国内出港 (module_gnc)
|
- **弹窗**: XPopup 2.9.19
|
||||||
货物收运、复磅称重、转运管理、出库装机、仓库管理、数据统计
|
- **图片**: Glide 4.15.1 + PictureSelector v3.11.2
|
||||||
|
|
||||||
### 国内进港 (module_gnj)
|
### 功能组件
|
||||||
舱单管理、卸机入库、出库提货、移库管理、货物交接、实时查询
|
- **路由**: ARouter 1.5.2
|
||||||
|
- **扫码**: ZXing 2.2.9
|
||||||
### 国际出港 (module_gjc)
|
- **权限**: AndPermission 2.0.2
|
||||||
国际货物收运、板箱组装、ULD容器管理、复磅称重、仓储移库
|
- **打印**: 佳博SDK 2.0.4
|
||||||
|
- **日志**: Timber 5.0.1
|
||||||
### 国际进港 (module_gjj)
|
|
||||||
国际舱单管理、报文解析、理货管理、出库操作、货物交接
|
## 💼 核心业务模块
|
||||||
|
|
||||||
### 支持模块
|
### 国内出港 (module_gnc)
|
||||||
- **航班管理** (module_hangban): 航班查询、航班统计
|
货物收运、复磅称重、转运管理、出库装机、仓库管理、数据统计
|
||||||
- **货物追踪** (module_cargo): 货物状态追踪、运输日志
|
|
||||||
- **监装监卸** (module_mit): 监装监卸管理
|
### 国内进港 (module_gnj)
|
||||||
- **PDA功能** (module_p): PDA专用功能
|
舱单管理、卸机入库、出库提货、移库管理、货物交接、实时查询
|
||||||
- **蓝牙打印** (Printer): 佳博打印机SDK集成
|
|
||||||
|
### 国际出港 (module_gjc)
|
||||||
## 📦 项目结构
|
国际货物收运、板箱组装、ULD容器管理、复磅称重、仓储移库
|
||||||
|
|
||||||
```
|
### 国际进港 (module_gjj)
|
||||||
aerologic-app/
|
国际舱单管理、报文解析、理货管理、出库操作、货物交接
|
||||||
├── app/ # 应用壳层,整合所有业务模块
|
|
||||||
├── module_base/ # 核心基础库,提供所有通用能力
|
### 支持模块
|
||||||
│ ├── base/ # MVVM基类
|
- **航班管理** (module_hangban): 航班查询、航班统计
|
||||||
│ ├── http/ # 网络请求框架
|
- **货物追踪** (module_cargo): 货物状态追踪、运输日志
|
||||||
│ ├── ui/weight/ # 统一UI组件
|
- **监装监卸** (module_mit): 监装监卸管理
|
||||||
│ ├── ktx/ # Kotlin扩展函数
|
- **PDA功能** (module_p): PDA专用功能
|
||||||
│ ├── bean/ # 数据模型
|
- **蓝牙打印** (Printer): 佳博打印机SDK集成
|
||||||
│ └── router/ # ARouter路由常量
|
|
||||||
├── module_gnc/ # 国内出港业务
|
## 📦 项目结构
|
||||||
├── module_gnj/ # 国内进港业务
|
|
||||||
├── module_gjc/ # 国际出港业务
|
```
|
||||||
├── module_gjj/ # 国际进港业务
|
aerologic-app/
|
||||||
├── module_hangban/ # 航班查询管理
|
├── app/ # 应用壳层,整合所有业务模块
|
||||||
├── module_cargo/ # 货物追踪查询
|
├── module_base/ # 核心基础库,提供所有通用能力
|
||||||
├── module_mit/ # 监装监卸管理
|
│ ├── base/ # MVVM基类
|
||||||
├── module_p/ # PDA专用功能
|
│ ├── http/ # 网络请求框架
|
||||||
├── Printer/ # 蓝牙打印模块
|
│ ├── ui/weight/ # 统一UI组件
|
||||||
├── MPChartLib/ # 定制图表库
|
│ ├── ktx/ # Kotlin扩展函数
|
||||||
├── CLAUDE.md # 详细开发指南
|
│ ├── bean/ # 数据模型
|
||||||
└── README.md # 项目说明文档
|
│ ├── util/ # 工具类(含 DeviceUtil 设备形态判定)
|
||||||
```
|
│ └── router/ # ARouter路由常量
|
||||||
|
├── module_gnc/ # 国内出港业务
|
||||||
## 🚀 快速开始
|
├── module_gnj/ # 国内进港业务
|
||||||
|
├── module_gjc/ # 国际出港业务
|
||||||
### 环境要求
|
├── module_gjj/ # 国际进港业务
|
||||||
|
├── module_hangban/ # 航班查询管理
|
||||||
- **IDE**: Android Studio Arctic Fox (2020.3.1) 或更高版本
|
├── module_cargo/ # 货物追踪查询
|
||||||
- **JDK**: 1.8
|
├── module_mit/ # 监装监卸管理
|
||||||
- **Gradle**: 7.3.3
|
├── module_p/ # PDA专用功能
|
||||||
- **Kotlin**: 1.6.21
|
├── Printer/ # 蓝牙打印模块
|
||||||
|
├── MPChartLib/ # 定制图表库
|
||||||
### 依赖配置
|
├── documents/ # 设计稿、报价单、技术方案文档
|
||||||
|
├── CLAUDE.md # 详细开发指南
|
||||||
如遇依赖下载问题:
|
└── README.md # 项目说明文档
|
||||||
|
```
|
||||||
1. 下载 gradle-7.3.3-bin.zip
|
|
||||||
- 百度网盘: https://pan.baidu.com/s/18wsuGRlNxjMYbxLhBH9yeg
|
各业务模块内的布局按设备形态分目录存放:
|
||||||
- 提取码: 1029
|
|
||||||
|
```
|
||||||
2. 配置Gradle:
|
module_gjc/src/main/res/
|
||||||
- Settings → Build, Execution, Deployment → Build Tools → Gradle
|
├── layout/ # 手机布局(5.5 寸竖屏,兜底)
|
||||||
- 解压并替换到 "Gradle user home" 目录
|
└── layout-sw600dp/ # 平板布局(10 寸横屏)
|
||||||
|
```
|
||||||
### 构建项目
|
|
||||||
|
> 两目录下**同名**的布局是同一布局的资源变体,系统按屏幕最小宽度自动选择。
|
||||||
```bash
|
> 尚未适配手机的页面,布局保留在 `layout/` 即可(两端共用),支持渐进式适配。
|
||||||
# 克隆项目
|
|
||||||
git clone [repository-url]
|
## 🚀 快速开始
|
||||||
cd aerologic-app
|
|
||||||
|
### 环境要求
|
||||||
# 清理构建
|
|
||||||
./gradlew clean
|
- **IDE**: Android Studio Arctic Fox (2020.3.1) 或更高版本
|
||||||
|
- **JDK**: 1.8
|
||||||
# 构建Debug版本
|
- **Gradle**: 7.3.3
|
||||||
./gradlew assembleDebug
|
- **Kotlin**: 1.6.21
|
||||||
|
|
||||||
# 构建Release版本(已签名)
|
### 依赖配置
|
||||||
./gradlew assembleRelease
|
|
||||||
|
如遇依赖下载问题:
|
||||||
# 安装到设备
|
|
||||||
./gradlew installDebug
|
1. 下载 gradle-7.3.3-bin.zip
|
||||||
```
|
- 百度网盘: https://pan.baidu.com/s/18wsuGRlNxjMYbxLhBH9yeg
|
||||||
|
- 提取码: 1029
|
||||||
### 组件化开发模式
|
|
||||||
|
2. 配置Gradle:
|
||||||
支持模块独立运行调试:
|
- Settings → Build, Execution, Deployment → Build Tools → Gradle
|
||||||
|
- 解压并替换到 "Gradle user home" 目录
|
||||||
1. 编辑 `gradle.properties`
|
|
||||||
2. 设置 `isBuildModule=true` (独立模块) 或 `false` (集成模式)
|
### 构建项目
|
||||||
3. Sync项目并运行对应模块
|
|
||||||
|
```bash
|
||||||
## ⚙️ 配置说明
|
# 克隆项目
|
||||||
|
git clone [repository-url]
|
||||||
### 网络配置
|
cd aerologic-app
|
||||||
|
|
||||||
服务器地址配置位置:
|
# 清理构建
|
||||||
- **文件**: `module_base/src/main/res/values/strings.xml`
|
./gradlew clean
|
||||||
- **主服务器**: `system_url_inner`
|
|
||||||
- **地磅服务器**: `weight_url`
|
# 构建Debug版本
|
||||||
- **运行时**: 可通过SharedPreferences动态修改IP地址
|
./gradlew assembleDebug
|
||||||
|
|
||||||
### 签名配置
|
# 构建Release版本(已签名)
|
||||||
|
./gradlew assembleRelease
|
||||||
Release版本签名信息:
|
|
||||||
- **KeyStore**: `key.jks` (项目根目录)
|
# 安装到设备
|
||||||
- **密码**: storePassword/keyPassword均为 `123321`
|
./gradlew installDebug
|
||||||
- **别名**: `key`
|
```
|
||||||
|
|
||||||
### 网络安全
|
### 组件化开发模式
|
||||||
|
|
||||||
- **超时时间**: 30秒(连接/读取/写入)
|
支持模块独立运行调试:
|
||||||
- **认证方式**: Bearer Token(自动添加)
|
|
||||||
- **HTTP支持**: 配置在 `res/xml/network_security_config.xml`
|
1. 编辑 `gradle.properties`
|
||||||
|
2. 设置 `isBuildModule=true` (独立模块) 或 `false` (集成模式)
|
||||||
## 📚 开发文档
|
3. Sync项目并运行对应模块
|
||||||
|
|
||||||
详细的开发指南请参考 **[CLAUDE.md](./CLAUDE.md)**,包含:
|
## ⚙️ 配置说明
|
||||||
|
|
||||||
- ✅ 完整的架构详解(基类、网络、UI组件)
|
### 网络配置
|
||||||
- ✅ 标准开发模板(Activity、ViewModel、ViewHolder)
|
|
||||||
- ✅ 实际业务示例(列表页、详情页、编辑页)
|
服务器地址配置位置:
|
||||||
- ✅ 开发检查清单(7步列表页、4步详情页、5步编辑页)
|
- **文件**: `module_base/src/main/res/values/strings.xml`
|
||||||
- ✅ DataBinding适配器(10+种)
|
- **主服务器**: `system_url_inner`
|
||||||
- ✅ Kotlin扩展函数(20+种)
|
- **地磅服务器**: `weight_url`
|
||||||
- ✅ 常见业务场景实现
|
- **运行时**: 可通过SharedPreferences动态修改IP地址
|
||||||
|
|
||||||
## 🔄 Git工作流
|
### 签名配置
|
||||||
|
|
||||||
### 分支策略
|
Release版本签名信息:
|
||||||
|
- **KeyStore**: `key.jks` (项目根目录)
|
||||||
- **develop**: 主开发分支
|
- **密码**: storePassword/keyPassword均为 `123321`
|
||||||
- **feature/xxx**: 功能开发分支
|
- **别名**: `key`
|
||||||
- **release/x.x.x**: 发布分支
|
|
||||||
- **hotfix/xxx**: 紧急修复分支
|
### 网络安全
|
||||||
|
|
||||||
### 当前分支
|
- **超时时间**: 30秒(连接/读取/写入)
|
||||||
|
- **认证方式**: Bearer Token(自动添加)
|
||||||
- **开发分支**: feature/hefei
|
- **HTTP支持**: 配置在 `res/xml/network_security_config.xml`
|
||||||
- **主分支**: develop(用于PR)
|
|
||||||
|
## 📚 开发文档
|
||||||
### 提交规范
|
|
||||||
|
详细的开发指南请参考 **[CLAUDE.md](./CLAUDE.md)**,包含:
|
||||||
提交前确保:
|
|
||||||
- ✅ 代码编译通过
|
- ✅ 完整的架构详解(基类、网络、UI组件)
|
||||||
- ✅ 无明显错误和警告
|
- ✅ 标准开发模板(Activity、ViewModel、ViewHolder)
|
||||||
- ✅ 遵循项目代码规范
|
- ✅ 实际业务示例(列表页、详情页、编辑页)
|
||||||
|
- ✅ 开发检查清单(7步列表页、4步详情页、5步编辑页)
|
||||||
## 📋 开发原则
|
- ✅ DataBinding适配器(10+种)
|
||||||
|
- ✅ Kotlin扩展函数(20+种)
|
||||||
1. ✅ **优先使用现有基类和封装**,避免重复造轮子
|
- ✅ 常见业务场景实现
|
||||||
2. ✅ **充分利用PadDataLayout和PadSearchLayout组件**,保证UI一致性
|
|
||||||
3. ✅ **遵循统一的命名和目录组织规范**
|
## 🔄 Git工作流
|
||||||
4. ✅ **使用DataBinding简化代码**,减少findViewById
|
|
||||||
5. ✅ **利用扩展函数处理通用逻辑**(Toast、Dialog、权限等)
|
### 分支策略
|
||||||
6. ✅ **保持架构一致性**,新增业务参考现有模块
|
|
||||||
|
- **develop**: 主开发分支
|
||||||
## 🔐 特性亮点
|
- **feature/xxx**: 功能开发分支
|
||||||
|
- **release/x.x.x**: 发布分支
|
||||||
### 1. 高度组件化
|
- **hotfix/xxx**: 紧急修复分支
|
||||||
- 业务模块完全解耦,支持独立开发、测试、发布
|
|
||||||
- 通过ARouter实现模块间通信,无需直接依赖
|
### 当前分支
|
||||||
|
|
||||||
### 2. 统一UI规范
|
- **开发分支**: feature/hefei
|
||||||
- 自定义PadSearchLayout、PadDataLayout组合控件
|
- **主分支**: develop(用于PR)
|
||||||
- 全局统一的颜色、字体、圆角、间距规范
|
|
||||||
- 丰富的DataBinding适配器,简化UI开发
|
### 提交规范
|
||||||
|
|
||||||
### 3. 高效网络框架
|
提交前确保:
|
||||||
- 协程+Flow的现代化异步方案
|
- ✅ 代码编译通过
|
||||||
- 统一的请求封装(launchCollect/launchLoadingCollect)
|
- ✅ 无明显错误和警告
|
||||||
- 自动的Loading管理和错误处理
|
- ✅ 遵循项目代码规范
|
||||||
|
|
||||||
### 4. 完善的基础设施
|
## 📋 开发原则
|
||||||
- BaseActivity提供扫码、Loading、键盘控制等通用能力
|
|
||||||
- BasePageViewModel自动处理分页逻辑
|
1. ✅ **优先使用现有基类和封装**,避免重复造轮子
|
||||||
- CommonAdapter统一列表适配器管理
|
2. ✅ **充分利用PadDataLayout和PadSearchLayout组件**,保证UI一致性
|
||||||
|
3. ✅ **遵循统一的命名和目录组织规范**
|
||||||
### 5. 丰富的工具扩展
|
4. ✅ **使用DataBinding简化代码**,减少findViewById
|
||||||
- 20+ Kotlin扩展函数(Toast、Dialog、JSON、日期等)
|
5. ✅ **利用扩展函数处理通用逻辑**(Toast、Dialog、权限等)
|
||||||
- 10+ DataBinding适配器(图片加载、可见性、Shape等)
|
6. ✅ **保持架构一致性**,新增业务参考现有模块
|
||||||
- 完整的业务开发模板和检查清单
|
|
||||||
|
## 🔐 特性亮点
|
||||||
## 🛠️ 技术特点
|
|
||||||
|
### 1. 高度组件化
|
||||||
- **响应式编程**: Kotlin Coroutines + Flow
|
- 业务模块完全解耦,支持独立开发、测试、发布
|
||||||
- **声明式UI**: DataBinding双向绑定
|
- 通过ARouter实现模块间通信,无需直接依赖
|
||||||
- **函数式编程**: Kotlin扩展函数和高阶函数
|
|
||||||
- **依赖注入**: 基于ServiceLoader的轻量级方案
|
### 2. 统一UI规范
|
||||||
- **模块化路由**: ARouter组件化通信
|
- 自定义PadSearchLayout、PadDataLayout组合控件
|
||||||
- **横屏适配**: AutoSize自动适配1152dp × 720dp
|
- 全局统一的颜色、字体、圆角、间距规范
|
||||||
- **蓝牙打印**: 佳博打印机SDK深度集成
|
- 丰富的DataBinding适配器,简化UI开发
|
||||||
- **二维码扫描**: ZXing高性能扫码
|
|
||||||
|
### 3. 高效网络框架
|
||||||
## 📄 许可证
|
- 协程+Flow的现代化异步方案
|
||||||
|
- 统一的请求封装(launchCollect/launchLoadingCollect)
|
||||||
本项目为企业内部系统,版权归所属公司所有。
|
- 自动的Loading管理和错误处理
|
||||||
|
|
||||||
## ⚠️ 注意事项
|
### 4. 完善的基础设施
|
||||||
|
- BaseActivity提供扫码、Loading、键盘控制等通用能力
|
||||||
**重要**: 本项目包含敏感业务信息和配置,仅供授权人员使用,严禁外传。
|
- BasePageViewModel自动处理分页逻辑
|
||||||
|
- CommonAdapter统一列表适配器管理
|
||||||
---
|
|
||||||
|
### 5. 丰富的工具扩展
|
||||||
**文档维护**: 本README提供项目概览和架构信息,详细开发指南请参考 [CLAUDE.md](./CLAUDE.md)
|
- 20+ Kotlin扩展函数(Toast、Dialog、JSON、日期等)
|
||||||
|
- 10+ DataBinding适配器(图片加载、可见性、Shape等)
|
||||||
|
- 完整的业务开发模板和检查清单
|
||||||
|
|
||||||
|
## 🛠️ 技术特点
|
||||||
|
|
||||||
|
- **响应式编程**: Kotlin Coroutines + Flow
|
||||||
|
- **声明式UI**: DataBinding双向绑定
|
||||||
|
- **函数式编程**: Kotlin扩展函数和高阶函数
|
||||||
|
- **依赖注入**: 基于ServiceLoader的轻量级方案
|
||||||
|
- **模块化路由**: ARouter组件化通信
|
||||||
|
- **横屏适配**: AutoSize自动适配1152dp × 720dp
|
||||||
|
- **蓝牙打印**: 佳博打印机SDK深度集成
|
||||||
|
- **二维码扫描**: ZXing高性能扫码
|
||||||
|
|
||||||
|
## 📄 许可证
|
||||||
|
|
||||||
|
本项目为企业内部系统,版权归所属公司所有。
|
||||||
|
|
||||||
|
## ⚠️ 注意事项
|
||||||
|
|
||||||
|
**重要**: 本项目包含敏感业务信息和配置,仅供授权人员使用,严禁外传。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**文档维护**: 本README提供项目概览和架构信息,详细开发指南请参考 [CLAUDE.md](./CLAUDE.md)
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ android {
|
|||||||
applicationId "com.lukouguoji.aerologic"
|
applicationId "com.lukouguoji.aerologic"
|
||||||
minSdkVersion 24
|
minSdkVersion 24
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
versionCode 85
|
versionCode 88
|
||||||
versionName "1.8.5"
|
versionName "1.8.8"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
|
|||||||
180
app/src/debug/AndroidManifest.xml
Normal file
180
app/src/debug/AndroidManifest.xml
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
仅 Debug 构建生效的 Manifest 覆盖(不会合并进 Release 包)
|
||||||
|
|
||||||
|
用途:手机版布局适配调试期间,允许通过 adb 直接拉起指定页面,
|
||||||
|
免去每次都要登录并从首页菜单逐级点入。
|
||||||
|
|
||||||
|
adb shell am start -n com.lukouguoji.aerologic/com.lukouguoji.gjc.page.move.IntExpMoveActivity
|
||||||
|
|
||||||
|
注意:这里只放调试便利配置,正式包的 exported 仍为 app/src/main/AndroidManifest.xml 中的 false。
|
||||||
|
-->
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<application>
|
||||||
|
|
||||||
|
<!-- 出港移库(手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.gjc.page.move.IntExpMoveActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 出港移库-运单详情(手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.gjc.page.move.IntExpMoveDetailActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 出库交接(手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.gjc.activity.IntExpOutHandoverActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 出库交接-板箱详情(手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.gjc.activity.IntExpOutHandoverDetailActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- ULD管理(手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.aerologic.page.uld.list.UldListActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- ULD新增/修改/详情(手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.aerologic.page.uld.edit.UldEditActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 出港待计重(手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.gjc.activity.GjcWeighingListActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 出港计重-开始计重(手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.gjc.activity.GjcWeighingStartActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 出港计重-计重记录(手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.gjc.activity.GjcWeighingRecordListActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 出港计重-计重明细(手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.gjc.activity.GjcWeighingRecordDetailsActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 出港计重-运单详情(手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.gjc.activity.GjcWeighingWbDetailActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 出港运抵(手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.gjc.activity.IntExpArriveActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 出港运抵-分单明细(手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.gjc.activity.IntExpArriveSubOrderActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 出港运抵-回执内容(手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.gjc.activity.IntExpArriveReceiptActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 出港运抵-补充信息(手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.gjc.activity.IntExpArriveSupplementActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 出港查询(手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.gjc.activity.GjcQueryActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 出港查询-详情(手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.gjc.activity.GjcQueryDetailsActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 运单追踪/操作日志详情(手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.aerologic.page.log.detail.LogDetailActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 出港仓库(手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.gjc.activity.IntExpStorageUseActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 进港仓库(手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.gjj.activity.IntImpStorageUseActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 进港查询-详情(手机版适配验证页,进港仓库卡片点击进入) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.gjj.activity.IntImpQueryDetailsActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 提取出库(手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.gjj.activity.IntImpPickUpDLVActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 提取出库-运单详情(手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.gjj.activity.IntImpPickUpDetailActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 进港查询(手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.gjj.activity.IntImpQueryActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 进港移库(国内进港,手机版适配验证页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.aerologic.page.gnj.move.stash.list.GnjMoveStashListActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 进港移库-运单详情(手机版专属页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.aerologic.page.gnj.move.stash.detail.GnjMoveStashDetailActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
<!-- 进港移库-拍照上传(手机版专属页) -->
|
||||||
|
<activity
|
||||||
|
android:name="com.lukouguoji.aerologic.page.gnj.move.stash.photo.GnjMoveStashPhotoActivity"
|
||||||
|
android:exported="true"
|
||||||
|
tools:replace="android:exported" />
|
||||||
|
|
||||||
|
</application>
|
||||||
|
</manifest>
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -75,23 +75,18 @@ class AccidentVisaDetailsViewModel : BaseViewModel(), IOnItemClickListener {
|
|||||||
onSuccess = {
|
onSuccess = {
|
||||||
dataBean.value = it.data ?: AccidentVisaBean()
|
dataBean.value = it.data ?: AccidentVisaBean()
|
||||||
|
|
||||||
// 渲染图片
|
// 渲染图片:pic 存缩略图文件名,originalPic 存原图文件名
|
||||||
val list = dataBean.value!!.pic.split(",")
|
val picList = dataBean.value!!.pic.split(",").filter { it.isNotEmpty() }
|
||||||
.filter { url -> url.isNotEmpty() }
|
val originalPicList = dataBean.value!!.originalPic.split(",").filter { it.isNotEmpty() }
|
||||||
.map { url ->
|
val list = picList.mapIndexed { index, picFilename ->
|
||||||
FileBean(MediaUtil.fillUrl(url), url)
|
val originalFilename = originalPicList.getOrElse(index) { picFilename }
|
||||||
}
|
FileBean(
|
||||||
val zipList = dataBean.value!!.originalPic.split(",")
|
path = MediaUtil.fillUrl(picFilename),
|
||||||
.filter { url -> url.isNotEmpty() }
|
url = picFilename,
|
||||||
.map { url ->
|
originalPic = MediaUtil.fillUrl(originalFilename)
|
||||||
FileBean(MediaUtil.fillUrl(url))
|
)
|
||||||
}
|
|
||||||
for ((index, fileBean) in list.withIndex()) {
|
|
||||||
val originalPic = zipList.get(index).path
|
|
||||||
list.get(index).originalPic = originalPic
|
|
||||||
}
|
}
|
||||||
rv?.commonAdapter()
|
rv?.commonAdapter()?.loadMore(list)
|
||||||
?.loadMore(list)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,8 +105,10 @@ class AccidentVisaDetailsViewModel : BaseViewModel(), IOnItemClickListener {
|
|||||||
.filter { it.path.isNotEmpty() && it.url.isEmpty() }
|
.filter { it.path.isNotEmpty() && it.url.isEmpty() }
|
||||||
.onEach {
|
.onEach {
|
||||||
val data = UploadUtil.upload(it.path).data
|
val data = UploadUtil.upload(it.path).data
|
||||||
it.url = data?.newName ?: ""
|
// UploadUtil 返回:newName=原图(较大),zipFileName=缩略图(较小)
|
||||||
it.originalPic = data?.zipFileName ?: ""
|
// FileBean.url 用作缩略图标识,FileBean.originalPic 用作原图标识
|
||||||
|
it.url = data?.zipFileName ?: ""
|
||||||
|
it.originalPic = data?.newName ?: ""
|
||||||
}
|
}
|
||||||
.flowOn(Dispatchers.IO)
|
.flowOn(Dispatchers.IO)
|
||||||
.onStart { showLoading() }
|
.onStart { showLoading() }
|
||||||
@@ -124,8 +121,8 @@ class AccidentVisaDetailsViewModel : BaseViewModel(), IOnItemClickListener {
|
|||||||
val list =
|
val list =
|
||||||
(rv?.commonAdapter()?.items as List<FileBean>).filter { it.path.isNotEmpty() }
|
(rv?.commonAdapter()?.items as List<FileBean>).filter { it.path.isNotEmpty() }
|
||||||
bean.picnumber = list.size.toString()
|
bean.picnumber = list.size.toString()
|
||||||
bean.originalPic = list.joinToString(separator = ",") { MediaUtil.removeUrl(it.url) }
|
bean.pic = list.joinToString(separator = ",") { MediaUtil.removeUrl(it.url) }
|
||||||
bean.pic = list.joinToString(separator = ",") { MediaUtil.removeUrl(it.originalPic) }
|
bean.originalPic = list.joinToString(separator = ",") { MediaUtil.removeUrl(it.originalPic) }
|
||||||
|
|
||||||
NetApply.api.anyPost(
|
NetApply.api.anyPost(
|
||||||
url = if (pageType.value == DetailsPageType.Add) "GnAccidentVisa/saveVisa" else "GnAccidentVisa/updateVisa",
|
url = if (pageType.value == DetailsPageType.Add) "GnAccidentVisa/saveVisa" else "GnAccidentVisa/updateVisa",
|
||||||
|
|||||||
@@ -3,12 +3,15 @@ package com.lukouguoji.aerologic.page.flight.query.details
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import com.alibaba.android.arouter.facade.annotation.Route
|
||||||
import com.lukouguoji.aerologic.R
|
import com.lukouguoji.aerologic.R
|
||||||
import com.lukouguoji.aerologic.databinding.ActivityFlightQueryDetailsBinding
|
import com.lukouguoji.aerologic.databinding.ActivityFlightQueryDetailsBinding
|
||||||
import com.lukouguoji.aerologic.databinding.ActivityGnjStashDetailsBinding
|
|
||||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||||
import com.lukouguoji.module_base.common.Constant
|
import com.lukouguoji.module_base.common.Constant
|
||||||
|
import com.lukouguoji.module_base.router.ARouterConstants
|
||||||
|
|
||||||
|
@Route(path = ARouterConstants.ACTIVITY_URL_FLIGHT_QUERY_DETAILS)
|
||||||
class FlightQueryDetailsActivity :
|
class FlightQueryDetailsActivity :
|
||||||
BaseBindingActivity<ActivityFlightQueryDetailsBinding, FlightQueryDetailsViewModel>() {
|
BaseBindingActivity<ActivityFlightQueryDetailsBinding, FlightQueryDetailsViewModel>() {
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import com.lukouguoji.module_base.base.BaseBindingActivity
|
|||||||
import com.lukouguoji.module_base.ktx.addOnItemClickListener
|
import com.lukouguoji.module_base.ktx.addOnItemClickListener
|
||||||
import com.lukouguoji.module_base.ktx.getLifecycleOwner
|
import com.lukouguoji.module_base.ktx.getLifecycleOwner
|
||||||
|
|
||||||
|
@Deprecated("使用 module_hangban 中的 HbQueryListActivity 替代")
|
||||||
class FlightQueryListActivity :
|
class FlightQueryListActivity :
|
||||||
BaseBindingActivity<ActivityFlightQueryListBinding, FlightQueryListViewModel>() {
|
BaseBindingActivity<ActivityFlightQueryListBinding, FlightQueryListViewModel>() {
|
||||||
override fun layoutId() = R.layout.activity_flight_query_list
|
override fun layoutId() = R.layout.activity_flight_query_list
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class FlightQueryListViewModel : BasePageViewModel() {
|
|||||||
val serviceType = MutableLiveData("")
|
val serviceType = MutableLiveData("")
|
||||||
|
|
||||||
val addressTypeList = MutableLiveData(listOf(KeyValue("全部", ""))).apply {
|
val addressTypeList = MutableLiveData(listOf(KeyValue("全部", ""))).apply {
|
||||||
DictUtils.getAreaTypeList {
|
DictUtils.getCountryTypeList {
|
||||||
value = it
|
value = it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.lukouguoji.aerologic.page.gnj.move.stash.detail
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.lukouguoji.aerologic.R
|
||||||
|
import com.lukouguoji.aerologic.databinding.ActivityGnjMoveStashDetailBinding
|
||||||
|
import com.lukouguoji.aerologic.page.gnj.move.stash.photo.GnjMoveStashPhotoActivity
|
||||||
|
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||||
|
import com.lukouguoji.module_base.bean.MoveStashBean
|
||||||
|
import com.lukouguoji.module_base.common.Constant
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国内进港移库「运单详情」(5.5 寸手持端专属页面,无平板变体)
|
||||||
|
*
|
||||||
|
* 由列表卡片的「查看详情」进入;「异常照片」卡片的加号槽位跳拍照上传页。
|
||||||
|
* 展示字段全部由列表项带入(Gson JSON),零新增请求。
|
||||||
|
*/
|
||||||
|
class GnjMoveStashDetailActivity :
|
||||||
|
BaseBindingActivity<ActivityGnjMoveStashDetailBinding, GnjMoveStashDetailViewModel>() {
|
||||||
|
|
||||||
|
override fun layoutId() = R.layout.activity_gnj_move_stash_detail
|
||||||
|
override fun viewModelClass() = GnjMoveStashDetailViewModel::class.java
|
||||||
|
|
||||||
|
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||||
|
setBackArrow("运单详情")
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
binding.activity = this
|
||||||
|
viewModel.initOnCreated(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 「异常照片」加号槽位 → 拍照上传页 */
|
||||||
|
fun openPhoto() {
|
||||||
|
viewModel.dataBean.value?.let {
|
||||||
|
GnjMoveStashPhotoActivity.start(this, it.mawbId, it.wbNo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun start(context: Context, bean: MoveStashBean) {
|
||||||
|
context.startActivity(
|
||||||
|
Intent(context, GnjMoveStashDetailActivity::class.java)
|
||||||
|
.putExtra(Constant.Key.DATA, Gson().toJson(bean))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.lukouguoji.aerologic.page.gnj.move.stash.detail
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.lukouguoji.module_base.base.BaseViewModel
|
||||||
|
import com.lukouguoji.module_base.bean.MoveStashBean
|
||||||
|
import com.lukouguoji.module_base.common.Constant
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国内进港移库「运单详情」ViewModel(5.5 寸手持端专属页面)
|
||||||
|
*
|
||||||
|
* 列表项数据已包含详情页所需全部字段(含 isMoved 端点打标),直接由列表带入,不额外请求。
|
||||||
|
*/
|
||||||
|
class GnjMoveStashDetailViewModel : BaseViewModel() {
|
||||||
|
|
||||||
|
val dataBean = MutableLiveData(MoveStashBean())
|
||||||
|
|
||||||
|
fun initOnCreated(intent: Intent) {
|
||||||
|
val json = intent.getStringExtra(Constant.Key.DATA).orEmpty()
|
||||||
|
if (json.isNotEmpty()) {
|
||||||
|
dataBean.value = Gson().fromJson(json, MoveStashBean::class.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,36 +1,104 @@
|
|||||||
package com.lukouguoji.aerologic.page.gnj.move.stash.list
|
package com.lukouguoji.aerologic.page.gnj.move.stash.list
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import com.lukouguoji.aerologic.R
|
import androidx.databinding.ObservableBoolean
|
||||||
import com.lukouguoji.aerologic.databinding.ActivityGnjMoveStashListBinding
|
import com.alibaba.android.arouter.facade.annotation.Route
|
||||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
import com.lukouguoji.aerologic.R
|
||||||
import com.lukouguoji.module_base.ktx.getLifecycleOwner
|
import com.lukouguoji.aerologic.databinding.ActivityGnjMoveStashListBinding
|
||||||
|
import com.lukouguoji.aerologic.page.gnj.move.stash.photo.GnjMoveStashPhotoActivity
|
||||||
class GnjMoveStashListActivity :
|
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||||
BaseBindingActivity<ActivityGnjMoveStashListBinding, GnjMoveStashListViewModel>() {
|
import com.lukouguoji.module_base.bean.MoveStashBean
|
||||||
override fun layoutId() = R.layout.activity_gnj_move_stash_list
|
import com.lukouguoji.module_base.common.ConstantEvent
|
||||||
|
import com.lukouguoji.module_base.impl.FlowBus
|
||||||
override fun viewModelClass() = GnjMoveStashListViewModel::class.java
|
import com.lukouguoji.module_base.impl.observe
|
||||||
|
import com.lukouguoji.module_base.ktx.getLifecycleOwner
|
||||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
import com.lukouguoji.module_base.router.ARouterConstants
|
||||||
setBackArrow("国内进港移库")
|
import com.lukouguoji.module_base.util.DeviceUtil
|
||||||
|
|
||||||
binding.viewModel = viewModel
|
@Route(path = ARouterConstants.ACTIVITY_URL_GNJ_MOVE_STASH_LIST)
|
||||||
|
class GnjMoveStashListActivity :
|
||||||
viewModel.pageModel
|
BaseBindingActivity<ActivityGnjMoveStashListBinding, GnjMoveStashListViewModel>() {
|
||||||
.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, getLifecycleOwner())
|
override fun layoutId() = R.layout.activity_gnj_move_stash_list
|
||||||
|
|
||||||
viewModel.refresh()
|
override fun viewModelClass() = GnjMoveStashListViewModel::class.java
|
||||||
}
|
|
||||||
|
/** 筛选弹层显隐(仅手机 UI 状态,平板布局不绑定) */
|
||||||
companion object {
|
val filterPanelVisible = ObservableBoolean(false)
|
||||||
@JvmStatic
|
|
||||||
fun start(context: Context) {
|
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||||
val starter = Intent(context, GnjMoveStashListActivity::class.java)
|
// 设计稿手机端标题为「进港移库」,平板保持原标题
|
||||||
context.startActivity(starter)
|
setBackArrow(if (DeviceUtil.isPhone()) "进港移库" else "国内进港移库")
|
||||||
}
|
|
||||||
}
|
binding.viewModel = viewModel
|
||||||
|
binding.activity = this
|
||||||
}
|
|
||||||
|
viewModel.pageModel
|
||||||
|
.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, getLifecycleOwner())
|
||||||
|
|
||||||
|
if (DeviceUtil.isPhone()) {
|
||||||
|
// 手机专属:Tab 角标 + 特码字典等额外请求
|
||||||
|
viewModel.initPhoneExtras()
|
||||||
|
|
||||||
|
// 卡片勾选变化 → 更新全选状态与已选计数
|
||||||
|
FlowBus.with<String>(ConstantEvent.EVENT_CHECK_CHANGED).observe(this) {
|
||||||
|
viewModel.updateCheckAllStatus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拍照上传等子页面完成后刷新列表(平板无发射方,观察无副作用)
|
||||||
|
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).observe(this) {
|
||||||
|
viewModel.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 筛选弹层(仅手机) ====================
|
||||||
|
|
||||||
|
fun toggleFilterPanel() {
|
||||||
|
filterPanelVisible.set(!filterPanelVisible.get())
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 筛选:重置(只清空弹层内条件,不影响 Tab 与顶部搜索框) */
|
||||||
|
fun resetFilter() {
|
||||||
|
viewModel.flightDate.value = ""
|
||||||
|
viewModel.flightNo.value = ""
|
||||||
|
viewModel.spCode.value = ""
|
||||||
|
viewModel.businessType.value = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
fun confirmFilter() {
|
||||||
|
filterPanelVisible.set(false)
|
||||||
|
viewModel.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 卡片长按「拍照」浮层(仅手机) ====================
|
||||||
|
|
||||||
|
/** 卡片长按:展开操作浮层(View.OnLongClickListener 要求返回 Boolean) */
|
||||||
|
fun showCardActionPhone(bean: MoveStashBean): Boolean {
|
||||||
|
bean.actionMenuVisible.set(true)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 点浮层空白处关闭 */
|
||||||
|
fun hideCardActionPhone(bean: MoveStashBean) {
|
||||||
|
bean.actionMenuVisible.set(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 浮层「拍照」→ 拍照上传页 */
|
||||||
|
fun openPhoto(bean: MoveStashBean) {
|
||||||
|
bean.actionMenuVisible.set(false)
|
||||||
|
GnjMoveStashPhotoActivity.start(this, bean.mawbId, bean.wbNo)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun start(context: Context) {
|
||||||
|
val starter = Intent(context, GnjMoveStashListActivity::class.java)
|
||||||
|
context.startActivity(starter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,21 +1,66 @@
|
|||||||
package com.lukouguoji.aerologic.page.gnj.move.stash.list
|
package com.lukouguoji.aerologic.page.gnj.move.stash.list
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import com.lukouguoji.aerologic.databinding.ItemGnjMoveStashListBinding
|
import android.widget.Toast
|
||||||
import com.lukouguoji.module_base.base.BaseViewHolder
|
import com.lukouguoji.aerologic.databinding.ItemGnjMoveStashListBinding
|
||||||
import com.lukouguoji.module_base.bean.MoveStashBean
|
import com.lukouguoji.aerologic.page.gnj.move.stash.detail.GnjMoveStashDetailActivity
|
||||||
import com.lukouguoji.module_base.bean.SimpleCheckBean
|
import com.lukouguoji.gnj.page.yiku.handover.GnjYiKuHandoverActivity
|
||||||
|
import com.lukouguoji.module_base.base.BaseViewHolder
|
||||||
class GnjMoveStashListViewHolder(view: View) :
|
import com.lukouguoji.module_base.bean.MoveStashBean
|
||||||
BaseViewHolder<MoveStashBean, ItemGnjMoveStashListBinding>(view) {
|
import com.lukouguoji.module_base.common.ConstantEvent
|
||||||
|
import com.lukouguoji.module_base.impl.FlowBus
|
||||||
override fun onBind(item: Any?, position: Int) {
|
import kotlinx.coroutines.GlobalScope
|
||||||
val bean = getItemBean(item)!!
|
import kotlinx.coroutines.launch
|
||||||
binding.bean = bean
|
|
||||||
|
/**
|
||||||
binding.ivIcon.setOnClickListener {
|
* 国内进港移库列表项 ViewHolder(双形态共用)
|
||||||
bean.checked.set(!bean.checked.get())
|
*
|
||||||
}
|
* 平板/手机布局差异较大,单侧独有的控件 id 在 Binding 基类中为 @Nullable,
|
||||||
}
|
* 全部走判空调用(平板:swipe_menu/btn_edit/ll;手机:ll_detail)。
|
||||||
|
*/
|
||||||
}
|
class GnjMoveStashListViewHolder(view: View) :
|
||||||
|
BaseViewHolder<MoveStashBean, ItemGnjMoveStashListBinding>(view) {
|
||||||
|
|
||||||
|
override fun onBind(item: Any?, position: Int) {
|
||||||
|
val bean = getItemBean(item)!!
|
||||||
|
binding.bean = bean
|
||||||
|
binding.position = position
|
||||||
|
binding.activity = itemView.context as? GnjMoveStashListActivity
|
||||||
|
|
||||||
|
// 勾选框(双形态共有):切换选中;手机端另行广播刷新全选/已选计数
|
||||||
|
binding.ivIcon.setOnClickListener {
|
||||||
|
bean.checked.set(!bean.checked.get())
|
||||||
|
binding.executePendingBindings()
|
||||||
|
|
||||||
|
GlobalScope.launch {
|
||||||
|
FlowBus.with<String>(ConstantEvent.EVENT_CHECK_CHANGED).emit("check_changed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 平板独有交互 =====
|
||||||
|
|
||||||
|
// 点击列表项进入移交详情
|
||||||
|
binding.ll?.setOnClickListener {
|
||||||
|
GnjYiKuHandoverActivity.startForDetails(itemView.context, bean.mawbId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 侧滑菜单 - 编辑按钮
|
||||||
|
binding.btnEdit?.setOnClickListener {
|
||||||
|
binding.swipeMenu?.quickClose()
|
||||||
|
if (bean.pickFlag == "1") {
|
||||||
|
Toast.makeText(itemView.context, "已出库,不可编辑", Toast.LENGTH_SHORT).show()
|
||||||
|
return@setOnClickListener
|
||||||
|
}
|
||||||
|
GnjYiKuHandoverActivity.startForEdit(itemView.context, bean.mawbId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 手机独有交互 =====
|
||||||
|
|
||||||
|
// 「查看详情」→ 手机版运单详情页
|
||||||
|
binding.llDetail?.setOnClickListener {
|
||||||
|
GnjMoveStashDetailActivity.start(itemView.context, bean)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.executePendingBindings()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -49,6 +49,41 @@ class GnjMoveStashListViewModel : BasePageViewModel() {
|
|||||||
val number = MutableLiveData("0")
|
val number = MutableLiveData("0")
|
||||||
val weight = MutableLiveData("0")
|
val weight = MutableLiveData("0")
|
||||||
|
|
||||||
|
// ========== 5.5 寸手持端专属字段(平板布局不绑定,默认值保证平板行为零变化) ==========
|
||||||
|
|
||||||
|
/** 移库状态 Tab:"0" 待移库(DomImpMove/search)/ "1" 已移库(DomImpMove/searchMoved) */
|
||||||
|
val moveState = MutableLiveData("0")
|
||||||
|
|
||||||
|
/** 手机筛选弹层:航班日期 / 航班号 / 特码(默认空 → 不进请求) */
|
||||||
|
val flightDate = MutableLiveData("")
|
||||||
|
val flightNo = MutableLiveData("")
|
||||||
|
val spCode = MutableLiveData("")
|
||||||
|
val spCodeList = MutableLiveData<List<KeyValue>>(emptyList())
|
||||||
|
|
||||||
|
val moveStateTabs = MutableLiveData(
|
||||||
|
listOf(KeyValue("待移库", "0"), KeyValue("已移库", "1"))
|
||||||
|
)
|
||||||
|
|
||||||
|
/** 状态 Tab 角标(与 [moveStateTabs] 等长,取两端点分页 total) */
|
||||||
|
val moveStateCounts = MutableLiveData(listOf("", ""))
|
||||||
|
|
||||||
|
/** 底部操作条「已选 N 项」 */
|
||||||
|
val selectedCount = MutableLiveData("0")
|
||||||
|
|
||||||
|
/** 全选状态(手机 PhoneBottomBar 勾选图标) */
|
||||||
|
val isAllChecked = MutableLiveData(false)
|
||||||
|
|
||||||
|
/** 手机专属的额外请求(Tab 角标、特码字典)开关,仅手机形态在 Activity 中开启 */
|
||||||
|
private var phoneExtrasEnabled = false
|
||||||
|
|
||||||
|
fun initPhoneExtras() {
|
||||||
|
phoneExtrasEnabled = true
|
||||||
|
// 特码字典:flag=0 国内、ieFlag=I 进港(是否生效待实测,见问题清单)
|
||||||
|
DictUtils.getSpecialCodeList(addAll = false, flag = 0, ieFlag = "I") { list ->
|
||||||
|
spCodeList.postValue(listOf(KeyValue("全部", "")) + list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// 方法区
|
// 方法区
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
@@ -95,25 +130,73 @@ class GnjMoveStashListViewModel : BasePageViewModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** 查询条件(分页参数除外),search / searchMoved / searchTotal 三处共用同一套入参 */
|
||||||
|
private fun buildFilterParams(): Map<String, Any?> = mapOf(
|
||||||
|
"awbType" to businessType.value!!.ifEmpty { null },
|
||||||
|
"wbNo" to waybill.value!!.ifEmpty { null },
|
||||||
|
"carrier" to carrier.value!!.ifEmpty { null },
|
||||||
|
// 以下为手机筛选弹层字段,平板恒为空串 → 恒传 null,行为不变
|
||||||
|
"fdate" to flightDate.value?.ifEmpty { null },
|
||||||
|
"fno" to flightNo.value?.ifEmpty { null },
|
||||||
|
"spCode" to spCode.value?.ifEmpty { null },
|
||||||
|
)
|
||||||
|
|
||||||
override fun getData() {
|
override fun getData() {
|
||||||
val body = mapOf(
|
val body = (buildFilterParams() + mapOf(
|
||||||
"page" to pageModel.page,
|
"page" to pageModel.page,
|
||||||
"limit" to pageModel.limit,
|
"limit" to pageModel.limit,
|
||||||
"awbType" to businessType.value!!.ifEmpty { null },
|
)).toRequestBody()
|
||||||
"wbNo" to waybill.value!!.ifEmpty { null },
|
val moved = moveState.value == "1"
|
||||||
"carrier" to carrier.value!!.ifEmpty { null },
|
|
||||||
).toRequestBody()
|
|
||||||
launchLoadingCollect({
|
launchLoadingCollect({
|
||||||
NetApply.api.getGnjMoveStashList(
|
// 平板 moveState 恒为 "0" → 恒走 search(原行为);已移库 Tab 走 searchMoved
|
||||||
body
|
if (moved) NetApply.api.getGnjMoveStashMovedList(body)
|
||||||
)
|
else NetApply.api.getGnjMoveStashList(body)
|
||||||
}) {
|
}) {
|
||||||
onSuccess = {
|
onSuccess = {
|
||||||
pageModel.handleListBean(it)
|
// searchMoved 出参无移库标识,按端点打标(卡片形态/详情移库信息卡依赖)
|
||||||
|
it.list?.forEach { bean -> bean.isMoved = moved }
|
||||||
|
pageModel.handleListBean(it) { updateCheckAllStatus() }
|
||||||
count.value = it.total
|
count.value = it.total
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getCountData(body)
|
getCountData(body)
|
||||||
|
if (phoneExtrasEnabled) loadTabCounts()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Tab 角标:search / searchMoved 各以 limit=1 查一次取分页 total(仅手机形态发起) */
|
||||||
|
private fun loadTabCounts() {
|
||||||
|
val body = (buildFilterParams() + mapOf("page" to 1, "limit" to 1)).toRequestBody()
|
||||||
|
launchCollect({ NetApply.api.getGnjMoveStashList(body) }) {
|
||||||
|
onSuccess = { updateTabCount(0, it.total) }
|
||||||
|
}
|
||||||
|
launchCollect({ NetApply.api.getGnjMoveStashMovedList(body) }) {
|
||||||
|
onSuccess = { updateTabCount(1, it.total) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateTabCount(index: Int, total: Int?) {
|
||||||
|
val current = moveStateCounts.value?.toMutableList() ?: mutableListOf("", "")
|
||||||
|
if (index < current.size) {
|
||||||
|
current[index] = (total ?: 0).toString()
|
||||||
|
moveStateCounts.value = current
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 手机端全选 / 已选计数 ==========
|
||||||
|
|
||||||
|
fun toggleSelectAll() {
|
||||||
|
val list = pageModel.rv?.commonAdapter()?.items
|
||||||
|
?.filterIsInstance<MoveStashBean>() ?: return
|
||||||
|
CheckUtil.handleAllCheck(list)
|
||||||
|
updateCheckAllStatus()
|
||||||
|
pageModel.rv?.commonAdapter()?.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateCheckAllStatus() {
|
||||||
|
val list = pageModel.rv?.commonAdapter()?.items
|
||||||
|
?.filterIsInstance<MoveStashBean>() ?: return
|
||||||
|
isAllChecked.value = list.isNotEmpty() && list.all { it.checked.get() }
|
||||||
|
selectedCount.value = list.count { it.checked.get() }.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getCountData(body: RequestBody) {
|
private fun getCountData(body: RequestBody) {
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.lukouguoji.aerologic.page.gnj.move.stash.photo
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import com.lukouguoji.aerologic.R
|
||||||
|
import com.lukouguoji.aerologic.databinding.ActivityGnjMoveStashPhotoBinding
|
||||||
|
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||||
|
import com.lukouguoji.module_base.common.Constant
|
||||||
|
import com.lukouguoji.module_base.ktx.addOnItemClickListener
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国内进港移库「拍照上传」(5.5 寸手持端专属页面,无平板变体)
|
||||||
|
*
|
||||||
|
* 由列表卡片长按浮层「拍照」或运单详情「异常照片」加号槽位进入。
|
||||||
|
* 已有照片经 DomImpMove/detail 回填,提交走 DomImpMove/modify
|
||||||
|
* (mawbId + pic/originalPic/picNumber 三字段规范,与平板移交编辑页同一链路)。
|
||||||
|
*/
|
||||||
|
class GnjMoveStashPhotoActivity :
|
||||||
|
BaseBindingActivity<ActivityGnjMoveStashPhotoBinding, GnjMoveStashPhotoViewModel>() {
|
||||||
|
|
||||||
|
override fun layoutId() = R.layout.activity_gnj_move_stash_photo
|
||||||
|
override fun viewModelClass() = GnjMoveStashPhotoViewModel::class.java
|
||||||
|
|
||||||
|
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||||
|
setBackArrow("拍照上传")
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
|
||||||
|
viewModel.rv = binding.rv
|
||||||
|
binding.rv.addOnItemClickListener(viewModel)
|
||||||
|
|
||||||
|
viewModel.initOnCreated(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun start(context: Context, mawbId: String, wbNo: String) {
|
||||||
|
context.startActivity(
|
||||||
|
Intent(context, GnjMoveStashPhotoActivity::class.java)
|
||||||
|
.putExtra(Constant.Key.ID, mawbId)
|
||||||
|
.putExtra(Constant.Key.CODE, wbNo)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
package com.lukouguoji.aerologic.page.gnj.move.stash.photo
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.lukouguoji.module_base.base.BaseViewModel
|
||||||
|
import com.lukouguoji.module_base.bean.FileBean
|
||||||
|
import com.lukouguoji.module_base.bean.GnjYiKuBean
|
||||||
|
import com.lukouguoji.module_base.common.Constant
|
||||||
|
import com.lukouguoji.module_base.common.ConstantEvent
|
||||||
|
import com.lukouguoji.module_base.http.net.NetApply
|
||||||
|
import com.lukouguoji.module_base.impl.FlowBus
|
||||||
|
import com.lukouguoji.module_base.impl.ImageSelectNewViewHolder
|
||||||
|
import com.lukouguoji.module_base.interfaces.IOnItemClickListener
|
||||||
|
import com.lukouguoji.module_base.ktx.commonAdapter
|
||||||
|
import com.lukouguoji.module_base.ktx.launchCollect
|
||||||
|
import com.lukouguoji.module_base.ktx.launchLoadingCollect
|
||||||
|
import com.lukouguoji.module_base.ktx.noNull
|
||||||
|
import com.lukouguoji.module_base.ktx.showToast
|
||||||
|
import com.lukouguoji.module_base.ktx.toRequestBody
|
||||||
|
import com.lukouguoji.module_base.util.MediaUtil
|
||||||
|
import com.lukouguoji.module_base.util.UploadUtil
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.asFlow
|
||||||
|
import kotlinx.coroutines.flow.catch
|
||||||
|
import kotlinx.coroutines.flow.filter
|
||||||
|
import kotlinx.coroutines.flow.flowOn
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.flow.onCompletion
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.flow.onStart
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国内进港移库「拍照上传」ViewModel(5.5 寸手持端专属页面)
|
||||||
|
*
|
||||||
|
* 图片选择/预览/删除复用 module_base 的 ImageSelectNewViewHolder(末位加号槽位)。
|
||||||
|
* 已有照片经 DomImpMove/detail 回填;提交走 DomImpMove/modify 最小体
|
||||||
|
* (mawbId/remark/picNumber/pic/originalPic),与平板移交编辑页同一链路。
|
||||||
|
*/
|
||||||
|
class GnjMoveStashPhotoViewModel : BaseViewModel(), IOnItemClickListener {
|
||||||
|
|
||||||
|
var mawbId = ""
|
||||||
|
|
||||||
|
/** 运单号(副标题展示,由列表带入) */
|
||||||
|
val wbNo = MutableLiveData("")
|
||||||
|
|
||||||
|
/** detail 回填的完整 bean(提交时保留 remark 等原值) */
|
||||||
|
private var detailBean = GnjYiKuBean()
|
||||||
|
|
||||||
|
// 图片网格适配器配置(复用公共图片选择组件)
|
||||||
|
val itemViewHolder = ImageSelectNewViewHolder::class.java
|
||||||
|
val itemLayoutId = com.lukouguoji.module_base.R.layout.item_image_select_new
|
||||||
|
|
||||||
|
var rv: RecyclerView? = null
|
||||||
|
|
||||||
|
fun initOnCreated(intent: Intent) {
|
||||||
|
mawbId = intent.getStringExtra(Constant.Key.ID).orEmpty()
|
||||||
|
wbNo.value = intent.getStringExtra(Constant.Key.CODE).orEmpty()
|
||||||
|
|
||||||
|
// 已有照片回填(pic 缩略图 + originalPic 原图),末位补加号槽位
|
||||||
|
launchCollect({ NetApply.api.getGnjMoveStashDetail(mawbId) }) {
|
||||||
|
onSuccess = {
|
||||||
|
detailBean = it.data ?: GnjYiKuBean()
|
||||||
|
val picList = detailBean.pic.split(",").filter { p -> p.isNotEmpty() }
|
||||||
|
val originalList = detailBean.originalPic.split(",").filter { p -> p.isNotEmpty() }
|
||||||
|
val images = picList.mapIndexed { index, picUrl ->
|
||||||
|
FileBean(
|
||||||
|
path = MediaUtil.fillUrl(picUrl),
|
||||||
|
url = picUrl,
|
||||||
|
originalPic = MediaUtil.fillUrl(originalList.getOrElse(index) { picUrl })
|
||||||
|
)
|
||||||
|
}
|
||||||
|
rv?.post {
|
||||||
|
rv?.commonAdapter()?.refresh(images + FileBean())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onFailed = { _, _ ->
|
||||||
|
// 详情取不到也允许直接新增照片
|
||||||
|
rv?.post { rv?.commonAdapter()?.refresh(listOf(FileBean())) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确认提交:先补传未上传的本地图片,再按三字段规范提交 modify
|
||||||
|
*/
|
||||||
|
fun submitClick() {
|
||||||
|
(rv?.commonAdapter()?.items ?: emptyList())
|
||||||
|
.asFlow()
|
||||||
|
.map { it as FileBean }
|
||||||
|
.filter { it.path.isNotEmpty() && it.url.isEmpty() }
|
||||||
|
.onEach {
|
||||||
|
val data = UploadUtil.upload(it.path).data
|
||||||
|
// UploadUtil 返回:newName=原图(较大),zipFileName=缩略图(较小)
|
||||||
|
it.url = data?.zipFileName ?: ""
|
||||||
|
it.originalPic = data?.newName ?: ""
|
||||||
|
}
|
||||||
|
.flowOn(Dispatchers.IO)
|
||||||
|
.onStart { showLoading() }
|
||||||
|
.catch {
|
||||||
|
showToast(it.message.noNull("上传图片失败"))
|
||||||
|
dismissLoading()
|
||||||
|
}
|
||||||
|
.onCompletion {
|
||||||
|
launchLoadingCollect({
|
||||||
|
val list = (rv?.commonAdapter()?.items ?: emptyList())
|
||||||
|
.filterIsInstance<FileBean>()
|
||||||
|
.filter { it.path.isNotEmpty() }
|
||||||
|
|
||||||
|
// 最小体提交:只更新图片三字段(remark 保留 detail 原值),与平板移交编辑页一致
|
||||||
|
val params = mapOf(
|
||||||
|
"mawbId" to mawbId,
|
||||||
|
"remark" to detailBean.remark,
|
||||||
|
"picNumber" to list.size.toString(),
|
||||||
|
"pic" to list.joinToString(",") { MediaUtil.removeUrl(it.url) },
|
||||||
|
"originalPic" to list.joinToString(",") { MediaUtil.removeUrl(it.originalPic) },
|
||||||
|
).toRequestBody(removeEmptyOrNull = true)
|
||||||
|
|
||||||
|
NetApply.api.modifyGnjMoveStash(params)
|
||||||
|
}) {
|
||||||
|
onSuccess = {
|
||||||
|
showToast("提交成功")
|
||||||
|
viewModelScope.launch {
|
||||||
|
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
|
||||||
|
}
|
||||||
|
getTopActivity().finish()
|
||||||
|
}
|
||||||
|
onFailed = { _, msg ->
|
||||||
|
showToast(msg.noNull("提交失败"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.launchIn(viewModelScope)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 「拍照/上传」按钮:直接唤起图片选择(含拍照入口)
|
||||||
|
*/
|
||||||
|
fun pickClick() {
|
||||||
|
MediaUtil.pickImage(getTopActivity(), maxNum = 9) { results ->
|
||||||
|
val adapter = rv?.commonAdapter() ?: return@pickImage
|
||||||
|
results.forEach { result ->
|
||||||
|
// 在加号槽位(最后一项)之前插入
|
||||||
|
val insertPos = (adapter.items.size - 1).coerceAtLeast(0)
|
||||||
|
adapter.items.add(insertPos, FileBean(path = result.realPath))
|
||||||
|
adapter.notifyItemInserted(insertPos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片网格点击回调(长按出删除角标 / 点删除角标移除)
|
||||||
|
*/
|
||||||
|
override fun onItemClick(position: Int, type: Int) {
|
||||||
|
val adapter = rv?.commonAdapter() ?: return
|
||||||
|
val bean = adapter.getItem(position) as? FileBean ?: return
|
||||||
|
when (type) {
|
||||||
|
com.lukouguoji.module_base.R.id.rl -> {
|
||||||
|
if (bean.path.isNotEmpty()) {
|
||||||
|
bean.canDelete.set(!bean.canDelete.get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
com.lukouguoji.module_base.R.id.iv_delete -> {
|
||||||
|
adapter.removeItem(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,347 @@
|
|||||||
|
package com.lukouguoji.aerologic.page.log.detail
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.graphics.Paint
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.TypedValue
|
||||||
|
import android.view.Gravity
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.TextView
|
||||||
|
import com.alibaba.android.arouter.facade.annotation.Route
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.lukouguoji.aerologic.R
|
||||||
|
import com.lukouguoji.aerologic.databinding.ActivityLogDetailBinding
|
||||||
|
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||||
|
import com.lukouguoji.module_base.bean.LogBean
|
||||||
|
import com.lukouguoji.module_base.common.Constant
|
||||||
|
import com.lukouguoji.module_base.router.ARouterConstants
|
||||||
|
import com.lukouguoji.module_base.util.DeviceUtil
|
||||||
|
|
||||||
|
@Route(path = ARouterConstants.ACTIVITY_URL_LOG_DETAIL)
|
||||||
|
class LogDetailActivity : BaseBindingActivity<ActivityLogDetailBinding, LogDetailViewModel>() {
|
||||||
|
|
||||||
|
private val timelineAdapter = LogDetailTimelineAdapter()
|
||||||
|
|
||||||
|
override fun layoutId(): Int {
|
||||||
|
return R.layout.activity_log_detail
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun viewModelClass(): Class<LogDetailViewModel> {
|
||||||
|
return LogDetailViewModel::class.java
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||||
|
// 手机版设计稿标题为「运单追踪」,平板保持原标题
|
||||||
|
setBackArrow(if (DeviceUtil.isPhone()) "运单追踪" else "操作日志详情")
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
|
||||||
|
// 配置操作详情 RecyclerView(垂直时间线)
|
||||||
|
binding.rvTimeline.adapter = timelineAdapter
|
||||||
|
|
||||||
|
// 观察数据变化,重新构建步骤进度条
|
||||||
|
viewModel.allSteps.observe(this) { rebuildSteps() }
|
||||||
|
viewModel.activeStepCodes.observe(this) { rebuildSteps() }
|
||||||
|
viewModel.latestStepCode.observe(this) { rebuildSteps() }
|
||||||
|
|
||||||
|
viewModel.statusLogList.observe(this) { list ->
|
||||||
|
val stepMap = viewModel.allSteps.value?.associate { it.code to it.name } ?: emptyMap()
|
||||||
|
timelineAdapter.setData(list, stepMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.initOnCreated(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun rebuildSteps() {
|
||||||
|
val steps = viewModel.allSteps.value ?: return
|
||||||
|
val activeCodes = viewModel.activeStepCodes.value ?: emptySet()
|
||||||
|
val latestCode = viewModel.latestStepCode.value ?: ""
|
||||||
|
if (steps.isEmpty()) return
|
||||||
|
// 手机布局是竖排时间线(layout/activity_log_detail.xml),平板保持横向步骤条
|
||||||
|
if (DeviceUtil.isPhone()) {
|
||||||
|
buildVerticalSteps(steps, activeCodes, latestCode)
|
||||||
|
} else {
|
||||||
|
buildStepProgressBar(steps, activeCodes, latestCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机版竖排流转时间线(对应设计稿「运单追踪」):
|
||||||
|
* 每个节点 = 左侧圆点 + 连接竖线,右侧步骤名 + 该环节最新操作时间。
|
||||||
|
* 已发生节点绿色,未发生节点灰色。
|
||||||
|
*/
|
||||||
|
private fun buildVerticalSteps(
|
||||||
|
steps: List<StepInfo>,
|
||||||
|
activeCodes: Set<String>,
|
||||||
|
latestCode: String
|
||||||
|
) {
|
||||||
|
val container = binding.llSteps
|
||||||
|
container.removeAllViews()
|
||||||
|
container.orientation = LinearLayout.VERTICAL
|
||||||
|
|
||||||
|
val logs = viewModel.statusLogList.value ?: emptyList()
|
||||||
|
val colorGreen = 0xFF16A34A.toInt()
|
||||||
|
val colorGray = 0xFF9CA3AF.toInt()
|
||||||
|
val colorLine = 0xFFE5E7EB.toInt()
|
||||||
|
|
||||||
|
for (i in steps.indices) {
|
||||||
|
val step = steps[i]
|
||||||
|
val isActive = step.code in activeCodes
|
||||||
|
val isLast = i == steps.size - 1
|
||||||
|
val stepLog = logs.lastOrNull { it.status == step.code }
|
||||||
|
val time = stepLog?.opDate ?: ""
|
||||||
|
val statusContent = stepLog?.content ?: ""
|
||||||
|
|
||||||
|
val row = LinearLayout(this).apply {
|
||||||
|
orientation = LinearLayout.HORIZONTAL
|
||||||
|
layoutParams = LinearLayout.LayoutParams(
|
||||||
|
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 左列:圆点 + 连接竖线
|
||||||
|
val dotColumn = LinearLayout(this).apply {
|
||||||
|
orientation = LinearLayout.VERTICAL
|
||||||
|
gravity = Gravity.CENTER_HORIZONTAL
|
||||||
|
layoutParams = LinearLayout.LayoutParams(dp(20), LinearLayout.LayoutParams.MATCH_PARENT)
|
||||||
|
}
|
||||||
|
val dot = View(this).apply {
|
||||||
|
setBackgroundResource(
|
||||||
|
if (isActive) com.lukouguoji.module_base.R.drawable.bg_phone_dot_green
|
||||||
|
else com.lukouguoji.module_base.R.drawable.bg_phone_dot_gray
|
||||||
|
)
|
||||||
|
layoutParams = LinearLayout.LayoutParams(
|
||||||
|
dp(if (isActive) 12 else 8), dp(if (isActive) 12 else 8)
|
||||||
|
).apply { topMargin = dp(if (isActive) 2 else 4) }
|
||||||
|
}
|
||||||
|
dotColumn.addView(dot)
|
||||||
|
if (!isLast) {
|
||||||
|
val line = View(this).apply {
|
||||||
|
setBackgroundColor(colorLine)
|
||||||
|
layoutParams = LinearLayout.LayoutParams(dp(2), 0).apply {
|
||||||
|
weight = 1f
|
||||||
|
topMargin = dp(2)
|
||||||
|
bottomMargin = dp(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dotColumn.addView(line)
|
||||||
|
}
|
||||||
|
row.addView(dotColumn)
|
||||||
|
|
||||||
|
// 右列:步骤名 + 时间
|
||||||
|
val content = LinearLayout(this).apply {
|
||||||
|
orientation = LinearLayout.VERTICAL
|
||||||
|
layoutParams = LinearLayout.LayoutParams(
|
||||||
|
0, LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
).apply {
|
||||||
|
weight = 1f
|
||||||
|
leftMargin = dp(10)
|
||||||
|
}
|
||||||
|
setPadding(0, 0, 0, if (isLast) 0 else dp(24))
|
||||||
|
}
|
||||||
|
// 名称行:步骤名(左)+ 已发生节点的状态 pill(右,设计稿如「放行状态:01」)
|
||||||
|
val nameRow = LinearLayout(this).apply {
|
||||||
|
orientation = LinearLayout.HORIZONTAL
|
||||||
|
gravity = Gravity.CENTER_VERTICAL
|
||||||
|
layoutParams = LinearLayout.LayoutParams(
|
||||||
|
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
)
|
||||||
|
}
|
||||||
|
nameRow.addView(TextView(this).apply {
|
||||||
|
text = step.name
|
||||||
|
setTextSize(TypedValue.COMPLEX_UNIT_SP, 15f)
|
||||||
|
setTextColor(if (isActive) colorGreen else colorGray)
|
||||||
|
if (isActive) setTypeface(typeface, android.graphics.Typeface.BOLD)
|
||||||
|
layoutParams = LinearLayout.LayoutParams(
|
||||||
|
0, LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
).apply { weight = 1f }
|
||||||
|
})
|
||||||
|
if (isActive && statusContent.isNotEmpty()) {
|
||||||
|
nameRow.addView(TextView(this).apply {
|
||||||
|
text = statusContent
|
||||||
|
setTextSize(TypedValue.COMPLEX_UNIT_SP, 11f)
|
||||||
|
setTextColor(colorGreen)
|
||||||
|
setBackgroundResource(com.lukouguoji.module_base.R.drawable.bg_phone_tag_green)
|
||||||
|
setPadding(dp(8), dp(3), dp(8), dp(3))
|
||||||
|
maxLines = 1
|
||||||
|
ellipsize = android.text.TextUtils.TruncateAt.END
|
||||||
|
maxWidth = dp(180)
|
||||||
|
layoutParams = LinearLayout.LayoutParams(
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
).apply { leftMargin = dp(8) }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
content.addView(nameRow)
|
||||||
|
if (time.isNotEmpty()) {
|
||||||
|
content.addView(TextView(this).apply {
|
||||||
|
text = time
|
||||||
|
setTextSize(TypedValue.COMPLEX_UNIT_SP, 12f)
|
||||||
|
setTextColor(colorGray)
|
||||||
|
layoutParams = LinearLayout.LayoutParams(
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
).apply { topMargin = dp(4) }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
row.addView(content)
|
||||||
|
|
||||||
|
container.addView(row)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildStepProgressBar(
|
||||||
|
steps: List<StepInfo>,
|
||||||
|
activeCodes: Set<String>,
|
||||||
|
latestCode: String
|
||||||
|
) {
|
||||||
|
val container = binding.llSteps
|
||||||
|
container.removeAllViews()
|
||||||
|
|
||||||
|
val colorBlue = 0xFF1C8CF5.toInt()
|
||||||
|
val colorGray = 0xFFCCCCCC.toInt()
|
||||||
|
val dotSize = dp(10)
|
||||||
|
val lineHeight = dp(2)
|
||||||
|
val labelHPadding = dp(6)
|
||||||
|
val alignBase = dp(27)
|
||||||
|
|
||||||
|
// 按"四个汉字 label"估算节点 label 宽度(含左右各 6dp padding)
|
||||||
|
val labelTextSizePx = TypedValue.applyDimension(
|
||||||
|
TypedValue.COMPLEX_UNIT_SP, 13f, resources?.displayMetrics
|
||||||
|
)
|
||||||
|
val fourCharTextWidth = Paint().apply { textSize = labelTextSizePx }
|
||||||
|
.measureText("测测测测").toInt()
|
||||||
|
val estimatedLabelWidth = fourCharTextWidth + labelHPadding * 2
|
||||||
|
|
||||||
|
// 计算每个节点宽度:屏幕宽度的 80% 均分给所有节点,并加上限避免步数少时单格过宽
|
||||||
|
val screenWidth = resources!!.displayMetrics.widthPixels
|
||||||
|
val rawStepWidth = (screenWidth * 0.8 / steps.size).toInt()
|
||||||
|
val maxStepWidth = estimatedLabelWidth + dp(40)
|
||||||
|
val stepWidth = minOf(rawStepWidth, maxStepWidth)
|
||||||
|
|
||||||
|
// 让第一个 label(居中在 stepWidth 内)的左边缘对齐到卡片内 15dp 基准线
|
||||||
|
// labelLeftInStep = (stepWidth - estimatedLabelWidth) / 2
|
||||||
|
// 所需 ll_steps leftMargin = alignBase - labelLeftInStep
|
||||||
|
val labelLeftInStep = (stepWidth - estimatedLabelWidth) / 2
|
||||||
|
(container.layoutParams as? ViewGroup.MarginLayoutParams)?.let {
|
||||||
|
it.leftMargin = alignBase - labelLeftInStep
|
||||||
|
container.layoutParams = it
|
||||||
|
}
|
||||||
|
|
||||||
|
// 找到最新节点在步骤列表中的索引
|
||||||
|
val latestIndex = steps.indexOfFirst { it.code == latestCode }
|
||||||
|
|
||||||
|
for (i in steps.indices) {
|
||||||
|
val step = steps[i]
|
||||||
|
val isActive = step.code in activeCodes
|
||||||
|
val isLatest = step.code == latestCode
|
||||||
|
val isFirst = i == 0
|
||||||
|
val isLast = i == steps.size - 1
|
||||||
|
|
||||||
|
// 每个步骤的根容器(内部水平居中:label 与圆点都在 stepWidth 中心)
|
||||||
|
val stepLayout = LinearLayout(this).apply {
|
||||||
|
orientation = LinearLayout.VERTICAL
|
||||||
|
gravity = Gravity.CENTER_HORIZONTAL
|
||||||
|
layoutParams = LinearLayout.LayoutParams(stepWidth, LinearLayout.LayoutParams.WRAP_CONTENT)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 步骤名称(所有步骤统一 padding 确保高度一致)
|
||||||
|
val tvName = TextView(this).apply {
|
||||||
|
text = step.name
|
||||||
|
setTextSize(TypedValue.COMPLEX_UNIT_SP, 13f)
|
||||||
|
gravity = Gravity.CENTER
|
||||||
|
setPadding(labelHPadding, dp(2), labelHPadding, dp(2))
|
||||||
|
if (isLatest) {
|
||||||
|
setBackgroundResource(R.drawable.bg_step_current_badge)
|
||||||
|
setTextColor(0xFFFFFFFF.toInt())
|
||||||
|
} else {
|
||||||
|
setTextColor(if (isActive) 0xFF333333.toInt() else 0xFF999999.toInt())
|
||||||
|
}
|
||||||
|
layoutParams = LinearLayout.LayoutParams(
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
)
|
||||||
|
}
|
||||||
|
stepLayout.addView(tvName)
|
||||||
|
|
||||||
|
// 圆点和连线区域(FrameLayout 叠加)
|
||||||
|
val dotLineContainer = FrameLayout(this).apply {
|
||||||
|
layoutParams = LinearLayout.LayoutParams(
|
||||||
|
LinearLayout.LayoutParams.MATCH_PARENT, dp(20)
|
||||||
|
).apply { topMargin = dp(8) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 左半连线(从左边缘到圆点中心)
|
||||||
|
if (!isFirst) {
|
||||||
|
val leftLineColor = if (latestIndex >= 0 && i <= latestIndex) colorBlue else colorGray
|
||||||
|
val lineLeft = View(this).apply {
|
||||||
|
setBackgroundColor(leftLineColor)
|
||||||
|
layoutParams = FrameLayout.LayoutParams(0, lineHeight).apply {
|
||||||
|
gravity = Gravity.CENTER_VERTICAL or Gravity.START
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dotLineContainer.addView(lineLeft)
|
||||||
|
dotLineContainer.post {
|
||||||
|
lineLeft.layoutParams = FrameLayout.LayoutParams(
|
||||||
|
dotLineContainer.width / 2 + dotSize / 2, lineHeight
|
||||||
|
).apply { gravity = Gravity.CENTER_VERTICAL or Gravity.START }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 右半连线(从圆点中心到右边缘)
|
||||||
|
if (!isLast) {
|
||||||
|
val rightLineColor = if (latestIndex >= 0 && i < latestIndex) colorBlue else colorGray
|
||||||
|
val lineRight = View(this).apply {
|
||||||
|
setBackgroundColor(rightLineColor)
|
||||||
|
layoutParams = FrameLayout.LayoutParams(0, lineHeight).apply {
|
||||||
|
gravity = Gravity.CENTER_VERTICAL or Gravity.END
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dotLineContainer.addView(lineRight)
|
||||||
|
dotLineContainer.post {
|
||||||
|
lineRight.layoutParams = FrameLayout.LayoutParams(
|
||||||
|
dotLineContainer.width / 2 + dotSize / 2, lineHeight
|
||||||
|
).apply { gravity = Gravity.CENTER_VERTICAL or Gravity.END }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 圆点(居中叠加在连线之上)
|
||||||
|
val dot = View(this).apply {
|
||||||
|
setBackgroundResource(
|
||||||
|
when {
|
||||||
|
isLatest -> R.drawable.bg_step_dot_green
|
||||||
|
isActive -> R.drawable.bg_step_dot_blue
|
||||||
|
else -> R.drawable.bg_step_dot_gray
|
||||||
|
}
|
||||||
|
)
|
||||||
|
layoutParams = FrameLayout.LayoutParams(dotSize, dotSize).apply {
|
||||||
|
gravity = Gravity.CENTER
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dotLineContainer.addView(dot)
|
||||||
|
|
||||||
|
stepLayout.addView(dotLineContainer)
|
||||||
|
container.addView(stepLayout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dp(value: Int): Int {
|
||||||
|
return TypedValue.applyDimension(
|
||||||
|
TypedValue.COMPLEX_UNIT_DIP, value.toFloat(), resources?.displayMetrics
|
||||||
|
).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun start(context: Context, bean: LogBean) {
|
||||||
|
val starter = Intent(context, LogDetailActivity::class.java)
|
||||||
|
starter.putExtra(Constant.Key.DATA, Gson().toJson(bean))
|
||||||
|
context.startActivity(starter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package com.lukouguoji.aerologic.page.log.detail
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.lukouguoji.aerologic.R
|
||||||
|
|
||||||
|
class LogDetailStepAdapter : RecyclerView.Adapter<LogDetailStepAdapter.StepViewHolder>() {
|
||||||
|
|
||||||
|
private var steps: List<String> = emptyList()
|
||||||
|
private var currentIndex: Int = -1
|
||||||
|
|
||||||
|
fun setData(steps: List<String>, currentIndex: Int) {
|
||||||
|
this.steps = steps
|
||||||
|
this.currentIndex = currentIndex
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StepViewHolder {
|
||||||
|
val view = LayoutInflater.from(parent.context)
|
||||||
|
.inflate(R.layout.item_log_step, parent, false)
|
||||||
|
return StepViewHolder(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: StepViewHolder, position: Int) {
|
||||||
|
val step = steps[position]
|
||||||
|
val isCompleted = position <= currentIndex
|
||||||
|
val isCurrent = position == currentIndex
|
||||||
|
val isFirst = position == 0
|
||||||
|
val isLast = position == steps.size - 1
|
||||||
|
|
||||||
|
// 步骤名称
|
||||||
|
if (isCurrent) {
|
||||||
|
holder.tvStepName.setBackgroundResource(R.drawable.bg_step_current_badge)
|
||||||
|
holder.tvStepName.setTextColor(0xFFFFFFFF.toInt())
|
||||||
|
} else {
|
||||||
|
holder.tvStepName.setBackgroundResource(0)
|
||||||
|
holder.tvStepName.setTextColor(
|
||||||
|
if (isCompleted) 0xFF333333.toInt() else 0xFF999999.toInt()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
holder.tvStepName.text = step
|
||||||
|
|
||||||
|
// 圆点
|
||||||
|
holder.dotView.setBackgroundResource(
|
||||||
|
when {
|
||||||
|
isCurrent -> R.drawable.bg_step_dot_green
|
||||||
|
isCompleted -> R.drawable.bg_step_dot_blue
|
||||||
|
else -> R.drawable.bg_step_dot_gray
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// 左侧连线
|
||||||
|
holder.lineLeft.visibility = if (isFirst) View.INVISIBLE else View.VISIBLE
|
||||||
|
holder.lineLeft.setBackgroundColor(
|
||||||
|
if (isCompleted) 0xFF1C8CF5.toInt() else 0xFFCCCCCC.toInt()
|
||||||
|
)
|
||||||
|
|
||||||
|
// 右侧连线
|
||||||
|
holder.lineRight.visibility = if (isLast) View.INVISIBLE else View.VISIBLE
|
||||||
|
holder.lineRight.setBackgroundColor(
|
||||||
|
if (isCompleted && position < currentIndex) 0xFF1C8CF5.toInt() else 0xFFCCCCCC.toInt()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = steps.size
|
||||||
|
|
||||||
|
class StepViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
val tvStepName: TextView = view.findViewById(R.id.tv_step_name)
|
||||||
|
val dotView: View = view.findViewById(R.id.view_dot)
|
||||||
|
val lineLeft: View = view.findViewById(R.id.view_line_left)
|
||||||
|
val lineRight: View = view.findViewById(R.id.view_line_right)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package com.lukouguoji.aerologic.page.log.detail
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.lukouguoji.aerologic.R
|
||||||
|
import com.lukouguoji.module_base.bean.StatusLogBean
|
||||||
|
|
||||||
|
class LogDetailTimelineAdapter : RecyclerView.Adapter<LogDetailTimelineAdapter.TimelineViewHolder>() {
|
||||||
|
|
||||||
|
private var items: List<StatusLogBean> = emptyList()
|
||||||
|
private var statusNameMap: Map<String, String> = emptyMap()
|
||||||
|
|
||||||
|
fun setData(list: List<StatusLogBean>, stepMap: Map<String, String> = emptyMap()) {
|
||||||
|
items = list
|
||||||
|
statusNameMap = stepMap
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TimelineViewHolder {
|
||||||
|
val view = LayoutInflater.from(parent.context)
|
||||||
|
.inflate(R.layout.item_log_timeline, parent, false)
|
||||||
|
return TimelineViewHolder(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: TimelineViewHolder, position: Int) {
|
||||||
|
val item = items[position]
|
||||||
|
val isFirst = position == 0
|
||||||
|
val isLast = position == items.size - 1
|
||||||
|
|
||||||
|
val statusName = statusNameMap[item.status] ?: item.status
|
||||||
|
holder.tvContent.text = if (statusName.isNotEmpty()) "$statusName ${item.opDate}" else item.opDate
|
||||||
|
holder.tvTime.text = item.content
|
||||||
|
|
||||||
|
// 最后一项(当前步骤)用绿色圆点
|
||||||
|
holder.dotView.setBackgroundResource(
|
||||||
|
if (isLast) R.drawable.bg_timeline_dot_green
|
||||||
|
else R.drawable.bg_timeline_dot_gray
|
||||||
|
)
|
||||||
|
|
||||||
|
// 第一项不显示顶部连线
|
||||||
|
holder.lineTop.visibility = if (isFirst) View.INVISIBLE else View.VISIBLE
|
||||||
|
|
||||||
|
// 最后一项不显示底部连线
|
||||||
|
holder.lineBottom.visibility = if (isLast) View.INVISIBLE else View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = items.size
|
||||||
|
|
||||||
|
class TimelineViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
val dotView: View = view.findViewById(R.id.view_dot)
|
||||||
|
val lineTop: View = view.findViewById(R.id.view_line_top)
|
||||||
|
val lineBottom: View = view.findViewById(R.id.view_line_bottom)
|
||||||
|
val tvContent: TextView = view.findViewById(R.id.tv_content)
|
||||||
|
val tvTime: TextView = view.findViewById(R.id.tv_time)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
package com.lukouguoji.aerologic.page.log.detail
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.lukouguoji.module_base.base.BaseViewModel
|
||||||
|
import com.lukouguoji.module_base.bean.LogBean
|
||||||
|
import com.lukouguoji.module_base.bean.StatusLogBean
|
||||||
|
import com.lukouguoji.module_base.common.Constant
|
||||||
|
import com.lukouguoji.module_base.http.net.NetApply
|
||||||
|
import com.lukouguoji.module_base.ktx.toRequestBody
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
data class StepInfo(val code: String, val name: String)
|
||||||
|
|
||||||
|
class LogDetailViewModel : BaseViewModel() {
|
||||||
|
|
||||||
|
val waybillNo = MutableLiveData("")
|
||||||
|
val waybillType = MutableLiveData("")
|
||||||
|
|
||||||
|
val statusLogList = MutableLiveData<List<StatusLogBean>>(emptyList())
|
||||||
|
|
||||||
|
// 流转状态步骤(根据运单类型动态设置)
|
||||||
|
val allSteps = MutableLiveData<List<StepInfo>>(emptyList())
|
||||||
|
|
||||||
|
// 操作详情中出现的步骤 code 集合
|
||||||
|
val activeStepCodes = MutableLiveData<Set<String>>(emptySet())
|
||||||
|
|
||||||
|
// 最新步骤的 code
|
||||||
|
val latestStepCode = MutableLiveData("")
|
||||||
|
|
||||||
|
// 当前完成到哪一步(索引),用于线条着色
|
||||||
|
val currentStepIndex = MutableLiveData(-1)
|
||||||
|
|
||||||
|
private var awbType = ""
|
||||||
|
|
||||||
|
// 国际出港步骤(来自 AwbGjcStatus.java)
|
||||||
|
private val gjcSteps = listOf(
|
||||||
|
StepInfo("1", "预录入"), StepInfo("2", "收运完成"),
|
||||||
|
StepInfo("3", "运抵申报"), StepInfo("4", "海关放行"),
|
||||||
|
StepInfo("5", "组装完成"), StepInfo("6", "复磅完成"),
|
||||||
|
StepInfo("7", "装载申报"), StepInfo("8", "航班关闭"),
|
||||||
|
StepInfo("9", "理货申报")
|
||||||
|
)
|
||||||
|
|
||||||
|
// 国际进港步骤(来自 AwbGjjStatus.java)
|
||||||
|
private val gjjSteps = listOf(
|
||||||
|
StepInfo("1", "原始舱单"), StepInfo("2", "分拣理货"),
|
||||||
|
StepInfo("3", "理货申报"), StepInfo("4", "海关放行"),
|
||||||
|
StepInfo("5", "柜台办结"), StepInfo("6", "提取出库")
|
||||||
|
)
|
||||||
|
|
||||||
|
fun initOnCreated(intent: Intent) {
|
||||||
|
// 优先从 ARouter 参数获取
|
||||||
|
val key = intent.getStringExtra(Constant.Key.KEY) ?: ""
|
||||||
|
awbType = intent.getStringExtra(Constant.Key.AWB_TYPE) ?: ""
|
||||||
|
|
||||||
|
// 如果没有 ARouter 参数,尝试从 LogBean 解析
|
||||||
|
if (key.isEmpty()) {
|
||||||
|
val json = intent.getStringExtra(Constant.Key.DATA) ?: ""
|
||||||
|
if (json.isNotEmpty()) {
|
||||||
|
val bean = Gson().fromJson(json, LogBean::class.java)
|
||||||
|
waybillNo.value = bean.key
|
||||||
|
awbType = bean.logType
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
waybillNo.value = key
|
||||||
|
}
|
||||||
|
|
||||||
|
waybillType.value = getAwbTypeName(awbType)
|
||||||
|
allSteps.value = if (awbType == "II") gjjSteps else gjcSteps
|
||||||
|
|
||||||
|
if (waybillNo.value?.isNotEmpty() == true) {
|
||||||
|
loadStatusList(waybillNo.value!!, awbType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadStatusList(key: String, logType: String) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
try {
|
||||||
|
// 注意:SelfLoginInterceptor 会把裸数组 [...] 包装成 {"data": [...]}
|
||||||
|
// 所以 API 返回类型必须是 BaseResultBean,从 .data 取实际列表
|
||||||
|
val result = withContext(Dispatchers.IO) {
|
||||||
|
NetApply.api.getLogStatusList(
|
||||||
|
mapOf(
|
||||||
|
"key" to key,
|
||||||
|
"awbType" to logType
|
||||||
|
).toRequestBody()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val list = result.data ?: emptyList()
|
||||||
|
statusLogList.value = list
|
||||||
|
|
||||||
|
if (list.isNotEmpty()) {
|
||||||
|
// 提取所有出现的 status code(用 status 字段匹配)
|
||||||
|
val codes = list.mapNotNull { item ->
|
||||||
|
item.status.ifEmpty { null }
|
||||||
|
}.toSet()
|
||||||
|
activeStepCodes.value = codes
|
||||||
|
|
||||||
|
// 最新节点 = 列表最后一条的 status
|
||||||
|
val latestCode = list.last().status
|
||||||
|
latestStepCode.value = latestCode
|
||||||
|
|
||||||
|
// 计算最新节点在步骤列表中的索引
|
||||||
|
val steps = allSteps.value ?: emptyList()
|
||||||
|
val index = steps.indexOfFirst { step -> step.code == latestCode }
|
||||||
|
currentStepIndex.value = if (index >= 0) index else -1
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAwbTypeName(logType: String): String {
|
||||||
|
return when (logType) {
|
||||||
|
"CI" -> "国内进港"
|
||||||
|
"CO" -> "国内出港"
|
||||||
|
"II" -> "国际进港"
|
||||||
|
"IO" -> "国际出港"
|
||||||
|
else -> logType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package com.lukouguoji.aerologic.page.log.list
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import com.alibaba.android.arouter.facade.annotation.Route
|
||||||
|
import com.lukouguoji.aerologic.R
|
||||||
|
import com.lukouguoji.aerologic.databinding.ActivityLogQueryBinding
|
||||||
|
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||||
|
import com.lukouguoji.module_base.ktx.getLifecycleOwner
|
||||||
|
import com.lukouguoji.module_base.router.ARouterConstants
|
||||||
|
|
||||||
|
@Route(path = ARouterConstants.ACTIVITY_URL_LOG_QUERY)
|
||||||
|
class LogQueryActivity : BaseBindingActivity<ActivityLogQueryBinding, LogQueryViewModel>() {
|
||||||
|
|
||||||
|
override fun layoutId(): Int {
|
||||||
|
return R.layout.activity_log_query
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun viewModelClass(): Class<LogQueryViewModel> {
|
||||||
|
return LogQueryViewModel::class.java
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||||
|
setBackArrow("日志查询")
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
viewModel.pageModel.bindSmartRefreshLayout(
|
||||||
|
binding.srl,
|
||||||
|
binding.rv,
|
||||||
|
viewModel,
|
||||||
|
getLifecycleOwner()
|
||||||
|
)
|
||||||
|
viewModel.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun start(context: Context) {
|
||||||
|
val starter = Intent(context, LogQueryActivity::class.java)
|
||||||
|
context.startActivity(starter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.lukouguoji.aerologic.page.log.list
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import com.lukouguoji.aerologic.databinding.ItemLogQueryBinding
|
||||||
|
import com.lukouguoji.aerologic.page.log.detail.LogDetailActivity
|
||||||
|
import com.lukouguoji.module_base.base.BaseViewHolder
|
||||||
|
import com.lukouguoji.module_base.bean.LogBean
|
||||||
|
|
||||||
|
class LogQueryViewHolder(view: View) : BaseViewHolder<LogBean, ItemLogQueryBinding>(view) {
|
||||||
|
|
||||||
|
override fun onBind(item: Any?, position: Int) {
|
||||||
|
val bean = getItemBean(item)
|
||||||
|
binding.bean = bean
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.lukouguoji.aerologic.page.log.list
|
||||||
|
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.lukouguoji.aerologic.R
|
||||||
|
import com.lukouguoji.module_base.base.BasePageViewModel
|
||||||
|
import com.lukouguoji.module_base.bean.LogBean
|
||||||
|
import com.lukouguoji.module_base.http.net.NetApply
|
||||||
|
import com.lukouguoji.module_base.ktx.formatDate
|
||||||
|
import com.lukouguoji.module_base.ktx.launchLoadingCollect
|
||||||
|
import com.lukouguoji.module_base.ktx.toRequestBody
|
||||||
|
import dev.utils.common.DateUtils
|
||||||
|
|
||||||
|
class LogQueryViewModel : BasePageViewModel() {
|
||||||
|
|
||||||
|
val startDate = MutableLiveData(DateUtils.getCurrentTime().formatDate())
|
||||||
|
val endDate = MutableLiveData("")
|
||||||
|
|
||||||
|
val keyWord = MutableLiveData("")
|
||||||
|
val operatorId = MutableLiveData("")
|
||||||
|
|
||||||
|
val count = MutableLiveData(0)
|
||||||
|
|
||||||
|
val itemLayoutId = R.layout.item_log_query
|
||||||
|
val itemViewHolder = LogQueryViewHolder::class.java
|
||||||
|
|
||||||
|
fun searchClick() {
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getData() {
|
||||||
|
launchLoadingCollect({
|
||||||
|
NetApply.api.getLogList(
|
||||||
|
mapOf(
|
||||||
|
"pageNum" to pageModel.page,
|
||||||
|
"pageSize" to pageModel.limit,
|
||||||
|
"startTime" to startDate.value,
|
||||||
|
"endTime" to endDate.value,
|
||||||
|
"key" to keyWord.value,
|
||||||
|
"opId" to operatorId.value,
|
||||||
|
).toRequestBody()
|
||||||
|
)
|
||||||
|
}) {
|
||||||
|
onSuccess = {
|
||||||
|
pageModel.handleListBean(it)
|
||||||
|
count.value = it.total
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,15 @@ import com.lukouguoji.aerologic.R
|
|||||||
import com.lukouguoji.aerologic.databinding.ActivityUldEditBinding
|
import com.lukouguoji.aerologic.databinding.ActivityUldEditBinding
|
||||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||||
import com.lukouguoji.module_base.common.Constant
|
import com.lukouguoji.module_base.common.Constant
|
||||||
|
import com.lukouguoji.module_base.common.DetailsPageType
|
||||||
|
import com.lxj.xpopup.XPopup
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ULD 新增 / 修改 / 详情(一页三态,标题按 pageType 切换)。
|
||||||
|
*
|
||||||
|
* 布局 id 不区分设备,平板/手机由资源限定符自动选择:
|
||||||
|
* layout-sw600dp/activity_uld_edit.xml(平板) / layout/activity_uld_edit.xml(手机)
|
||||||
|
*/
|
||||||
class UldEditActivity : BaseBindingActivity<ActivityUldEditBinding, UldEditViewModel>() {
|
class UldEditActivity : BaseBindingActivity<ActivityUldEditBinding, UldEditViewModel>() {
|
||||||
|
|
||||||
override fun layoutId() = R.layout.activity_uld_edit
|
override fun layoutId() = R.layout.activity_uld_edit
|
||||||
@@ -18,6 +26,26 @@ class UldEditActivity : BaseBindingActivity<ActivityUldEditBinding, UldEditViewM
|
|||||||
viewModel.initOnCreate(intent)
|
viewModel.initOnCreate(intent)
|
||||||
setBackArrow("ULD${viewModel.pageType.value!!.title}")
|
setBackArrow("ULD${viewModel.pageType.value!!.title}")
|
||||||
binding.viewModel = viewModel
|
binding.viewModel = viewModel
|
||||||
|
binding.activity = this
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 手机版专用交互(纯 UI) ====================
|
||||||
|
|
||||||
|
/** 详情态右上铅笔 → 关闭详情并进入修改页 */
|
||||||
|
fun onEditClick() {
|
||||||
|
start(this, viewModel.id, modify = true)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 状态行点击 → 底部选择面板(详情态只读不弹) */
|
||||||
|
fun onStatusRowClick() {
|
||||||
|
if (viewModel.pageType.value == DetailsPageType.Details) return
|
||||||
|
val options = viewModel.statusPhoneList
|
||||||
|
XPopup.Builder(this)
|
||||||
|
.asBottomList("请选择状态", options.map { it.key }.toTypedArray()) { position, _ ->
|
||||||
|
options.getOrNull(position)?.let { viewModel.onStatusSelected(it.value) }
|
||||||
|
}
|
||||||
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import com.lukouguoji.module_base.ktx.launchLoadingCollect
|
|||||||
import com.lukouguoji.module_base.ktx.noNull
|
import com.lukouguoji.module_base.ktx.noNull
|
||||||
import com.lukouguoji.module_base.ktx.showToast
|
import com.lukouguoji.module_base.ktx.showToast
|
||||||
import com.lukouguoji.module_base.ktx.toRequestBody
|
import com.lukouguoji.module_base.ktx.toRequestBody
|
||||||
|
import com.lukouguoji.module_base.util.DeviceUtil
|
||||||
|
import com.lukouguoji.module_base.util.DictUtils
|
||||||
import dev.DevUtils
|
import dev.DevUtils
|
||||||
import dev.utils.app.info.KeyValue
|
import dev.utils.app.info.KeyValue
|
||||||
|
|
||||||
@@ -29,24 +31,49 @@ class UldEditViewModel : BaseViewModel() {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
// 所属航司下拉列表(mock,后续替换为接口)
|
// 所属航司下拉列表(数据源:POST /typeCode/intCarrier)
|
||||||
val carrierList = MutableLiveData<List<KeyValue>>(
|
val carrierList = MutableLiveData<List<KeyValue>>(emptyList())
|
||||||
|
|
||||||
|
// ========== 手机版(5.5 寸手持端)专用 ==========
|
||||||
|
|
||||||
|
/** 来源选项(本地枚举;后端字段暂不支持,需求已登记 documents/后端接口对接问题清单.xlsx) */
|
||||||
|
val sourceEditList = MutableLiveData<List<KeyValue>>(
|
||||||
listOf(
|
listOf(
|
||||||
KeyValue("MU - 东方航空", "MU"),
|
KeyValue("空运", "空运"),
|
||||||
KeyValue("CA - 国航", "CA"),
|
KeyValue("陆运", "陆运"),
|
||||||
KeyValue("CZ - 南方航空", "CZ"),
|
|
||||||
KeyValue("HO - 吉祥航空", "HO"),
|
|
||||||
KeyValue("FM - 上海航空", "FM"),
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机版状态选项。设计稿为三态(可用/占用/维修),后端枚举当前仅 0/1,
|
||||||
|
* 按语义映射 可用=0 / 维修=1;「占用」待后端扩展枚举后放开(需求已登记清单)。
|
||||||
|
*/
|
||||||
|
val statusPhoneList = listOf(
|
||||||
|
KeyValue("可用", "0"),
|
||||||
|
KeyValue("维修", "1"),
|
||||||
|
)
|
||||||
|
|
||||||
fun initOnCreate(intent: Intent) {
|
fun initOnCreate(intent: Intent) {
|
||||||
id = intent.getStringExtra(Constant.Key.ID) ?: ""
|
id = intent.getStringExtra(Constant.Key.ID) ?: ""
|
||||||
val modify = intent.getBooleanExtra(Constant.Key.DATA, false)
|
val modify = intent.getBooleanExtra(Constant.Key.DATA, false)
|
||||||
pageType.value = if (id.isEmpty()) DetailsPageType.Add
|
pageType.value = if (id.isEmpty()) DetailsPageType.Add
|
||||||
else if (modify) DetailsPageType.Modify else DetailsPageType.Details
|
else if (modify) DetailsPageType.Modify else DetailsPageType.Details
|
||||||
|
|
||||||
getData()
|
if (id.isEmpty()) {
|
||||||
|
// 新增:直接加载航司列表
|
||||||
|
loadCarrierList(null)
|
||||||
|
// 手机版新增默认所在港 HFE(设计稿约定);平板无此预填,行为不变
|
||||||
|
if (DeviceUtil.isPhone()) {
|
||||||
|
uldBean.value = uldBean.value?.copy(airport = "HFE")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
getData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 手机版状态行选中回调(copy 重新赋值以触发标签样式刷新) */
|
||||||
|
fun onStatusSelected(statusValue: String) {
|
||||||
|
uldBean.value = uldBean.value?.copy(status = statusValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getData() {
|
private fun getData() {
|
||||||
@@ -56,16 +83,35 @@ class UldEditViewModel : BaseViewModel() {
|
|||||||
}) {
|
}) {
|
||||||
onSuccess = {
|
onSuccess = {
|
||||||
uldBean.value = it.data ?: ULDBean()
|
uldBean.value = it.data ?: ULDBean()
|
||||||
|
// 编辑/详情:数据加载完成后再加载字典,将已选航司置顶回填
|
||||||
|
loadCarrierList(uldBean.value?.carrier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun loadCarrierList(checkedValue: String?) {
|
||||||
|
DictUtils.getIntCarrierList(checkedValue = checkedValue?.ifEmpty { null }) {
|
||||||
|
carrierList.value = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun onSaveClick() {
|
fun onSaveClick() {
|
||||||
val bean = uldBean.value ?: return
|
val bean = uldBean.value ?: return
|
||||||
if (bean.uld.isBlank()) {
|
if (bean.uld.isBlank()) {
|
||||||
showToast("ULD编号不能为空")
|
showToast("ULD编号不能为空")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// 手机版按设计稿校验必填项(自重 / 入库时间);平板表单无入库时间项,保持原校验行为
|
||||||
|
if (DeviceUtil.isPhone()) {
|
||||||
|
if (bean.uldWeight.isBlank()) {
|
||||||
|
showToast("自重不能为空")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (bean.checkInDate.isBlank()) {
|
||||||
|
showToast("入库时间不能为空")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
val isAdd = pageType.value == DetailsPageType.Add
|
val isAdd = pageType.value == DetailsPageType.Add
|
||||||
launchLoadingCollect({
|
launchLoadingCollect({
|
||||||
if (isAdd) NetApply.api.saveUld(bean.toRequestBody())
|
if (isAdd) NetApply.api.saveUld(bean.toRequestBody())
|
||||||
@@ -73,7 +119,12 @@ class UldEditViewModel : BaseViewModel() {
|
|||||||
}) {
|
}) {
|
||||||
onSuccess = {
|
onSuccess = {
|
||||||
showToast(it.msg.noNull(if (isAdd) "新增成功" else "修改成功"))
|
showToast(it.msg.noNull(if (isAdd) "新增成功" else "修改成功"))
|
||||||
if (isAdd) uldBean.value = ULDBean() else getData()
|
if (isAdd) {
|
||||||
|
// 清空表单继续录入;手机版保持所在港默认 HFE(与进入页面时一致)
|
||||||
|
uldBean.value = if (DeviceUtil.isPhone()) ULDBean(airport = "HFE") else ULDBean()
|
||||||
|
} else {
|
||||||
|
getData()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,27 @@ package com.lukouguoji.aerologic.page.uld.list
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import androidx.databinding.ObservableBoolean
|
||||||
|
import com.alibaba.android.arouter.facade.annotation.Route
|
||||||
import com.lukouguoji.aerologic.R
|
import com.lukouguoji.aerologic.R
|
||||||
import com.lukouguoji.aerologic.databinding.ActivityUldListBinding
|
import com.lukouguoji.aerologic.databinding.ActivityUldListBinding
|
||||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||||
|
import com.lukouguoji.module_base.common.ConstantEvent
|
||||||
|
import com.lukouguoji.module_base.impl.FlowBus
|
||||||
|
import com.lukouguoji.module_base.impl.observe
|
||||||
import com.lukouguoji.module_base.ktx.addOnItemClickListener
|
import com.lukouguoji.module_base.ktx.addOnItemClickListener
|
||||||
import com.lukouguoji.module_base.ktx.getLifecycleOwner
|
import com.lukouguoji.module_base.ktx.getLifecycleOwner
|
||||||
|
import com.lukouguoji.module_base.ktx.showToast
|
||||||
|
import com.lukouguoji.module_base.model.ConfirmDialogModel
|
||||||
|
import com.lukouguoji.module_base.router.ARouterConstants
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ULD管理列表页。
|
||||||
|
*
|
||||||
|
* 布局 id 不区分设备,平板/手机由资源限定符自动选择:
|
||||||
|
* layout-sw600dp/activity_uld_list.xml(平板) / layout/activity_uld_list.xml(手机)
|
||||||
|
*/
|
||||||
|
@Route(path = ARouterConstants.ACTIVITY_URL_ULD_LIST)
|
||||||
class UldListActivity : BaseBindingActivity<ActivityUldListBinding, UldListViewModel>() {
|
class UldListActivity : BaseBindingActivity<ActivityUldListBinding, UldListViewModel>() {
|
||||||
|
|
||||||
override fun layoutId(): Int {
|
override fun layoutId(): Int {
|
||||||
@@ -19,9 +34,13 @@ class UldListActivity : BaseBindingActivity<ActivityUldListBinding, UldListViewM
|
|||||||
return UldListViewModel::class.java
|
return UldListViewModel::class.java
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 手机版筛选弹层显隐(仅 UI 状态,不涉及业务逻辑) */
|
||||||
|
val filterPanelVisible = ObservableBoolean(false)
|
||||||
|
|
||||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||||
setBackArrow("ULD管理")
|
setBackArrow("ULD管理")
|
||||||
binding.viewModel = viewModel
|
binding.viewModel = viewModel
|
||||||
|
binding.activity = this
|
||||||
viewModel.pageModel.bindSmartRefreshLayout(
|
viewModel.pageModel.bindSmartRefreshLayout(
|
||||||
binding.srl,
|
binding.srl,
|
||||||
binding.rv,
|
binding.rv,
|
||||||
@@ -29,6 +48,11 @@ class UldListActivity : BaseBindingActivity<ActivityUldListBinding, UldListViewM
|
|||||||
getLifecycleOwner()
|
getLifecycleOwner()
|
||||||
)
|
)
|
||||||
binding.rv.addOnItemClickListener(viewModel)
|
binding.rv.addOnItemClickListener(viewModel)
|
||||||
|
|
||||||
|
// 手机版卡片勾选变化 → 刷新全选与已选统计(平板 item 无勾选框,不会触发)
|
||||||
|
FlowBus.with<String>(ConstantEvent.EVENT_CHECK_CHANGED).observe(this) {
|
||||||
|
viewModel.onItemCheckChanged()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
@@ -36,6 +60,46 @@ class UldListActivity : BaseBindingActivity<ActivityUldListBinding, UldListViewM
|
|||||||
viewModel.refresh()
|
viewModel.refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 手机版专用交互(纯 UI,复用既有 ViewModel 字段) ====================
|
||||||
|
|
||||||
|
/** 手机版筛选弹层显隐切换 */
|
||||||
|
fun toggleFilterPanel() {
|
||||||
|
filterPanelVisible.set(!filterPanelVisible.get())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机版筛选:重置
|
||||||
|
*
|
||||||
|
* 只清空弹层内的四个条件(入库时间 / 进港航班号 / 所属航司 / 来源),不影响顶部搜索框。
|
||||||
|
*/
|
||||||
|
fun resetFilter() {
|
||||||
|
viewModel.checkInDateFilter.value = ""
|
||||||
|
viewModel.ifNoFilter.value = ""
|
||||||
|
viewModel.uldSuffix.value = ""
|
||||||
|
viewModel.sourceFilter.value = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 手机版筛选:确认 */
|
||||||
|
fun confirmFilter() {
|
||||||
|
filterPanelVisible.set(false)
|
||||||
|
viewModel.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 手机版批量删除(二次确认后逐条调用单条删除接口) */
|
||||||
|
fun showDeleteConfirmDialog() {
|
||||||
|
val selected = viewModel.getSelectedItems()
|
||||||
|
if (selected.isEmpty()) {
|
||||||
|
showToast("请选择要删除的ULD")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ConfirmDialogModel(
|
||||||
|
message = "确定要删除选中的 ${selected.size} 条ULD记录吗?",
|
||||||
|
title = "删除确认"
|
||||||
|
) {
|
||||||
|
viewModel.deleteSelected()
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun start(context: Context) {
|
fun start(context: Context) {
|
||||||
|
|||||||
@@ -4,13 +4,35 @@ import android.view.View
|
|||||||
import com.lukouguoji.aerologic.databinding.ItemUldListBinding
|
import com.lukouguoji.aerologic.databinding.ItemUldListBinding
|
||||||
import com.lukouguoji.module_base.base.BaseViewHolder
|
import com.lukouguoji.module_base.base.BaseViewHolder
|
||||||
import com.lukouguoji.module_base.bean.ULDBean
|
import com.lukouguoji.module_base.bean.ULDBean
|
||||||
|
import com.lukouguoji.module_base.common.ConstantEvent
|
||||||
|
import com.lukouguoji.module_base.impl.FlowBus
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ULD管理列表项 ViewHolder。
|
||||||
|
*
|
||||||
|
* 平板 / 手机共用:布局按资源限定符切换,本类不做设备判断。
|
||||||
|
* 平板独有 id(tv_modify / tv_delete 侧滑按钮)与手机独有 id(iv_check 勾选框)
|
||||||
|
* 在 Binding 基类中为 @Nullable,各自判空使用。
|
||||||
|
*/
|
||||||
class UldListViewHolder(view: View) : BaseViewHolder<ULDBean, ItemUldListBinding>(view) {
|
class UldListViewHolder(view: View) : BaseViewHolder<ULDBean, ItemUldListBinding>(view) {
|
||||||
override fun onBind(item: Any?, position: Int) {
|
override fun onBind(item: Any?, position: Int) {
|
||||||
val itemBean = getItemBean(item)!!
|
val itemBean = getItemBean(item)!!
|
||||||
binding.bean = itemBean
|
binding.bean = itemBean
|
||||||
|
|
||||||
|
// 点卡片进详情(两端共用,走 ViewModel.onItemClick 的 R.id.ll_content 分支)
|
||||||
notifyItemClick(position, binding.llContent)
|
notifyItemClick(position, binding.llContent)
|
||||||
notifyItemClick(position, binding.tvModify)
|
|
||||||
notifyItemClick(position, binding.tvDelete)
|
// 平板侧滑按钮(手机变体无此控件)
|
||||||
|
binding.tvModify?.let { notifyItemClick(position, it) }
|
||||||
|
binding.tvDelete?.let { notifyItemClick(position, it) }
|
||||||
|
|
||||||
|
// 手机版勾选框(平板变体无此控件):切换选中态并通知页面刷新全选/已选统计
|
||||||
|
binding.ivCheck?.setOnClickListener {
|
||||||
|
itemBean.checked.set(!itemBean.checked.get())
|
||||||
|
FlowBus.with<String>(ConstantEvent.EVENT_CHECK_CHANGED).tryEmit("check_changed")
|
||||||
|
binding.executePendingBindings()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.executePendingBindings()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import com.lukouguoji.module_base.ktx.showToast
|
|||||||
import com.lukouguoji.module_base.model.ConfirmDialogModel
|
import com.lukouguoji.module_base.model.ConfirmDialogModel
|
||||||
import com.lukouguoji.module_base.ktx.toRequestBody
|
import com.lukouguoji.module_base.ktx.toRequestBody
|
||||||
import com.lukouguoji.module_base.model.ScanModel
|
import com.lukouguoji.module_base.model.ScanModel
|
||||||
|
import com.lukouguoji.module_base.util.DictUtils
|
||||||
import dev.DevUtils
|
import dev.DevUtils
|
||||||
import dev.utils.app.info.KeyValue
|
import dev.utils.app.info.KeyValue
|
||||||
|
|
||||||
@@ -26,6 +27,27 @@ class UldListViewModel : BasePageViewModel() {
|
|||||||
val uldSuffix = MutableLiveData("")
|
val uldSuffix = MutableLiveData("")
|
||||||
val uldNo = MutableLiveData("")
|
val uldNo = MutableLiveData("")
|
||||||
|
|
||||||
|
// ========== 手机版(5.5 寸手持端)专用筛选条件 ==========
|
||||||
|
// 平板布局无对应控件,恒为空 → 不进请求参数,平板查询行为与改造前完全一致。
|
||||||
|
// 三个入参后端暂不支持(api-doc 已核对),已登记 documents/后端接口对接问题清单.xlsx,
|
||||||
|
// 按「以设计为准」的约定照传(后端静默忽略无副作用),后端支持后自动生效。
|
||||||
|
val checkInDateFilter = MutableLiveData("") // 入库时间
|
||||||
|
val ifNoFilter = MutableLiveData("") // 进港航班号
|
||||||
|
val sourceFilter = MutableLiveData("") // 来源:空运 / 陆运
|
||||||
|
|
||||||
|
/** 来源下拉(本地枚举,后端字段需求已登记清单) */
|
||||||
|
val sourceList = MutableLiveData<List<KeyValue>>(
|
||||||
|
listOf(
|
||||||
|
KeyValue("全部", ""),
|
||||||
|
KeyValue("空运", "空运"),
|
||||||
|
KeyValue("陆运", "陆运"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// ========== 手机版批量选择状态 ==========
|
||||||
|
val isAllChecked = MutableLiveData(false)
|
||||||
|
val selectedCount = MutableLiveData("0")
|
||||||
|
|
||||||
// 状态下拉列表
|
// 状态下拉列表
|
||||||
val statusList = MutableLiveData<List<KeyValue>>(
|
val statusList = MutableLiveData<List<KeyValue>>(
|
||||||
listOf(
|
listOf(
|
||||||
@@ -35,17 +57,8 @@ class UldListViewModel : BasePageViewModel() {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
// 所属航司下拉列表(mock,后续替换为接口)
|
// 所属航司下拉列表(数据源:POST /typeCode/intCarrier)
|
||||||
val carrierList = MutableLiveData<List<KeyValue>>(
|
val carrierList = MutableLiveData<List<KeyValue>>(listOf(KeyValue("全部", "")))
|
||||||
listOf(
|
|
||||||
KeyValue("全部", ""),
|
|
||||||
KeyValue("MU - 东方航空", "MU"),
|
|
||||||
KeyValue("CA - 国航", "CA"),
|
|
||||||
KeyValue("CZ - 南方航空", "CZ"),
|
|
||||||
KeyValue("HO - 吉祥航空", "HO"),
|
|
||||||
KeyValue("FM - 上海航空", "FM"),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
// 合计数量
|
// 合计数量
|
||||||
val count = MutableLiveData(0L)
|
val count = MutableLiveData(0L)
|
||||||
@@ -53,6 +66,13 @@ class UldListViewModel : BasePageViewModel() {
|
|||||||
val itemLayoutId = R.layout.item_uld_list
|
val itemLayoutId = R.layout.item_uld_list
|
||||||
val itemViewHolder = UldListViewHolder::class.java
|
val itemViewHolder = UldListViewHolder::class.java
|
||||||
|
|
||||||
|
init {
|
||||||
|
// 加载所属航司列表(addAll=true 保留“全部”作为筛选默认项)
|
||||||
|
DictUtils.getIntCarrierList(addAll = true) {
|
||||||
|
carrierList.value = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun getData() {
|
override fun getData() {
|
||||||
launchLoadingCollect({
|
launchLoadingCollect({
|
||||||
NetApply.api.getUldList(
|
NetApply.api.getUldList(
|
||||||
@@ -62,16 +82,75 @@ class UldListViewModel : BasePageViewModel() {
|
|||||||
"status" to status.value?.ifEmpty { null },
|
"status" to status.value?.ifEmpty { null },
|
||||||
"uldSuffix" to uldSuffix.value?.ifEmpty { null },
|
"uldSuffix" to uldSuffix.value?.ifEmpty { null },
|
||||||
"uld" to uldNo.value?.ifEmpty { null },
|
"uld" to uldNo.value?.ifEmpty { null },
|
||||||
|
// 手机版筛选维度(平板恒空不参与);后端暂不支持这三个入参,已登记清单
|
||||||
|
"checkInDate" to checkInDateFilter.value?.ifEmpty { null },
|
||||||
|
"ifNo" to ifNoFilter.value?.ifEmpty { null },
|
||||||
|
"source" to sourceFilter.value?.ifEmpty { null },
|
||||||
).toRequestBody()
|
).toRequestBody()
|
||||||
)
|
)
|
||||||
}) {
|
}) {
|
||||||
onSuccess = {
|
onSuccess = {
|
||||||
pageModel.handleListBean(it.toBaseListBean())
|
pageModel.handleListBean(it.toBaseListBean()) { updateCheckAllStatus() }
|
||||||
count.value = it.total
|
count.value = it.total
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========== 手机版:多选与批量删除 ==========
|
||||||
|
|
||||||
|
fun onItemCheckChanged() {
|
||||||
|
updateCheckAllStatus()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateCheckAllStatus() {
|
||||||
|
val list = pageModel.rv?.commonAdapter()?.items?.filterIsInstance<ULDBean>() ?: return
|
||||||
|
isAllChecked.value = list.isNotEmpty() && list.all { it.checked.get() }
|
||||||
|
selectedCount.value = list.count { it.checked.get() }.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toggleSelectAll() {
|
||||||
|
val list = pageModel.rv?.commonAdapter()?.items?.filterIsInstance<ULDBean>() ?: return
|
||||||
|
val shouldCheckAll = !(isAllChecked.value ?: false)
|
||||||
|
list.forEach { it.checked.set(shouldCheckAll) }
|
||||||
|
isAllChecked.value = shouldCheckAll
|
||||||
|
selectedCount.value = (if (shouldCheckAll) list.size else 0).toString()
|
||||||
|
pageModel.rv?.commonAdapter()?.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSelectedItems(): List<ULDBean> =
|
||||||
|
pageModel.rv?.commonAdapter()?.items?.filterIsInstance<ULDBean>()
|
||||||
|
?.filter { it.checked.get() } ?: emptyList()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除选中的 ULD。
|
||||||
|
*
|
||||||
|
* 后端仅有单条删除接口(/eqm/uld/deleteUld,批量接口需求已登记清单),
|
||||||
|
* 此处按队列逐条串行调用,全部完成后统一刷新;中途失败即停并提示。
|
||||||
|
*/
|
||||||
|
fun deleteSelected() {
|
||||||
|
val ulds = getSelectedItems().map { it.uld }
|
||||||
|
if (ulds.isEmpty()) {
|
||||||
|
showToast("请选择要删除的ULD")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
deleteQueue(ulds, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deleteQueue(ulds: List<String>, index: Int) {
|
||||||
|
if (index >= ulds.size) {
|
||||||
|
showToast("已删除 ${ulds.size} 条")
|
||||||
|
refresh()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
launchLoadingCollect({ NetApply.api.deleteUld(ulds[index]) }) {
|
||||||
|
onSuccess = { deleteQueue(ulds, index + 1) }
|
||||||
|
onFailed = { _, msg ->
|
||||||
|
showToast("删除 ${ulds[index]} 失败:${msg.noNull("未知错误")}")
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun onUldScanClick() {
|
fun onUldScanClick() {
|
||||||
ScanModel.startScan(DevUtils.getTopActivity(), Constant.RequestCode.ULD)
|
ScanModel.startScan(DevUtils.getTopActivity(), Constant.RequestCode.ULD)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import com.lukouguoji.aerologic.page.gnj.query.list.GnjQueryListActivity
|
|||||||
import com.lukouguoji.aerologic.page.gnj.stash.list.GnjStashListActivity
|
import com.lukouguoji.aerologic.page.gnj.stash.list.GnjStashListActivity
|
||||||
import com.lukouguoji.aerologic.page.gnj.unload.list.GnjUnloadListActivity
|
import com.lukouguoji.aerologic.page.gnj.unload.list.GnjUnloadListActivity
|
||||||
import com.lukouguoji.aerologic.page.log.list.LogListActivity
|
import com.lukouguoji.aerologic.page.log.list.LogListActivity
|
||||||
|
import com.lukouguoji.aerologic.page.log.list.LogQueryActivity
|
||||||
import com.lukouguoji.aerologic.page.message.list.MessageListActivity
|
import com.lukouguoji.aerologic.page.message.list.MessageListActivity
|
||||||
import com.lukouguoji.aerologic.page.telegram.list.TelegramListActivity
|
import com.lukouguoji.aerologic.page.telegram.list.TelegramListActivity
|
||||||
import com.lukouguoji.aerologic.page.test.PrintActivity
|
import com.lukouguoji.aerologic.page.test.PrintActivity
|
||||||
@@ -36,6 +37,7 @@ import com.lukouguoji.gnc.page.deposit.list.GncDepositListActivity
|
|||||||
import com.lukouguoji.gnc.page.distribution.home.GncDistributionHomeActivity
|
import com.lukouguoji.gnc.page.distribution.home.GncDistributionHomeActivity
|
||||||
import com.lukouguoji.gnc.page.fubang.list.GncFuBangListActivity
|
import com.lukouguoji.gnc.page.fubang.list.GncFuBangListActivity
|
||||||
import com.lukouguoji.gnc.page.shouyun.unlist.GncShouYunUnListActivity
|
import com.lukouguoji.gnc.page.shouyun.unlist.GncShouYunUnListActivity
|
||||||
|
import com.lukouguoji.gnj.activity.GnjChuKuListActivity
|
||||||
import com.lukouguoji.module_base.MyApplication
|
import com.lukouguoji.module_base.MyApplication
|
||||||
import com.lukouguoji.module_base.common.Constant
|
import com.lukouguoji.module_base.common.Constant
|
||||||
import com.lukouguoji.module_base.db.perference.SharedPreferenceUtil
|
import com.lukouguoji.module_base.db.perference.SharedPreferenceUtil
|
||||||
@@ -52,7 +54,7 @@ class HomeFragment : Fragment() {
|
|||||||
* TODO: 正式发布前务必设置为 false
|
* TODO: 正式发布前务必设置为 false
|
||||||
*/
|
*/
|
||||||
companion object {
|
companion object {
|
||||||
private const val DEV_AUTO_SELECT_MENU = true // 开发调试:自动选择菜单开关,正式发布前设为 false
|
private const val DEV_AUTO_SELECT_MENU = false // 开发调试:自动选择菜单开关,正式发布前设为 false
|
||||||
private const val DEV_AUTO_SELECT_MENU_ID = Constant.AuthName.IntImp // 自动选择的目标菜单
|
private const val DEV_AUTO_SELECT_MENU_ID = Constant.AuthName.IntImp // 自动选择的目标菜单
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +76,11 @@ class HomeFragment : Fragment() {
|
|||||||
|
|
||||||
val leftMenuList = initLeftMenuData()
|
val leftMenuList = initLeftMenuData()
|
||||||
rvLeft.adapter = HomeLeftAdapt(leftMenuList)
|
rvLeft.adapter = HomeLeftAdapt(leftMenuList)
|
||||||
rvRight.adapter = HomeRightAdapt(getRightMenu4Id(leftMenuList.first().id))
|
// 权限过滤后列表可能为空(账号无任何菜单权限),避免 first() 抛异常
|
||||||
|
val firstMenuId = leftMenuList.firstOrNull()?.id
|
||||||
|
rvRight.adapter = HomeRightAdapt(
|
||||||
|
if (firstMenuId != null) getRightMenu4Id(firstMenuId) else emptyList()
|
||||||
|
)
|
||||||
|
|
||||||
// ========== 开发调试:自动选择指定菜单 ==========
|
// ========== 开发调试:自动选择指定菜单 ==========
|
||||||
autoSelectMenuForDev()
|
autoSelectMenuForDev()
|
||||||
@@ -106,7 +112,9 @@ class HomeFragment : Fragment() {
|
|||||||
if (Constant.AuthName.Flight == leftMenuTemp.id) {
|
if (Constant.AuthName.Flight == leftMenuTemp.id) {
|
||||||
// ARouter.getInstance().build(ARouterConstants.ACTIVITY_URL_HANG_BAN_QUERY)
|
// ARouter.getInstance().build(ARouterConstants.ACTIVITY_URL_HANG_BAN_QUERY)
|
||||||
// .navigation(activity, Constant.RequestCode.home_left_hang_ban_query)
|
// .navigation(activity, Constant.RequestCode.home_left_hang_ban_query)
|
||||||
FlightQueryListActivity.start(requireContext())
|
// FlightQueryListActivity.start(requireContext()) // 已废弃
|
||||||
|
ARouter.getInstance().build(ARouterConstants.ACTIVITY_URL_HB_QUERY_LIST)
|
||||||
|
.navigation()
|
||||||
mPosition = oldPosition
|
mPosition = oldPosition
|
||||||
}
|
}
|
||||||
//货物查询
|
//货物查询
|
||||||
@@ -194,7 +202,7 @@ class HomeFragment : Fragment() {
|
|||||||
inner class LeftMenu(val id: String, val img: Int, val text: String)
|
inner class LeftMenu(val id: String, val img: Int, val text: String)
|
||||||
|
|
||||||
fun initLeftMenuData(): List<LeftMenu> {
|
fun initLeftMenuData(): List<LeftMenu> {
|
||||||
var list = arrayListOf<LeftMenu>()
|
val list = arrayListOf<LeftMenu>()
|
||||||
list.add(LeftMenu(Constant.AuthName.DomExp, R.mipmap.gncn_icon, "国内出港"))
|
list.add(LeftMenu(Constant.AuthName.DomExp, R.mipmap.gncn_icon, "国内出港"))
|
||||||
list.add(LeftMenu(Constant.AuthName.DomImp, R.mipmap.gnjg, "国内进港"))
|
list.add(LeftMenu(Constant.AuthName.DomImp, R.mipmap.gnjg, "国内进港"))
|
||||||
list.add(LeftMenu(Constant.AuthName.IntExp, R.mipmap.gjcn_icon, "国际出港"))
|
list.add(LeftMenu(Constant.AuthName.IntExp, R.mipmap.gjcn_icon, "国际出港"))
|
||||||
@@ -206,15 +214,15 @@ class HomeFragment : Fragment() {
|
|||||||
list.add(LeftMenu(Constant.AuthName.Comprehensive, R.mipmap.zhgl_icon, "综合管理"))
|
list.add(LeftMenu(Constant.AuthName.Comprehensive, R.mipmap.zhgl_icon, "综合管理"))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 左侧菜单 权限过滤
|
* 左侧菜单 权限过滤:仅保留接口下发、且含有二级权限的主菜单
|
||||||
* TODO: 暂时关闭权限筛选,方便开发调试
|
* auths 结构:{ 主菜单ID: [二级权限串, ...], ... }
|
||||||
*/
|
*/
|
||||||
// getAuthsObj()?.let {
|
getAuthsObj()?.let { authsObj ->
|
||||||
// val authsFilter = list.filter { m ->
|
return list.filter { m ->
|
||||||
// it.getJSONArray(m.id) != null && it.getJSONArray(m.id).size > 0
|
val arr = authsObj.getJSONArray(m.id)
|
||||||
// }
|
arr != null && arr.size > 0
|
||||||
// list = authsFilter as ArrayList<LeftMenu>
|
}
|
||||||
// }
|
}
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,7 +319,8 @@ class HomeFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
//出库
|
//出库
|
||||||
Constant.AuthName.GnjChuKuList -> {
|
Constant.AuthName.GnjChuKuList -> {
|
||||||
GnjMoveStashListActivity.start(requireContext())
|
ARouter.getInstance().build(ARouterConstants.ACTIVITY_URL_GNJ_CHU_KU_LIST)
|
||||||
|
.navigation()
|
||||||
}
|
}
|
||||||
//仓库管理
|
//仓库管理
|
||||||
Constant.AuthName.GnjWareHouse -> {
|
Constant.AuthName.GnjWareHouse -> {
|
||||||
@@ -548,7 +557,7 @@ class HomeFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
// 日志查询
|
// 日志查询
|
||||||
Constant.AuthName.ComprehensiveLog -> {
|
Constant.AuthName.ComprehensiveLog -> {
|
||||||
LogListActivity.start(requireContext())
|
LogQueryActivity.start(requireContext())
|
||||||
}
|
}
|
||||||
// ULD管理
|
// ULD管理
|
||||||
Constant.AuthName.ComprehensiveUld -> {
|
Constant.AuthName.ComprehensiveUld -> {
|
||||||
@@ -740,16 +749,7 @@ class HomeFragment : Fragment() {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
// 8. 出库交接
|
// 8. 出港理货
|
||||||
list.add(
|
|
||||||
RightMenu(
|
|
||||||
Constant.AuthName.GjcIntExpOutHandover,
|
|
||||||
R.drawable.img_gjc_chuku_jiaojie,
|
|
||||||
"出库交接"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
// 9. 出港理货
|
|
||||||
list.add(
|
list.add(
|
||||||
RightMenu(
|
RightMenu(
|
||||||
Constant.AuthName.GjcIntExpTally,
|
Constant.AuthName.GjcIntExpTally,
|
||||||
@@ -758,6 +758,15 @@ class HomeFragment : Fragment() {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 9. 出库交接
|
||||||
|
list.add(
|
||||||
|
RightMenu(
|
||||||
|
Constant.AuthName.GjcIntExpOutHandover,
|
||||||
|
R.drawable.img_gjc_chuku_jiaojie,
|
||||||
|
"出库交接"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
// 10. 出港移库
|
// 10. 出港移库
|
||||||
list.add(
|
list.add(
|
||||||
RightMenu(
|
RightMenu(
|
||||||
@@ -820,59 +829,59 @@ class HomeFragment : Fragment() {
|
|||||||
"电报解析"
|
"电报解析"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
list.add(
|
|
||||||
RightMenu(
|
|
||||||
Constant.AuthName.IntArrAirManifest,
|
|
||||||
R.mipmap.img_bwjx,
|
|
||||||
"原始舱单"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
list.add(
|
list.add(
|
||||||
RightMenu(
|
RightMenu(
|
||||||
Constant.AuthName.IntImpManifest,
|
Constant.AuthName.IntImpManifest,
|
||||||
R.mipmap.img_bwjx,
|
R.mipmap.gjj_jin_gang_cang_dan_icon,
|
||||||
"进港舱单"
|
"进港舱单"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
list.add(
|
||||||
|
RightMenu(
|
||||||
|
Constant.AuthName.IntArrAirManifest,
|
||||||
|
R.mipmap.gjj_yuan_shi_cang_dan_icon,
|
||||||
|
"原始舱单"
|
||||||
|
)
|
||||||
|
)
|
||||||
list.add(
|
list.add(
|
||||||
RightMenu(
|
RightMenu(
|
||||||
Constant.AuthName.IntImpTally,
|
Constant.AuthName.IntImpTally,
|
||||||
R.mipmap.img_bwjx,
|
R.mipmap.gjj_li_huo_bao_gao_icon,
|
||||||
"理货报告"
|
"理货报告"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
list.add(
|
list.add(
|
||||||
RightMenu(
|
RightMenu(
|
||||||
Constant.AuthName.GjjWareHouseActivity,
|
Constant.AuthName.GjjWareHouseActivity,
|
||||||
R.mipmap.gnj_cang_ku_icon,
|
R.drawable.gjc_cang_ku_icon,
|
||||||
"进港仓库"
|
"进港仓库"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
list.add(
|
list.add(
|
||||||
RightMenu(
|
RightMenu(
|
||||||
Constant.AuthName.IntImpPickUpRecord,
|
Constant.AuthName.IntImpPickUpRecord,
|
||||||
R.mipmap.gnj_cang_ku_icon,
|
R.mipmap.gjj_ti_qu_ji_lu_icon,
|
||||||
"提取记录"
|
"提取记录"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
list.add(
|
list.add(
|
||||||
RightMenu(
|
RightMenu(
|
||||||
Constant.AuthName.IntImpPickUpDLV,
|
Constant.AuthName.IntImpPickUpDLV,
|
||||||
R.mipmap.gnj_cang_ku_icon,
|
R.mipmap.gjj_chu_ku_icon,
|
||||||
"提取出库"
|
"提取出库"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
list.add(
|
list.add(
|
||||||
RightMenu(
|
RightMenu(
|
||||||
Constant.AuthName.GjjQueryListActivity,
|
Constant.AuthName.GjjQueryListActivity,
|
||||||
R.mipmap.img_bwjx,
|
R.mipmap.gjj_query_icon,
|
||||||
"进港查询"
|
"进港查询"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
list.add(
|
list.add(
|
||||||
RightMenu(
|
RightMenu(
|
||||||
Constant.AuthName.IntImpAccidentVisa,
|
Constant.AuthName.IntImpAccidentVisa,
|
||||||
R.mipmap.img_bwjx,
|
R.drawable.gjj_jgqz,
|
||||||
"事故签证"
|
"事故签证"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -967,13 +976,6 @@ class HomeFragment : Fragment() {
|
|||||||
"ULD管理"
|
"ULD管理"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
list.add(
|
|
||||||
RightMenu(
|
|
||||||
Constant.AuthName.ComprehensiveColdStorage,
|
|
||||||
com.lukouguoji.module_base.R.mipmap.gnc_cangku,
|
|
||||||
"冷库登记"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
@@ -982,13 +984,15 @@ class HomeFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 右侧菜单 权限过滤
|
* 右侧菜单 权限过滤:仅保留当前主菜单下、接口下发的二级入口
|
||||||
|
* 使用集合精确匹配,避免子串误判(如 AppIntExpAssemble 是 AppIntExpAssembleAllocate 的子串)
|
||||||
*/
|
*/
|
||||||
// TODO: 暂时关闭权限筛选
|
getAuthsObj()?.let { authsObj ->
|
||||||
// val authsFilter = list.filter { m ->
|
val authArr = authsObj.getJSONArray(id)
|
||||||
// SharedPreferenceUtil.getString(Constant.Share.authList).contains(m.id)
|
// trim:兜底后端下发的权限串可能带首尾空格(如 "AppDomImpManiFest "),避免精确匹配失败
|
||||||
// }
|
val authSet = authArr?.map { it.toString().trim() }?.toSet() ?: emptySet()
|
||||||
// list = authsFilter as ArrayList<RightMenu>
|
return list.filter { m -> authSet.contains(m.id) }
|
||||||
|
}
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
6
app/src/main/res/drawable/bg_step_current_badge.xml
Normal file
6
app/src/main/res/drawable/bg_step_current_badge.xml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="#4CAF50" />
|
||||||
|
<corners android:radius="4dp" />
|
||||||
|
</shape>
|
||||||
5
app/src/main/res/drawable/bg_step_dot_blue.xml
Normal file
5
app/src/main/res/drawable/bg_step_dot_blue.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="oval">
|
||||||
|
<solid android:color="#FF1C8CF5" />
|
||||||
|
</shape>
|
||||||
8
app/src/main/res/drawable/bg_step_dot_gray.xml
Normal file
8
app/src/main/res/drawable/bg_step_dot_gray.xml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="oval">
|
||||||
|
<stroke
|
||||||
|
android:width="1.5dp"
|
||||||
|
android:color="#CCCCCC" />
|
||||||
|
<solid android:color="#FFFFFF" />
|
||||||
|
</shape>
|
||||||
5
app/src/main/res/drawable/bg_step_dot_green.xml
Normal file
5
app/src/main/res/drawable/bg_step_dot_green.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="oval">
|
||||||
|
<solid android:color="#4CAF50" />
|
||||||
|
</shape>
|
||||||
5
app/src/main/res/drawable/bg_timeline_dot_gray.xml
Normal file
5
app/src/main/res/drawable/bg_timeline_dot_gray.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="oval">
|
||||||
|
<solid android:color="#CCCCCC" />
|
||||||
|
</shape>
|
||||||
5
app/src/main/res/drawable/bg_timeline_dot_green.xml
Normal file
5
app/src/main/res/drawable/bg_timeline_dot_green.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="oval">
|
||||||
|
<solid android:color="#4CAF50" />
|
||||||
|
</shape>
|
||||||
153
app/src/main/res/layout-sw600dp/activity_gnj_move_stash_list.xml
Normal file
153
app/src/main/res/layout-sw600dp/activity_gnj_move_stash_list.xml
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<import type="com.lukouguoji.module_base.ui.weight.search.layout.SearchLayoutType" />
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="com.lukouguoji.aerologic.page.gnj.move.stash.list.GnjMoveStashListViewModel" />
|
||||||
|
|
||||||
|
<!-- 平板不使用,仅为与手机变体保持 <variable> 一致(DataBinding 双变体强制约束) -->
|
||||||
|
<variable
|
||||||
|
name="activity"
|
||||||
|
type="com.lukouguoji.aerologic.page.gnj.move.stash.list.GnjMoveStashListActivity" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/color_f2"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<include layout="@layout/title_tool_bar" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="10dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
||||||
|
hint='@{"请选择业务类型"}'
|
||||||
|
list="@{viewModel.businessTypeList}"
|
||||||
|
type="@{SearchLayoutType.SPINNER}"
|
||||||
|
value="@={viewModel.businessType}"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
||||||
|
hint='@{"请输入运单号"}'
|
||||||
|
icon="@{@drawable/img_scan}"
|
||||||
|
setInputWaybill="@{true}"
|
||||||
|
setOnIconClickListener="@{()-> viewModel.waybillScanClick()}"
|
||||||
|
setRefreshCallBack="@{viewModel::refresh}"
|
||||||
|
setSearchListRefresh="@{viewModel::getWayBillList}"
|
||||||
|
type="@{SearchLayoutType.INPUT}"
|
||||||
|
value="@={viewModel.waybill}"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
||||||
|
hint='@{"请输入承运人"}'
|
||||||
|
type="@{SearchLayoutType.INPUT}"
|
||||||
|
value="@={viewModel.carrier}"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
style="@style/iv_search_action"
|
||||||
|
android:onClick="@{()-> viewModel.refresh()}"
|
||||||
|
android:src="@drawable/img_search" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingTop="10dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="15dp"
|
||||||
|
android:onClick="@{()->viewModel.checkAllClick()}"
|
||||||
|
android:text="全选" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/checkIcon"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_marginLeft="5dp"
|
||||||
|
android:onClick="@{()->viewModel.checkAllClick()}"
|
||||||
|
android:src="@drawable/img_check_all" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
<com.scwang.smart.refresh.layout.SmartRefreshLayout
|
||||||
|
android:id="@+id/srl"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/rv"
|
||||||
|
itemLayoutId="@{viewModel.itemLayoutId}"
|
||||||
|
viewHolder="@{viewModel.itemViewHolder}"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
tools:listitem="@layout/item_gnj_move_stash_list" />
|
||||||
|
|
||||||
|
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:background="@color/color_bottom_layout"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingHorizontal="15dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text='@{"合计:"+viewModel.count+"条,总件数:"+viewModel.number+",总重量:"+viewModel.weight+"KG"}'
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:text="合计:3条,总件数:212,总重量:342KG" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/tv_bottom_btn"
|
||||||
|
android:onClick="@{()-> viewModel.moveStashClick()}"
|
||||||
|
android:text="移库" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</layout>
|
||||||
231
app/src/main/res/layout-sw600dp/activity_log_detail.xml
Normal file
231
app/src/main/res/layout-sw600dp/activity_log_detail.xml
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="com.lukouguoji.aerologic.page.log.detail.LogDetailViewModel" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/color_f2"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<include layout="@layout/title_tool_bar" />
|
||||||
|
|
||||||
|
<androidx.core.widget.NestedScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:fillViewport="true">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="15dp">
|
||||||
|
|
||||||
|
<!-- 运单信息 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- 标题区 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:background="@drawable/bg_white_radius_top_8"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingHorizontal="15dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="运单信息"
|
||||||
|
android:textColor="#333333"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 分割线(贯穿卡片宽度) -->
|
||||||
|
<com.google.android.material.divider.MaterialDivider
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="#E7E7E7" />
|
||||||
|
|
||||||
|
<!-- 内容区 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_white_radius_bottom_8"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="30dp"
|
||||||
|
android:layout_marginEnd="15dp"
|
||||||
|
android:layout_marginVertical="12dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="运单号:"
|
||||||
|
android:textColor="#666666"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{viewModel.waybillNo}"
|
||||||
|
android:textColor="#333333"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="运单类型:"
|
||||||
|
android:textColor="#666666"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{viewModel.waybillType}"
|
||||||
|
android:textColor="#333333"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 流转状态 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="15dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- 标题区 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:background="@drawable/bg_white_radius_top_8"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingHorizontal="15dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="流转状态"
|
||||||
|
android:textColor="#333333"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 分割线 -->
|
||||||
|
<com.google.android.material.divider.MaterialDivider
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="#E7E7E7" />
|
||||||
|
|
||||||
|
<!-- 内容区 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_white_radius_bottom_8"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/ll_steps"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="23dp"
|
||||||
|
android:layout_marginEnd="15dp"
|
||||||
|
android:layout_marginVertical="12dp"
|
||||||
|
android:orientation="horizontal" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 操作详情 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="15dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- 标题区 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:background="@drawable/bg_white_radius_top_8"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingHorizontal="15dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="操作详情"
|
||||||
|
android:textColor="#333333"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 分割线 -->
|
||||||
|
<com.google.android.material.divider.MaterialDivider
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="#E7E7E7" />
|
||||||
|
|
||||||
|
<!-- 内容区 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_white_radius_bottom_8"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/rv_timeline"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:nestedScrollingEnabled="false"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</layout>
|
||||||
171
app/src/main/res/layout-sw600dp/activity_uld_edit.xml
Normal file
171
app/src/main/res/layout-sw600dp/activity_uld_edit.xml
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
<import type="com.lukouguoji.module_base.ui.weight.data.layout.DataLayoutType" />
|
||||||
|
<import type="com.lukouguoji.module_base.common.DetailsPageType" />
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="com.lukouguoji.aerologic.page.uld.edit.UldEditViewModel" />
|
||||||
|
<!-- 平板端不使用,但两个布局变体的 <variable> 必须一致(手机变体用它做详情态编辑入口与状态选择) -->
|
||||||
|
<variable
|
||||||
|
name="activity"
|
||||||
|
type="com.lukouguoji.aerologic.page.uld.edit.UldEditActivity" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/color_f2"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<include layout="@layout/title_tool_bar" />
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:fillViewport="true">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="15dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_white_radius_8"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="15dp">
|
||||||
|
|
||||||
|
<!-- Row 1: ULD编号 / 状态 / 自重 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
enable="@{viewModel.pageType == DetailsPageType.Add}"
|
||||||
|
hint='@{"请输入ULD编号"}'
|
||||||
|
title='@{"ULD编号"}'
|
||||||
|
titleLength="@{7}"
|
||||||
|
type="@{DataLayoutType.INPUT}"
|
||||||
|
value='@={viewModel.uldBean.uld}' />
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
||||||
|
hint='@{"请选择状态"}'
|
||||||
|
list="@{viewModel.statusList}"
|
||||||
|
title='@{"状态"}'
|
||||||
|
titleLength="@{5}"
|
||||||
|
type="@{DataLayoutType.SPINNER}"
|
||||||
|
value='@={viewModel.uldBean.status}' />
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
||||||
|
hint='@{"请输入自重"}'
|
||||||
|
title='@{"自重"}'
|
||||||
|
titleLength="@{5}"
|
||||||
|
type="@{DataLayoutType.INPUT}"
|
||||||
|
value='@={viewModel.uldBean.uldWeight}' />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Row 2: 最大装载容积 / 最大载重 / 所属航司 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
||||||
|
hint='@{"请输入最大装载容积"}'
|
||||||
|
title='@{"最大装载容积"}'
|
||||||
|
titleLength="@{7}"
|
||||||
|
type="@{DataLayoutType.INPUT}"
|
||||||
|
value='@={viewModel.uldBean.maxVolume}' />
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
||||||
|
hint='@{"请输入最大载重"}'
|
||||||
|
title='@{"最大载重"}'
|
||||||
|
titleLength="@{5}"
|
||||||
|
type="@{DataLayoutType.INPUT}"
|
||||||
|
value='@={viewModel.uldBean.maxWeight}' />
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
||||||
|
hint='@{"请选择所属航司"}'
|
||||||
|
list="@{viewModel.carrierList}"
|
||||||
|
title='@{"所属航司"}'
|
||||||
|
titleLength="@{5}"
|
||||||
|
type="@{DataLayoutType.SPINNER}"
|
||||||
|
value='@={viewModel.uldBean.carrier}' />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 备注(全行,多行输入) -->
|
||||||
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
||||||
|
hint='@{"请输入备注"}'
|
||||||
|
inputHeight="@{80}"
|
||||||
|
title='@{"备注"}'
|
||||||
|
titleLength="@{7}"
|
||||||
|
type="@{DataLayoutType.INPUT}"
|
||||||
|
value='@={viewModel.uldBean.remark}' />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 底部操作按钮 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:gravity="center"
|
||||||
|
visible="@{viewModel.pageType != DetailsPageType.Details}">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/tv_bottom_btn"
|
||||||
|
android:layout_width="120dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:onClick="@{()-> viewModel.onCancelClick()}"
|
||||||
|
android:text="取消" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/tv_bottom_btn"
|
||||||
|
android:layout_width="120dp"
|
||||||
|
android:onClick="@{()-> viewModel.onSaveClick()}"
|
||||||
|
android:text="保存" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</layout>
|
||||||
122
app/src/main/res/layout-sw600dp/activity_uld_list.xml
Normal file
122
app/src/main/res/layout-sw600dp/activity_uld_list.xml
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
<import type="com.lukouguoji.module_base.ui.weight.search.layout.SearchLayoutType" />
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="com.lukouguoji.aerologic.page.uld.list.UldListViewModel" />
|
||||||
|
<!-- 平板端不使用,但两个布局变体的 <variable> 必须一致(手机变体用它驱动筛选弹层) -->
|
||||||
|
<variable
|
||||||
|
name="activity"
|
||||||
|
type="com.lukouguoji.aerologic.page.uld.list.UldListActivity" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/color_f2"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<include layout="@layout/title_tool_bar" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="10dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
||||||
|
hint='@{"选择状态"}'
|
||||||
|
list="@{viewModel.statusList}"
|
||||||
|
type="@{SearchLayoutType.SPINNER}"
|
||||||
|
value="@={viewModel.status}"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0.33" />
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
||||||
|
hint='@{"选择所属航司"}'
|
||||||
|
list="@{viewModel.carrierList}"
|
||||||
|
type="@{SearchLayoutType.SPINNER}"
|
||||||
|
value="@={viewModel.uldSuffix}"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0.33" />
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
||||||
|
hint='@{"请输入ULD编号"}'
|
||||||
|
icon="@{@drawable/img_scan}"
|
||||||
|
setOnIconClickListener="@{()-> viewModel.onUldScanClick()}"
|
||||||
|
type="@{SearchLayoutType.INPUT}"
|
||||||
|
value="@={viewModel.uldNo}"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0.33" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center_vertical|start"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="24dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="36dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:onClick="@{()-> viewModel.refresh()}"
|
||||||
|
android:padding="2dp"
|
||||||
|
android:src="@drawable/img_search" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:onClick="@{()-> viewModel.onAddClick()}"
|
||||||
|
android:src="@drawable/img_add" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<com.scwang.smart.refresh.layout.SmartRefreshLayout
|
||||||
|
android:id="@+id/srl"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/rv"
|
||||||
|
itemLayoutId="@{viewModel.itemLayoutId}"
|
||||||
|
viewHolder="@{viewModel.itemViewHolder}"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
tools:listitem="@layout/item_uld_list" />
|
||||||
|
|
||||||
|
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:background="@color/white"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingHorizontal="15dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text='@{"合计:" + viewModel.count + "条"}'
|
||||||
|
android:textColor="@color/bottom_tool_tips_text_color"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</layout>
|
||||||
296
app/src/main/res/layout-sw600dp/item_gnj_move_stash_list.xml
Normal file
296
app/src/main/res/layout-sw600dp/item_gnj_move_stash_list.xml
Normal file
@@ -0,0 +1,296 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="bean"
|
||||||
|
type="com.lukouguoji.module_base.bean.MoveStashBean" />
|
||||||
|
|
||||||
|
<!-- 以下两个变量平板不使用,仅为与手机变体保持 <variable> 一致(DataBinding 双变体强制约束) -->
|
||||||
|
<variable
|
||||||
|
name="position"
|
||||||
|
type="Integer" />
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="activity"
|
||||||
|
type="com.lukouguoji.aerologic.page.gnj.move.stash.list.GnjMoveStashListActivity" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<!-- 外层容器承载间距 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="15dp"
|
||||||
|
android:layout_marginVertical="5dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- 侧滑布局 -->
|
||||||
|
<com.mcxtzhang.swipemenulib.SwipeMenuLayout
|
||||||
|
android:id="@+id/swipe_menu"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<!-- 主列表项容器 -->
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:id="@+id/ll"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_item"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="10dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_icon"
|
||||||
|
loadImage="@{bean.checked ? @drawable/img_plane_s : @drawable/img_plane}"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:src="@drawable/img_plane" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="10dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1.1"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
completeSpace="@{4}"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="运单号:" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{bean.wbNo}"
|
||||||
|
android:textColor="@color/colorPrimary"
|
||||||
|
tools:text="789165431" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0.8"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
completeSpace="@{4}"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="件数:" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text='@{bean.pc}' />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0.7"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
completeSpace="@{4}"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="重量:" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{bean.weight}" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0.8"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
completeSpace="@{4}"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="代理人:" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text='@{bean.agentCode}' />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1.1"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
completeSpace="@{5}"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="运单类型:" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text='@{bean.awbType}' />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1.1"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
completeSpace="@{4}"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="航班:" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{bean.flight}" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0.8"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
completeSpace="@{4}"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="始发港:" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{bean.origin}" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0.8"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
completeSpace="@{4}"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="起始站:" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{bean.dep}" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0.8"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
completeSpace="@{4}"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="目的港:" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{bean.dest}" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1.1"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
completeSpace="@{5}"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="品名:" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{bean.goods}" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 右侧箭头 -->
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginLeft="10dp"
|
||||||
|
android:src="@drawable/img_pda_right" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
<!-- 侧滑菜单区域 -->
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<!-- 编辑按钮 -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/btn_edit"
|
||||||
|
style="@style/tv_item_action"
|
||||||
|
android:background="@color/colorPrimary"
|
||||||
|
android:text="编辑" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
</com.mcxtzhang.swipemenulib.SwipeMenuLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</layout>
|
||||||
254
app/src/main/res/layout-sw600dp/item_uld_list.xml
Normal file
254
app/src/main/res/layout-sw600dp/item_uld_list.xml
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
<variable
|
||||||
|
name="bean"
|
||||||
|
type="com.lukouguoji.module_base.bean.ULDBean" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<com.mcxtzhang.swipemenulib.SwipeMenuLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:id="@+id/ll_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="15dp"
|
||||||
|
android:layout_marginVertical="5dp"
|
||||||
|
android:background="@drawable/bg_item"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="10dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_icon"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:src="@drawable/img_plane"
|
||||||
|
tools:src="@drawable/img_plane" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="10dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- 第一行:ULD编号 | 状态 | 自重 | 所属航司 | 最大装载容积 -->
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<!-- ULD编号 -->
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1.5"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="ULD编号:"
|
||||||
|
android:textSize="15sp"
|
||||||
|
completeSpace="@{5}" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{bean.uld}"
|
||||||
|
android:textColor="@color/colorPrimary"
|
||||||
|
android:textSize="15sp" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
<!-- 状态 -->
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0.8"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="状态:"
|
||||||
|
android:textSize="15sp"
|
||||||
|
completeSpace="@{3}" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{bean.statusName()}"
|
||||||
|
android:textColor='@{bean.status.equals("0") ? @color/text_green : @color/red}'
|
||||||
|
android:textSize="15sp" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
<!-- 自重 -->
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0.8"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="自重:"
|
||||||
|
android:textSize="15sp"
|
||||||
|
completeSpace="@{3}" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{bean.uldWeight}"
|
||||||
|
android:textSize="15sp" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
<!-- 所属航司 -->
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0.8"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="所属航司:"
|
||||||
|
android:textSize="15sp"
|
||||||
|
completeSpace="@{5}" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{bean.carrier}"
|
||||||
|
android:textSize="15sp" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
<!-- 最大装载容积 -->
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1.2"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="最大装载容积:"
|
||||||
|
android:textSize="15sp"
|
||||||
|
completeSpace="@{7}" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{bean.maxVolume}"
|
||||||
|
android:textSize="15sp" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
<!-- 第二行:最大载重 | 备注 -->
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp">
|
||||||
|
|
||||||
|
<!-- 最大载重 -->
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1.5"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="最大载重:"
|
||||||
|
android:textSize="15sp"
|
||||||
|
completeSpace="@{5}" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{bean.maxWeight}"
|
||||||
|
android:textSize="15sp" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
<!-- 备注 -->
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="3.6"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="备注:"
|
||||||
|
android:textSize="15sp"
|
||||||
|
completeSpace="@{3}" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{bean.remark}"
|
||||||
|
android:textSize="15sp" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginLeft="10dp"
|
||||||
|
android:src="@drawable/img_pda_right" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_modify"
|
||||||
|
style="@style/tv_item_action"
|
||||||
|
android:background="#8313ef"
|
||||||
|
android:text="修改" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_delete"
|
||||||
|
style="@style/tv_item_action"
|
||||||
|
android:background="@color/red"
|
||||||
|
android:text="删除" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
</com.mcxtzhang.swipemenulib.SwipeMenuLayout>
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
</layout>
|
||||||
@@ -13,265 +13,268 @@
|
|||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/backgroud_gray"
|
android:background="@color/color_f2"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<include layout="@layout/title_tool_bar" />
|
<include layout="@layout/title_tool_bar" />
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
<ScrollView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:layout_height="0dp">
|
android:fillViewport="true">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_height="match_parent">
|
android:padding="15dp">
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="10dp">
|
android:background="@drawable/bg_white_radius_8"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="15dp">
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
|
<!-- 第1行:航班日期、航班号、航程 -->
|
||||||
enable="@{false}"
|
<LinearLayout
|
||||||
title='@{"航班日期:"}'
|
android:layout_width="match_parent"
|
||||||
titleLength="@{5}"
|
|
||||||
type="@{DataLayoutType.INPUT}"
|
|
||||||
value='@{viewModel.dataBean.fdate}'
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1" />
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
enable="@{false}"
|
android:layout_width="0dp"
|
||||||
hint='@{" "}'
|
android:layout_height="wrap_content"
|
||||||
title='@{"航班号:"}'
|
android:layout_weight="1"
|
||||||
titleLength="@{5}"
|
enable="@{false}"
|
||||||
type="@{DataLayoutType.INPUT}"
|
title='@{"航班日期"}'
|
||||||
value='@{viewModel.dataBean.fno}'
|
titleLength="@{4}"
|
||||||
android:layout_width="0dp"
|
type="@{DataLayoutType.INPUT}"
|
||||||
|
value='@{viewModel.dataBean.fdate}' />
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
enable="@{false}"
|
||||||
|
title='@{"航班号"}'
|
||||||
|
titleLength="@{4}"
|
||||||
|
type="@{DataLayoutType.INPUT}"
|
||||||
|
value='@{viewModel.dataBean.fno}' />
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
enable="@{false}"
|
||||||
|
title='@{"航程"}'
|
||||||
|
titleLength="@{4}"
|
||||||
|
type="@{DataLayoutType.INPUT}"
|
||||||
|
value='@{viewModel.dataBean.range}' />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 第2行:地区类型、服务类型、经停站 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1" />
|
android:layout_marginTop="8dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
enable="@{false}"
|
android:layout_width="0dp"
|
||||||
hint='@{" "}'
|
android:layout_height="wrap_content"
|
||||||
title='@{"航程:"}'
|
android:layout_weight="1"
|
||||||
titleLength="@{5}"
|
enable="@{false}"
|
||||||
type="@{DataLayoutType.INPUT}"
|
title='@{"地区类型"}'
|
||||||
value='@{viewModel.dataBean.range}'
|
titleLength="@{4}"
|
||||||
android:layout_width="0dp"
|
type="@{DataLayoutType.INPUT}"
|
||||||
|
value='@{viewModel.dataBean.countryType}' />
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
enable="@{false}"
|
||||||
|
title='@{"服务类型"}'
|
||||||
|
titleLength="@{4}"
|
||||||
|
type="@{DataLayoutType.INPUT}"
|
||||||
|
value='@{viewModel.dataBean.serviceType}' />
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
enable="@{false}"
|
||||||
|
title='@{"经停站"}'
|
||||||
|
titleLength="@{4}"
|
||||||
|
type="@{DataLayoutType.INPUT}"
|
||||||
|
value='@{viewModel.dataBean.jtz}' />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 第3行:计划起飞、预计起飞、实际起飞 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1" />
|
android:layout_marginTop="8dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
</LinearLayout>
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
enable="@{false}"
|
||||||
|
title='@{"计划起飞"}'
|
||||||
|
titleLength="@{4}"
|
||||||
|
type="@{DataLayoutType.INPUT}"
|
||||||
|
value='@{viewModel.dataBean.scheduledTackOff}' />
|
||||||
|
|
||||||
<LinearLayout
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="10dp">
|
android:layout_weight="1"
|
||||||
|
enable="@{false}"
|
||||||
|
title='@{"预计起飞"}'
|
||||||
|
titleLength="@{4}"
|
||||||
|
type="@{DataLayoutType.INPUT}"
|
||||||
|
value='@{viewModel.dataBean.estimatedTakeOff}' />
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
enable="@{false}"
|
android:layout_width="0dp"
|
||||||
title='@{"地区类型:"}'
|
android:layout_height="wrap_content"
|
||||||
titleLength="@{5}"
|
android:layout_weight="1"
|
||||||
type="@{DataLayoutType.SPINNER}"
|
enable="@{false}"
|
||||||
value='@{viewModel.dataBean.countryType}'
|
title='@{"实际起飞"}'
|
||||||
android:layout_width="0dp"
|
titleLength="@{4}"
|
||||||
|
type="@{DataLayoutType.INPUT}"
|
||||||
|
value='@{viewModel.dataBean.actualTakeOff}' />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 第4行:计划降落、预计降落、实际降落 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1" />
|
android:layout_marginTop="8dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
enable="@{false}"
|
android:layout_width="0dp"
|
||||||
title='@{"服务类型:"}'
|
android:layout_height="wrap_content"
|
||||||
titleLength="@{5}"
|
android:layout_weight="1"
|
||||||
type="@{DataLayoutType.SPINNER}"
|
enable="@{false}"
|
||||||
value='@{viewModel.dataBean.serviceType}'
|
title='@{"计划降落"}'
|
||||||
android:layout_width="0dp"
|
titleLength="@{4}"
|
||||||
|
type="@{DataLayoutType.INPUT}"
|
||||||
|
value='@{viewModel.dataBean.scheduledArrival}' />
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
enable="@{false}"
|
||||||
|
title='@{"预计降落"}'
|
||||||
|
titleLength="@{4}"
|
||||||
|
type="@{DataLayoutType.INPUT}"
|
||||||
|
value='@{viewModel.dataBean.estimatedArrival}' />
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
enable="@{false}"
|
||||||
|
title='@{"实际降落"}'
|
||||||
|
titleLength="@{4}"
|
||||||
|
type="@{DataLayoutType.INPUT}"
|
||||||
|
value='@{viewModel.dataBean.actualArrival}' />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 第5行:飞行状态、航班状态、延误原因 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1" />
|
android:layout_marginTop="8dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
enable="@{false}"
|
android:layout_width="0dp"
|
||||||
title='@{"经停站:"}'
|
android:layout_height="wrap_content"
|
||||||
titleLength="@{5}"
|
android:layout_weight="1"
|
||||||
type="@{DataLayoutType.INPUT}"
|
enable="@{false}"
|
||||||
value='@{viewModel.dataBean.jtz}'
|
title='@{"飞行状态"}'
|
||||||
android:layout_width="0dp"
|
titleLength="@{4}"
|
||||||
|
type="@{DataLayoutType.INPUT}"
|
||||||
|
value='@{viewModel.dataBean.portCode}' />
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
enable="@{false}"
|
||||||
|
title='@{"航班状态"}'
|
||||||
|
titleLength="@{4}"
|
||||||
|
type="@{DataLayoutType.INPUT}"
|
||||||
|
value='@{viewModel.dataBean.flightStatus}' />
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
enable="@{false}"
|
||||||
|
title='@{"延误原因"}'
|
||||||
|
titleLength="@{4}"
|
||||||
|
type="@{DataLayoutType.INPUT}"
|
||||||
|
value='@{viewModel.dataBean.delayFreeText}' />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 第6行:机号、机型、机位 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1" />
|
android:layout_marginTop="8dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
</LinearLayout>
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
enable="@{false}"
|
||||||
|
title='@{"机号"}'
|
||||||
|
titleLength="@{4}"
|
||||||
|
type="@{DataLayoutType.INPUT}"
|
||||||
|
value='@{viewModel.dataBean.registration}' />
|
||||||
|
|
||||||
<LinearLayout
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="10dp">
|
android:layout_weight="1"
|
||||||
|
enable="@{false}"
|
||||||
|
title='@{"机型"}'
|
||||||
|
titleLength="@{4}"
|
||||||
|
type="@{DataLayoutType.INPUT}"
|
||||||
|
value='@{viewModel.dataBean.aircraftCode}' />
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
|
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
||||||
enable="@{false}"
|
android:layout_width="0dp"
|
||||||
hint='@{" "}'
|
android:layout_height="wrap_content"
|
||||||
title='@{"计划起飞:"}'
|
android:layout_weight="1"
|
||||||
titleLength="@{5}"
|
enable="@{false}"
|
||||||
type="@{DataLayoutType.INPUT}"
|
title='@{"机位"}'
|
||||||
value='@{viewModel.dataBean.scheduledTackOff}'
|
titleLength="@{4}"
|
||||||
android:layout_width="0dp"
|
type="@{DataLayoutType.INPUT}"
|
||||||
android:layout_height="wrap_content"
|
value='@{viewModel.dataBean.standId}' />
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
|
</LinearLayout>
|
||||||
enable="@{false}"
|
|
||||||
hint='@{" "}'
|
|
||||||
title='@{"预计起飞:"}'
|
|
||||||
titleLength="@{5}"
|
|
||||||
type="@{DataLayoutType.INPUT}"
|
|
||||||
value='@{viewModel.dataBean.estimatedTakeOff}'
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
|
|
||||||
enable="@{false}"
|
|
||||||
hint='@{" "}'
|
|
||||||
title='@{"实际起飞:"}'
|
|
||||||
titleLength="@{5}"
|
|
||||||
type="@{DataLayoutType.INPUT}"
|
|
||||||
value='@{viewModel.dataBean.actualTakeOff}'
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_margin="10dp">
|
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
|
|
||||||
enable="@{false}"
|
|
||||||
title='@{"计划降落:"}'
|
|
||||||
titleLength="@{5}"
|
|
||||||
type="@{DataLayoutType.INPUT}"
|
|
||||||
value='@{viewModel.dataBean.scheduledArrival}'
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
|
|
||||||
enable="@{false}"
|
|
||||||
hint='@{" "}'
|
|
||||||
title='@{"预计降落:"}'
|
|
||||||
titleLength="@{5}"
|
|
||||||
type="@{DataLayoutType.INPUT}"
|
|
||||||
value='@{viewModel.dataBean.estimatedArrival}'
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
|
|
||||||
enable="@{false}"
|
|
||||||
hint='@{" "}'
|
|
||||||
title='@{"实际降落:"}'
|
|
||||||
titleLength="@{5}"
|
|
||||||
type="@{DataLayoutType.INPUT}"
|
|
||||||
value='@{viewModel.dataBean.actualArrival}'
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_margin="10dp">
|
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
|
|
||||||
enable="@{false}"
|
|
||||||
title='@{"飞行状态:"}'
|
|
||||||
titleLength="@{5}"
|
|
||||||
type="@{DataLayoutType.SPINNER}"
|
|
||||||
value='@{viewModel.dataBean.portCode}'
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
|
|
||||||
enable="@{false}"
|
|
||||||
hint='@{" "}'
|
|
||||||
title='@{"航班状态:"}'
|
|
||||||
titleLength="@{5}"
|
|
||||||
type="@{DataLayoutType.SPINNER}"
|
|
||||||
value='@{viewModel.dataBean.flightStatus}'
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
|
|
||||||
enable="@{false}"
|
|
||||||
hint='@{" "}'
|
|
||||||
title='@{"延误原因:"}'
|
|
||||||
titleLength="@{5}"
|
|
||||||
type="@{DataLayoutType.INPUT}"
|
|
||||||
value='@{viewModel.dataBean.delayFreeText}'
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_margin="10dp">
|
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
|
|
||||||
enable="@{false}"
|
|
||||||
title='@{"机号:"}'
|
|
||||||
titleLength="@{5}"
|
|
||||||
type="@{DataLayoutType.INPUT}"
|
|
||||||
value='@{viewModel.dataBean.registration}'
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
|
|
||||||
enable="@{false}"
|
|
||||||
hint='@{" "}'
|
|
||||||
title='@{"机型:"}'
|
|
||||||
titleLength="@{5}"
|
|
||||||
type="@{DataLayoutType.INPUT}"
|
|
||||||
value='@{viewModel.dataBean.aircraftCode}'
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayout
|
|
||||||
enable="@{false}"
|
|
||||||
hint='@{" "}'
|
|
||||||
title='@{"机位:"}'
|
|
||||||
titleLength="@{5}"
|
|
||||||
type="@{DataLayoutType.INPUT}"
|
|
||||||
value='@{viewModel.dataBean.standId}'
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.core.widget.NestedScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="50dp"
|
|
||||||
android:background="#5c6890"
|
|
||||||
android:gravity="center_vertical|end"
|
|
||||||
android:paddingHorizontal="15dp">
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</layout>
|
</layout>
|
||||||
|
|||||||
332
app/src/main/res/layout/activity_gnj_move_stash_detail.xml
Normal file
332
app/src/main/res/layout/activity_gnj_move_stash_detail.xml
Normal file
@@ -0,0 +1,332 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
国内进港移库「运单详情」—— 5.5 寸手持端专属页面(无平板变体)
|
||||||
|
|
||||||
|
对应设计稿 11_进港移库 的「运单详情」页:
|
||||||
|
· 卡片一:蓝色表头(运单号 + 绿点 + 操作时间)+ 类型标签行(红「运单类型」+ 货物类型)
|
||||||
|
+ 品名大字 + 两列字段网格(件数/重量/特码/代理/出运路径/承运人)
|
||||||
|
· 卡片二:绿色表头「移库信息」+ 移库人 / 移库时间(仅已移库显示)
|
||||||
|
· 卡片三:橙色表头「异常照片」+ 三个虚线加号槽位(点击跳拍照上传页)
|
||||||
|
-->
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<import type="android.view.View" />
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="com.lukouguoji.aerologic.page.gnj.move.stash.detail.GnjMoveStashDetailViewModel" />
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="activity"
|
||||||
|
type="com.lukouguoji.aerologic.page.gnj.move.stash.detail.GnjMoveStashDetailActivity" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/phone_page_bg"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<include layout="@layout/title_tool_bar" />
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:fillViewport="true"
|
||||||
|
android:overScrollMode="never">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<!-- ==================== 卡片一:运单基本信息 ==================== -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_phone_card"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- 蓝色表头:运单号 + 绿点 + 操作时间 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_phone_card_header_blue"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="16dp"
|
||||||
|
android:paddingVertical="12dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@{viewModel.dataBean.wbNo}"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="17sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="8dp"
|
||||||
|
android:layout_height="8dp"
|
||||||
|
android:layout_marginEnd="6dp"
|
||||||
|
android:background="@drawable/bg_phone_dot_green" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{viewModel.dataBean.orDash(viewModel.dataBean.opDate)}"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<!-- 类型标签行:运单类型(红标签) + 货物类型 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="22dp"
|
||||||
|
android:background="@drawable/bg_phone_tag_red"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingHorizontal="8dp"
|
||||||
|
android:text="@{viewModel.dataBean.orDash(viewModel.dataBean.awbType)}"
|
||||||
|
android:textColor="@color/phone_tag_red_text"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="14dp"
|
||||||
|
android:layout_marginHorizontal="10dp"
|
||||||
|
android:background="@color/phone_divider" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@{viewModel.dataBean.orDash(viewModel.dataBean.cargoType)}"
|
||||||
|
android:textColor="@color/phone_text_body"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 品名(主字段大字) -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:text="@{viewModel.dataBean.orDash(viewModel.dataBean.goods)}"
|
||||||
|
android:textColor="@color/phone_text_strong"
|
||||||
|
android:textSize="22sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<!-- 第 1 行:件数 / 重量 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneKvItem
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
title='@{"件数"}'
|
||||||
|
value="@{viewModel.dataBean.orDash(viewModel.dataBean.pc)}" />
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneKvItem
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="32dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
title='@{"重量"}'
|
||||||
|
value='@{viewModel.dataBean.orDash(viewModel.dataBean.weight) + " kg"}' />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 第 2 行:特码 / 代理 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneKvItem
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
title='@{"特码"}'
|
||||||
|
value="@{viewModel.dataBean.spCode}" />
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneKvItem
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="32dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
title='@{"代理"}'
|
||||||
|
value="@{viewModel.dataBean.agentDisplay}" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 第 3 行:出运路径 / 承运人 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneKvItem
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
title='@{"出运路径"}'
|
||||||
|
value="@{viewModel.dataBean.range}" />
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneKvItem
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="32dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
title='@{"承运人"}'
|
||||||
|
value="@{viewModel.dataBean.by1}" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- ==================== 卡片二:移库信息(仅已移库显示) ==================== -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:background="@drawable/bg_phone_card"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="@{viewModel.dataBean.isMoved ? View.VISIBLE : View.GONE}">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_phone_card_header_green"
|
||||||
|
android:paddingHorizontal="16dp"
|
||||||
|
android:paddingVertical="10dp"
|
||||||
|
android:text="移库信息"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="16dp"
|
||||||
|
android:paddingVertical="12dp">
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneKvItem
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
title='@{"移库人"}'
|
||||||
|
value="@{viewModel.dataBean.opId}" />
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneKvItem
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="32dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
title='@{"移库时间"}'
|
||||||
|
value="@{viewModel.dataBean.opDate}" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- ==================== 卡片三:异常照片 ==================== -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:background="@drawable/bg_phone_card"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_phone_card_header_orange"
|
||||||
|
android:paddingHorizontal="16dp"
|
||||||
|
android:paddingVertical="10dp"
|
||||||
|
android:text="异常照片"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<!-- 三个虚线加号槽位(等宽正方形由 weight + 固定高实现),点击进拍照上传页 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="96dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@drawable/bg_phone_photo_add"
|
||||||
|
android:gravity="center"
|
||||||
|
android:onClick="@{()-> activity.openPhoto()}"
|
||||||
|
android:text="+"
|
||||||
|
android:textColor="@color/phone_text_hint"
|
||||||
|
android:textSize="24sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="96dp"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@drawable/bg_phone_photo_add"
|
||||||
|
android:gravity="center"
|
||||||
|
android:onClick="@{()-> activity.openPhoto()}"
|
||||||
|
android:text="+"
|
||||||
|
android:textColor="@color/phone_text_hint"
|
||||||
|
android:textSize="24sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="96dp"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@drawable/bg_phone_photo_add"
|
||||||
|
android:gravity="center"
|
||||||
|
android:onClick="@{()-> activity.openPhoto()}"
|
||||||
|
android:text="+"
|
||||||
|
android:textColor="@color/phone_text_hint"
|
||||||
|
android:textSize="24sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</layout>
|
||||||
@@ -1,148 +1,166 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
<!--
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
国内进港移库 —— 5.5 寸手持端布局(平板变体见 layout-sw600dp/ 同名文件)
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
|
||||||
|
对应设计稿 documents/5.5寸手持端设计文件/11_进港移库/进港移库.html:
|
||||||
<data>
|
· 顶部搜索框(运单号,含扫码)+ 筛选弹层(航班日期 / 航班号 / 特码 / 运单类型)
|
||||||
|
· 「待移库 / 已移库」Tab 绑定 viewModel.moveState("0"/"1"),
|
||||||
<import type="com.lukouguoji.module_base.ui.weight.search.layout.SearchLayoutType" />
|
分别走 DomImpMove/search 与 DomImpMove/searchMoved 两个端点
|
||||||
|
· 已移库 Tab 下隐藏底部操作条(与设计稿一致)
|
||||||
<variable
|
· 卡片长按出「拍照」浮层(见 item_gnj_move_stash_list.xml)
|
||||||
name="viewModel"
|
-->
|
||||||
type="com.lukouguoji.aerologic.page.gnj.move.stash.list.GnjMoveStashListViewModel" />
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
</data>
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
<data>
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="@color/color_f2"
|
<import type="android.view.View" />
|
||||||
android:orientation="vertical">
|
|
||||||
|
<import type="com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayoutType" />
|
||||||
<include layout="@layout/title_tool_bar" />
|
|
||||||
|
<variable
|
||||||
<LinearLayout
|
name="viewModel"
|
||||||
android:layout_width="match_parent"
|
type="com.lukouguoji.aerologic.page.gnj.move.stash.list.GnjMoveStashListViewModel" />
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="10dp"
|
<variable
|
||||||
android:layout_marginTop="10dp"
|
name="activity"
|
||||||
android:gravity="center_vertical">
|
type="com.lukouguoji.aerologic.page.gnj.move.stash.list.GnjMoveStashListActivity" />
|
||||||
|
</data>
|
||||||
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
|
||||||
hint='@{"请选择业务类型"}'
|
<FrameLayout
|
||||||
list="@{viewModel.businessTypeList}"
|
android:layout_width="match_parent"
|
||||||
type="@{SearchLayoutType.SPINNER}"
|
android:layout_height="match_parent"
|
||||||
value="@={viewModel.businessType}"
|
android:background="@color/phone_page_bg">
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
<LinearLayout
|
||||||
android:layout_weight="1" />
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
android:orientation="vertical">
|
||||||
hint='@{"请输入运单号"}'
|
|
||||||
icon="@{@drawable/img_scan}"
|
<include layout="@layout/title_tool_bar" />
|
||||||
setInputWaybill="@{true}"
|
|
||||||
setOnIconClickListener="@{()-> viewModel.waybillScanClick()}"
|
<!-- ==================== 搜索行 ==================== -->
|
||||||
setRefreshCallBack="@{viewModel::refresh}"
|
<LinearLayout
|
||||||
setSearchListRefresh="@{viewModel::getWayBillList}"
|
android:layout_width="match_parent"
|
||||||
type="@{SearchLayoutType.INPUT}"
|
android:layout_height="wrap_content"
|
||||||
value="@={viewModel.waybill}"
|
android:background="@color/white"
|
||||||
android:layout_width="0dp"
|
android:orientation="vertical"
|
||||||
android:layout_height="wrap_content"
|
android:paddingHorizontal="16dp"
|
||||||
android:layout_weight="1" />
|
android:paddingTop="16dp"
|
||||||
|
android:paddingBottom="12dp">
|
||||||
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
|
||||||
hint='@{"请输入承运人"}'
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneSearchBar
|
||||||
type="@{SearchLayoutType.INPUT}"
|
android:layout_width="match_parent"
|
||||||
value="@={viewModel.carrier}"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="0dp"
|
hint='@{"搜索运单号"}'
|
||||||
android:layout_height="wrap_content"
|
setOnFilterClickListener="@{(v)-> activity.toggleFilterPanel()}"
|
||||||
android:layout_weight="1" />
|
setOnScanClickListener="@{(v)-> viewModel.waybillScanClick()}"
|
||||||
|
setRefreshCallBack="@{viewModel::refresh}"
|
||||||
<LinearLayout
|
upperCase="@{true}"
|
||||||
android:layout_width="0dp"
|
value="@={viewModel.waybill}" />
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1">
|
</LinearLayout>
|
||||||
|
|
||||||
<ImageView
|
<!-- ==================== 待移库 / 已移库 Tab ==================== -->
|
||||||
style="@style/iv_search_action"
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneStatusTab
|
||||||
android:onClick="@{()-> viewModel.refresh()}"
|
android:layout_width="match_parent"
|
||||||
android:src="@drawable/img_search" />
|
android:layout_height="wrap_content"
|
||||||
|
counts="@{viewModel.moveStateCounts}"
|
||||||
</LinearLayout>
|
setOnTabChanged="@{viewModel::refresh}"
|
||||||
|
tabs="@{viewModel.moveStateTabs}"
|
||||||
<View
|
value="@={viewModel.moveState}" />
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="0dp"
|
<View
|
||||||
android:layout_weight="1" />
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1px"
|
||||||
<View
|
android:background="@color/phone_divider" />
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="0dp"
|
<!-- ==================== 列表 ==================== -->
|
||||||
android:layout_weight="1" />
|
<com.scwang.smart.refresh.layout.SmartRefreshLayout
|
||||||
|
android:id="@+id/srl"
|
||||||
</LinearLayout>
|
android:layout_width="match_parent"
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
android:layout_height="0dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_weight="1">
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center_vertical"
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:paddingTop="10dp">
|
android:id="@+id/rv"
|
||||||
|
android:layout_width="match_parent"
|
||||||
<TextView
|
android:layout_height="match_parent"
|
||||||
android:layout_width="wrap_content"
|
android:clipToPadding="false"
|
||||||
android:layout_height="wrap_content"
|
android:overScrollMode="never"
|
||||||
android:layout_marginLeft="15dp"
|
android:paddingBottom="12dp"
|
||||||
android:onClick="@{()->viewModel.checkAllClick()}"
|
itemLayoutId="@{viewModel.itemLayoutId}"
|
||||||
android:text="全选" />
|
viewHolder="@{viewModel.itemViewHolder}"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
<ImageView
|
tools:itemCount="3"
|
||||||
android:id="@+id/checkIcon"
|
tools:listitem="@layout/item_gnj_move_stash_list" />
|
||||||
android:layout_width="30dp"
|
|
||||||
android:layout_height="30dp"
|
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
|
||||||
android:layout_marginLeft="5dp"
|
|
||||||
android:onClick="@{()->viewModel.checkAllClick()}"
|
<!-- ==================== 底部操作条(已移库 Tab 下隐藏) ==================== -->
|
||||||
android:src="@drawable/img_check_all" />
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneBottomBar
|
||||||
|
android:layout_width="match_parent"
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
android:layout_height="wrap_content"
|
||||||
|
actionText='@{"移库"}'
|
||||||
<com.scwang.smart.refresh.layout.SmartRefreshLayout
|
allChecked="@{viewModel.isAllChecked}"
|
||||||
android:id="@+id/srl"
|
countText='@{"已选 " + viewModel.selectedCount + " 项"}'
|
||||||
android:layout_width="match_parent"
|
setOnActionClick="@{(v)-> viewModel.moveStashClick()}"
|
||||||
android:layout_height="0dp"
|
setOnAllCheckClick="@{(v)-> viewModel.toggleSelectAll()}"
|
||||||
android:layout_weight="1">
|
android:visibility="@{`1`.equals(viewModel.moveState) ? View.GONE : View.VISIBLE}" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
</LinearLayout>
|
||||||
android:id="@+id/rv"
|
|
||||||
itemLayoutId="@{viewModel.itemLayoutId}"
|
<!-- ==================== 筛选弹层 ==================== -->
|
||||||
viewHolder="@{viewModel.itemViewHolder}"
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneFilterPanel
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
panelVisible="@{activity.filterPanelVisible}"
|
||||||
tools:listitem="@layout/item_gnj_move_stash_list" />
|
setOnConfirmClick="@{(v)-> activity.confirmFilter()}"
|
||||||
|
setOnDismissClick="@{(v)-> activity.toggleFilterPanel()}"
|
||||||
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
|
setOnResetClick="@{(v)-> activity.resetFilter()}"
|
||||||
|
title='@{"筛选条件"}'>
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
<!-- 航班日期(入参 fdate) -->
|
||||||
android:layout_height="50dp"
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayout
|
||||||
android:background="@color/color_bottom_layout"
|
android:layout_width="match_parent"
|
||||||
android:gravity="center_vertical"
|
android:layout_height="wrap_content"
|
||||||
android:paddingHorizontal="15dp">
|
hint='@{"请选择航班日期"}'
|
||||||
|
title='@{"航班日期"}'
|
||||||
<TextView
|
type="@{PhoneDataLayoutType.DATE}"
|
||||||
android:layout_width="0dp"
|
value="@={viewModel.flightDate}" />
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
<!-- 航班号(入参 fno) -->
|
||||||
android:text='@{"合计:"+viewModel.count+"条,总件数:"+viewModel.number+",总重量:"+viewModel.weight+"KG"}'
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayout
|
||||||
android:textColor="@color/white"
|
android:layout_width="match_parent"
|
||||||
android:textSize="18sp"
|
android:layout_height="wrap_content"
|
||||||
android:textStyle="bold"
|
hint='@{"请输入航班号"}'
|
||||||
tools:text="合计:3条,总件数:212,总重量:342KG" />
|
title='@{"航班号"}'
|
||||||
|
type="@{PhoneDataLayoutType.INPUT}"
|
||||||
<TextView
|
value="@={viewModel.flightNo}" />
|
||||||
style="@style/tv_bottom_btn"
|
|
||||||
android:onClick="@{()-> viewModel.moveStashClick()}"
|
<!-- 特码(入参 spCode) -->
|
||||||
android:text="移库" />
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
</LinearLayout>
|
android:layout_height="wrap_content"
|
||||||
|
hint='@{"请选择特码"}'
|
||||||
</LinearLayout>
|
list="@{viewModel.spCodeList}"
|
||||||
</layout>
|
title='@{"特码"}'
|
||||||
|
type="@{PhoneDataLayoutType.SPINNER}"
|
||||||
|
value="@={viewModel.spCode}" />
|
||||||
|
|
||||||
|
<!-- 运单类型(入参 awbType,复用平板既有 businessType 字段与字典) -->
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
hint='@{"请选择运单类型"}'
|
||||||
|
list="@{viewModel.businessTypeList}"
|
||||||
|
title='@{"运单类型"}'
|
||||||
|
type="@{PhoneDataLayoutType.SPINNER}"
|
||||||
|
value="@={viewModel.businessType}" />
|
||||||
|
|
||||||
|
</com.lukouguoji.module_base.ui.weight.phone.PhoneFilterPanel>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
</layout>
|
||||||
|
|||||||
123
app/src/main/res/layout/activity_gnj_move_stash_photo.xml
Normal file
123
app/src/main/res/layout/activity_gnj_move_stash_photo.xml
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
国内进港移库「拍照上传」—— 5.5 寸手持端专属页面(无平板变体)
|
||||||
|
|
||||||
|
对应设计稿 11_进港移库/photo.html:
|
||||||
|
· 白卡「运单照片上传」+ 图片预览网格(复用公共 ImageSelectNewViewHolder,末位加号槽位)
|
||||||
|
· 底部两个按钮:拍照/上传(蓝) + 确认提交(绿)
|
||||||
|
|
||||||
|
提交走 DomImpMove/modify(pic/originalPic/picNumber 三字段规范)。
|
||||||
|
-->
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="com.lukouguoji.aerologic.page.gnj.move.stash.photo.GnjMoveStashPhotoViewModel" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/phone_page_bg"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<include layout="@layout/title_tool_bar" />
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:fillViewport="true"
|
||||||
|
android:overScrollMode="never">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_phone_card"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<!-- 标题:运单照片上传(副行展示运单号) -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="运单照片上传"
|
||||||
|
android:textColor="@color/phone_text_strong"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:text="@{viewModel.wbNo}"
|
||||||
|
android:textColor="@color/phone_text_body"
|
||||||
|
android:textSize="13sp"
|
||||||
|
tools:text="78133363573" />
|
||||||
|
|
||||||
|
<!-- 图片预览网格(末位加号槽位,长按出删除角标) -->
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/rv"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:overScrollMode="never"
|
||||||
|
itemLayoutId="@{viewModel.itemLayoutId}"
|
||||||
|
viewHolder="@{viewModel.itemViewHolder}"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
||||||
|
app:spanCount="3"
|
||||||
|
tools:itemCount="3" />
|
||||||
|
|
||||||
|
<!-- 底部按钮:拍照/上传(蓝) + 确认提交(绿) -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="44dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@drawable/bg_phone_btn_primary"
|
||||||
|
android:gravity="center"
|
||||||
|
android:onClick="@{()-> viewModel.pickClick()}"
|
||||||
|
android:text="拍照/上传"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="44dp"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@drawable/bg_phone_btn_green"
|
||||||
|
android:gravity="center"
|
||||||
|
android:onClick="@{()-> viewModel.submitClick()}"
|
||||||
|
android:text="确认提交"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</layout>
|
||||||
138
app/src/main/res/layout/activity_log_detail.xml
Normal file
138
app/src/main/res/layout/activity_log_detail.xml
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
操作日志详情(运单追踪)—— 手机版布局(5.5 寸手持端,最小宽度 < 600dp 时生效)
|
||||||
|
|
||||||
|
平板版为同名文件 layout-sw600dp/activity_log_detail.xml(横向步骤条 + 操作详情时间线),
|
||||||
|
两者是同一布局的资源变体,DataBinding 因此生成同一个 ActivityLogDetailBinding 类。
|
||||||
|
|
||||||
|
变体之间必须满足:
|
||||||
|
· DataBinding 变量完全一致:viewModel
|
||||||
|
· 保留 Activity 引用的控件 id:ll_steps / rv_timeline
|
||||||
|
|
||||||
|
手机版按设计稿「运单追踪」呈现:
|
||||||
|
· 顶卡:运单号 + 运单类型标签
|
||||||
|
· 流转状态:竖排时间线(LogDetailActivity 手机分支 buildVerticalSteps 动态填充 ll_steps)
|
||||||
|
· 平板的「操作详情」时间线列表在手机设计稿中不存在,rv_timeline 保留 id 但隐藏
|
||||||
|
-->
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="com.lukouguoji.aerologic.page.log.detail.LogDetailViewModel" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/phone_page_bg"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<include layout="@layout/title_tool_bar" />
|
||||||
|
|
||||||
|
<androidx.core.widget.NestedScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:fillViewport="true"
|
||||||
|
android:overScrollMode="never">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="12dp">
|
||||||
|
|
||||||
|
<!-- ==================== 运单卡片 ==================== -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_phone_card"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<!-- 运单号 + 运单类型标签 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@{viewModel.waybillNo}"
|
||||||
|
android:textColor="@color/phone_text_title"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:text="78133358743" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="22dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:background="@drawable/bg_phone_tag_indigo"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingHorizontal="10dp"
|
||||||
|
android:text="@{viewModel.waybillType}"
|
||||||
|
android:textColor="@color/phone_tag_indigo_text"
|
||||||
|
android:textSize="12sp"
|
||||||
|
tools:text="国际出港" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.divider.MaterialDivider
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1px"
|
||||||
|
android:layout_marginTop="14dp"
|
||||||
|
android:layout_marginBottom="14dp"
|
||||||
|
android:background="@color/phone_divider" />
|
||||||
|
|
||||||
|
<!-- 流转状态标题 -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="流转状态"
|
||||||
|
android:textColor="@color/phone_text_title"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<!-- 竖排时间线(Activity 手机分支动态填充) -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/ll_steps"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="14dp"
|
||||||
|
android:orientation="vertical" />
|
||||||
|
|
||||||
|
<!-- 平板的操作详情时间线,手机设计稿无此区块,保留 id 但隐藏 -->
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/rv_timeline"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 触底提示 -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:letterSpacing="0.3"
|
||||||
|
android:text="查询信息已触底"
|
||||||
|
android:textColor="@color/phone_text_hint"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</layout>
|
||||||
119
app/src/main/res/layout/activity_log_query.xml
Normal file
119
app/src/main/res/layout/activity_log_query.xml
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<import type="com.lukouguoji.module_base.ui.weight.search.layout.SearchLayoutType" />
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="com.lukouguoji.aerologic.page.log.list.LogQueryViewModel" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/color_f2"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<include layout="@layout/title_tool_bar" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="10dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
||||||
|
hint='@{"请选择航班日期起"}'
|
||||||
|
icon="@{@drawable/img_date}"
|
||||||
|
type="@{SearchLayoutType.DATE}"
|
||||||
|
value="@={viewModel.startDate}"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
||||||
|
hint='@{"请选择航班日期止"}'
|
||||||
|
icon="@{@drawable/img_date}"
|
||||||
|
type="@{SearchLayoutType.DATE}"
|
||||||
|
value="@={viewModel.endDate}"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
||||||
|
hint='@{"请输入关键字"}'
|
||||||
|
type="@{SearchLayoutType.INPUT}"
|
||||||
|
value="@={viewModel.keyWord}"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
||||||
|
hint='@{"请输入操作员ID"}'
|
||||||
|
type="@{SearchLayoutType.INPUT}"
|
||||||
|
value="@={viewModel.operatorId}"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center_vertical|start"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="24dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="36dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:onClick="@{()-> viewModel.searchClick()}"
|
||||||
|
android:padding="2dp"
|
||||||
|
android:src="@drawable/img_search" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<com.scwang.smart.refresh.layout.SmartRefreshLayout
|
||||||
|
android:id="@+id/srl"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/rv"
|
||||||
|
itemLayoutId="@{viewModel.itemLayoutId}"
|
||||||
|
viewHolder="@{viewModel.itemViewHolder}"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
tools:listitem="@layout/item_log_query" />
|
||||||
|
|
||||||
|
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:background="@color/white"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingHorizontal="15dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text='@{"合计:" + viewModel.count + "条"}'
|
||||||
|
android:textColor="@color/bottom_tool_tips_text_color"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:text="合计:1条" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</layout>
|
||||||
@@ -1,167 +1,267 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<layout xmlns:android="http://schemas.android.com/apk/res/android">
|
<!--
|
||||||
|
ULD新增 / 修改 / 详情 —— 手机版布局(5.5 寸手持端,最小宽度 < 600dp 时生效)
|
||||||
|
|
||||||
|
平板版为同名文件 layout-sw600dp/activity_uld_edit.xml(PadDataLayoutNew 三列表单),
|
||||||
|
两者是同一布局的资源变体,DataBinding 生成同一个 ActivityUldEditBinding 类。
|
||||||
|
|
||||||
|
变体之间必须满足:
|
||||||
|
· DataBinding 变量完全一致:viewModel / activity
|
||||||
|
→ UldEditViewModel 的加载/保存逻辑全部复用,平板端行为不受影响
|
||||||
|
|
||||||
|
一套布局覆盖设计稿三个页面(标题由 Activity 按 pageType 设置):
|
||||||
|
· ULD新增(Add) :可编辑 + 底部保存;所在港默认 HFE、必填星(编号/自重/入库时间)
|
||||||
|
· ULD修改(Modify):编号只读,其余可编辑 + 底部保存
|
||||||
|
· ULD详情(Details):全只读右对齐 + 顶栏右侧铅笔进入修改 + 额外展示最大装载容积/最大载重
|
||||||
|
|
||||||
|
「来源」「状态三态(占用)」为后端暂不支持的设计稿要求,
|
||||||
|
已登记 documents/后端接口对接问题清单.xlsx,UI 先行、后端补齐后自动生效。
|
||||||
|
-->
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
<data>
|
<data>
|
||||||
<import type="com.lukouguoji.module_base.ui.weight.data.layout.DataLayoutType" />
|
|
||||||
|
<import type="android.view.View" />
|
||||||
|
|
||||||
<import type="com.lukouguoji.module_base.common.DetailsPageType" />
|
<import type="com.lukouguoji.module_base.common.DetailsPageType" />
|
||||||
|
|
||||||
|
<import type="com.lukouguoji.module_base.ui.weight.phone.PhoneFormRowType" />
|
||||||
|
|
||||||
<variable
|
<variable
|
||||||
name="viewModel"
|
name="viewModel"
|
||||||
type="com.lukouguoji.aerologic.page.uld.edit.UldEditViewModel" />
|
type="com.lukouguoji.aerologic.page.uld.edit.UldEditViewModel" />
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="activity"
|
||||||
|
type="com.lukouguoji.aerologic.page.uld.edit.UldEditActivity" />
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/color_f2"
|
android:background="@color/phone_page_bg"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<include layout="@layout/title_tool_bar" />
|
<!-- 标题栏 + 详情态右侧铅笔(编辑入口) -->
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<include layout="@layout/title_tool_bar" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:onClick="@{()-> activity.onEditClick()}"
|
||||||
|
android:padding="14dp"
|
||||||
|
android:src="@drawable/ic_phone_edit"
|
||||||
|
android:visibility="@{viewModel.pageType == DetailsPageType.Details ? View.VISIBLE : View.GONE}" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:fillViewport="true">
|
android:fillViewport="true"
|
||||||
|
android:overScrollMode="never">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="15dp">
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<!-- ==================== 表单卡片 ==================== -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@drawable/bg_white_radius_8"
|
android:background="@drawable/bg_phone_card"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="15dp">
|
android:paddingHorizontal="16dp">
|
||||||
|
|
||||||
<!-- Row 1: ULD编号 / 状态 / 自重 -->
|
<!-- ULD编号:新增可输,修改/详情只读 -->
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
enable="@{viewModel.pageType == DetailsPageType.Add}"
|
||||||
|
hint='@{"请输入ULD编号"}'
|
||||||
|
required="@{viewModel.pageType == DetailsPageType.Add}"
|
||||||
|
title='@{"ULD编号"}'
|
||||||
|
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.INPUT}"
|
||||||
|
value="@={viewModel.uldBean.uld}" />
|
||||||
|
|
||||||
|
<!-- 状态:彩色标签 + 底部选择面板(详情态右对齐、无箭头) -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:minHeight="54dp"
|
||||||
|
android:onClick="@{()-> activity.onStatusRowClick()}"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
<TextView
|
||||||
android:layout_width="0dp"
|
android:layout_width="110dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:text="状态"
|
||||||
enable="@{viewModel.pageType == DetailsPageType.Add}"
|
android:textColor="@color/phone_text_label"
|
||||||
hint='@{"请输入ULD编号"}'
|
android:textSize="15sp" />
|
||||||
title='@{"ULD编号"}'
|
|
||||||
titleLength="@{7}"
|
|
||||||
type="@{DataLayoutType.INPUT}"
|
|
||||||
value='@={viewModel.uldBean.uld}' />
|
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
<!-- 详情态用这个占位把标签推到右侧 -->
|
||||||
|
<Space
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="1dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
android:visibility="@{viewModel.pageType == DetailsPageType.Details ? View.VISIBLE : View.GONE}" />
|
||||||
hint='@{"请选择状态"}'
|
|
||||||
list="@{viewModel.statusList}"
|
|
||||||
title='@{"状态"}'
|
|
||||||
titleLength="@{5}"
|
|
||||||
type="@{DataLayoutType.SPINNER}"
|
|
||||||
value='@={viewModel.uldBean.status}' />
|
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="22dp"
|
||||||
|
android:background="@{viewModel.uldBean.status.empty ? null : (viewModel.uldBean.isStatusAvailable ? @drawable/bg_phone_tag_green : (viewModel.uldBean.isStatusOccupied ? @drawable/bg_phone_tag_orange : @drawable/bg_phone_tag_red_light))}"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingHorizontal="8dp"
|
||||||
|
android:text='@{viewModel.uldBean.status.empty ? "请选择状态" : viewModel.uldBean.statusPhoneName}'
|
||||||
|
android:textColor="@{viewModel.uldBean.status.empty ? @color/phone_text_hint : (viewModel.uldBean.isStatusAvailable ? @color/phone_tag_green_text : (viewModel.uldBean.isStatusOccupied ? @color/phone_tag_orange_text : @color/phone_danger_text))}"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<!-- 编辑态右箭头 -->
|
||||||
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
android:gravity="end|center_vertical"
|
||||||
hint='@{"请输入自重"}'
|
android:orientation="horizontal"
|
||||||
title='@{"自重"}'
|
android:visibility="@{viewModel.pageType == DetailsPageType.Details ? View.GONE : View.VISIBLE}">
|
||||||
titleLength="@{5}"
|
|
||||||
type="@{DataLayoutType.INPUT}"
|
<ImageView
|
||||||
value='@={viewModel.uldBean.uldWeight}' />
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="16dp"
|
||||||
|
android:src="@drawable/ic_phone_chevron_right" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- Row 2: 最大装载容积 / 最大载重 / 所属航司 -->
|
<View
|
||||||
<LinearLayout
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1px"
|
||||||
|
android:background="@color/phone_divider" />
|
||||||
|
|
||||||
|
<!-- 所属航司 -->
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
||||||
android:orientation="horizontal">
|
hint='@{"请选择所属航司"}'
|
||||||
|
list="@{viewModel.carrierList}"
|
||||||
|
title='@{"所属航司"}'
|
||||||
|
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.SELECT}"
|
||||||
|
value="@={viewModel.uldBean.carrier}" />
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
<!-- 自重(kg) -->
|
||||||
android:layout_width="0dp"
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_weight="1"
|
android:layout_height="wrap_content"
|
||||||
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
||||||
hint='@{"请输入最大装载容积"}'
|
hint='@{"请输入自重"}'
|
||||||
title='@{"最大装载容积"}'
|
numeric="@{true}"
|
||||||
titleLength="@{7}"
|
required="@{viewModel.pageType == DetailsPageType.Add}"
|
||||||
type="@{DataLayoutType.INPUT}"
|
title='@{"自重(kg)"}'
|
||||||
value='@={viewModel.uldBean.maxVolume}' />
|
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.INPUT}"
|
||||||
|
value="@={viewModel.uldBean.uldWeight}" />
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
|
||||||
android:layout_width="0dp"
|
<!-- 最大装载容积(仅详情展示,与设计稿一致) -->
|
||||||
android:layout_height="wrap_content"
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
|
||||||
android:layout_weight="1"
|
android:layout_width="match_parent"
|
||||||
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
android:layout_height="wrap_content"
|
||||||
hint='@{"请输入最大载重"}'
|
title='@{"最大装载容积(m³)"}'
|
||||||
title='@{"最大载重"}'
|
type="@{PhoneFormRowType.TEXT}"
|
||||||
titleLength="@{5}"
|
value="@{viewModel.uldBean.maxVolume}"
|
||||||
type="@{DataLayoutType.INPUT}"
|
android:visibility="@{viewModel.pageType == DetailsPageType.Details ? View.VISIBLE : View.GONE}" />
|
||||||
value='@={viewModel.uldBean.maxWeight}' />
|
|
||||||
|
<!-- 最大载重(仅详情展示,与设计稿一致) -->
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
title='@{"最大载重(kg)"}'
|
||||||
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
type="@{PhoneFormRowType.TEXT}"
|
||||||
hint='@{"请选择所属航司"}'
|
value="@{viewModel.uldBean.maxWeight}"
|
||||||
list="@{viewModel.carrierList}"
|
android:visibility="@{viewModel.pageType == DetailsPageType.Details ? View.VISIBLE : View.GONE}" />
|
||||||
title='@{"所属航司"}'
|
|
||||||
titleLength="@{5}"
|
<!-- 进港航班号(绑 ifNo,语义待后端确认,已登记清单) -->
|
||||||
type="@{DataLayoutType.SPINNER}"
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
|
||||||
value='@={viewModel.uldBean.carrier}' />
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
</LinearLayout>
|
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
||||||
|
hint='@{"请输入进港航班号"}'
|
||||||
<!-- 备注(全行,多行输入) -->
|
title='@{"进港航班号"}'
|
||||||
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
|
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.INPUT}"
|
||||||
|
value="@={viewModel.uldBean.ifNo}" />
|
||||||
|
|
||||||
|
<!-- 所在港(新增默认 HFE,由 ViewModel 手机开关预填) -->
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
||||||
|
hint='@{"请输入所在港"}'
|
||||||
|
title='@{"所在港"}'
|
||||||
|
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.INPUT}"
|
||||||
|
value="@={viewModel.uldBean.airport}" />
|
||||||
|
|
||||||
|
<!-- 来源(设计稿顺序位于所在港之后;后端字段暂不支持,已登记清单,提交后端忽略) -->
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
||||||
|
hint='@{"请选择来源"}'
|
||||||
|
list="@{viewModel.sourceEditList}"
|
||||||
|
title='@{"来源"}'
|
||||||
|
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.SELECT}"
|
||||||
|
value="@={viewModel.uldBean.source}" />
|
||||||
|
|
||||||
|
<!-- 入库时间(绑 checkInDate,筛选/格式语义待后端确认,已登记清单) -->
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
||||||
|
hint='@{"请输入入库时间"}'
|
||||||
|
required="@{viewModel.pageType == DetailsPageType.Add}"
|
||||||
|
title='@{"入库时间"}'
|
||||||
|
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.DATE}"
|
||||||
|
value="@={viewModel.uldBean.checkInDate}" />
|
||||||
|
|
||||||
|
<!-- 备注 -->
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
enable="@{viewModel.pageType != DetailsPageType.Details}"
|
||||||
hint='@{"请输入备注"}'
|
hint='@{"请输入备注"}'
|
||||||
inputHeight="@{80}"
|
|
||||||
title='@{"备注"}'
|
title='@{"备注"}'
|
||||||
titleLength="@{3}"
|
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.INPUT}"
|
||||||
type="@{DataLayoutType.INPUT}"
|
value="@={viewModel.uldBean.remark}" />
|
||||||
value='@={viewModel.uldBean.remark}' />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- 底部操作按钮 -->
|
<!-- ==================== 保存按钮(详情态隐藏) ==================== -->
|
||||||
<LinearLayout
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="56dp"
|
android:layout_height="48dp"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
|
android:background="@drawable/bg_phone_btn_primary"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
visible="@{viewModel.pageType != DetailsPageType.Details}">
|
android:onClick="@{()-> viewModel.onSaveClick()}"
|
||||||
|
android:text="保存"
|
||||||
<TextView
|
android:textColor="@color/white"
|
||||||
style="@style/tv_bottom_btn"
|
android:textSize="16sp"
|
||||||
android:layout_width="120dp"
|
android:textStyle="bold"
|
||||||
android:layout_marginEnd="20dp"
|
android:visibility="@{viewModel.pageType == DetailsPageType.Details ? View.GONE : View.VISIBLE}" />
|
||||||
android:onClick="@{()-> viewModel.onCancelClick()}"
|
|
||||||
android:text="取消" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
style="@style/tv_bottom_btn"
|
|
||||||
android:layout_width="120dp"
|
|
||||||
android:onClick="@{()-> viewModel.onSaveClick()}"
|
|
||||||
android:text="保存" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</layout>
|
</layout>
|
||||||
|
|||||||
@@ -1,119 +1,175 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
ULD管理 —— 手机版布局(5.5 寸手持端,最小宽度 < 600dp 时生效)
|
||||||
|
|
||||||
|
平板版为同名文件 layout-sw600dp/activity_uld_list.xml,两者是同一布局的资源变体,
|
||||||
|
DataBinding 因此生成同一个 ActivityUldListBinding 类。
|
||||||
|
|
||||||
|
变体之间必须满足:
|
||||||
|
· DataBinding 变量完全一致:viewModel / activity
|
||||||
|
· 保留 Activity 中引用的控件 id:srl / rv
|
||||||
|
→ UldListViewModel 的业务逻辑与接口调用全部复用,平板端行为不受影响
|
||||||
|
|
||||||
|
交互差异(均复用既有 ViewModel 字段与接口):
|
||||||
|
· 平板 3 个横排搜索条 → 手机顶部搜索框(ULD 编号)+ 底部筛选弹层
|
||||||
|
(入库时间 / 进港航班号 / 所属航司 / 来源;前两项与来源的筛选入参后端暂不支持,
|
||||||
|
已登记 documents/后端接口对接问题清单.xlsx,后端支持后自动生效)
|
||||||
|
· 平板右上「新增」按钮 → 手机右下角浮动 + 按钮
|
||||||
|
· 平板侧滑单条删除 → 手机底部操作条(全选 + 已选统计 + 批量删除)
|
||||||
|
-->
|
||||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<data>
|
<data>
|
||||||
<import type="com.lukouguoji.module_base.ui.weight.search.layout.SearchLayoutType" />
|
|
||||||
|
<import type="com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayoutType" />
|
||||||
|
|
||||||
<variable
|
<variable
|
||||||
name="viewModel"
|
name="viewModel"
|
||||||
type="com.lukouguoji.aerologic.page.uld.list.UldListViewModel" />
|
type="com.lukouguoji.aerologic.page.uld.list.UldListViewModel" />
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="activity"
|
||||||
|
type="com.lukouguoji.aerologic.page.uld.list.UldListActivity" />
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
<LinearLayout
|
<FrameLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/color_f2"
|
android:background="@color/phone_page_bg">
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<include layout="@layout/title_tool_bar" />
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginHorizontal="10dp"
|
android:orientation="vertical">
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:gravity="center_vertical">
|
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
<include layout="@layout/title_tool_bar" />
|
||||||
hint='@{"选择状态"}'
|
|
||||||
list="@{viewModel.statusList}"
|
|
||||||
type="@{SearchLayoutType.SPINNER}"
|
|
||||||
value="@={viewModel.status}"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
|
||||||
hint='@{"选择所属航司"}'
|
|
||||||
list="@{viewModel.carrierList}"
|
|
||||||
type="@{SearchLayoutType.SPINNER}"
|
|
||||||
value="@={viewModel.uldSuffix}"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
|
||||||
hint='@{"请输入ULD编号"}'
|
|
||||||
icon="@{@drawable/img_scan}"
|
|
||||||
setOnIconClickListener="@{()-> viewModel.onUldScanClick()}"
|
|
||||||
type="@{SearchLayoutType.INPUT}"
|
|
||||||
value="@={viewModel.uldNo}"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
|
<!-- ==================== 搜索行 ==================== -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:background="@color/white"
|
||||||
android:gravity="center_vertical|start"
|
android:orientation="vertical"
|
||||||
android:orientation="horizontal"
|
android:paddingHorizontal="16dp"
|
||||||
android:paddingHorizontal="24dp">
|
android:paddingTop="16dp"
|
||||||
|
android:paddingBottom="12dp">
|
||||||
|
|
||||||
<ImageView
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneSearchBar
|
||||||
android:layout_width="36dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="36dp"
|
android:layout_height="wrap_content"
|
||||||
android:onClick="@{()-> viewModel.refresh()}"
|
hint='@{"搜索ULD编号"}'
|
||||||
android:padding="2dp"
|
setOnFilterClickListener="@{(v)-> activity.toggleFilterPanel()}"
|
||||||
android:src="@drawable/img_search" />
|
setOnScanClickListener="@{(v)-> viewModel.onUldScanClick()}"
|
||||||
|
setRefreshCallBack="@{viewModel::refresh}"
|
||||||
<ImageView
|
upperCase="@{true}"
|
||||||
android:layout_width="36dp"
|
value="@={viewModel.uldNo}" />
|
||||||
android:layout_height="36dp"
|
|
||||||
android:layout_marginLeft="16dp"
|
|
||||||
android:onClick="@{()-> viewModel.onAddClick()}"
|
|
||||||
android:padding="4dp"
|
|
||||||
android:src="@drawable/img_add" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
<!-- ==================== 列表 ==================== -->
|
||||||
|
<com.scwang.smart.refresh.layout.SmartRefreshLayout
|
||||||
<com.scwang.smart.refresh.layout.SmartRefreshLayout
|
android:id="@+id/srl"
|
||||||
android:id="@+id/srl"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_weight="1">
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/rv"
|
|
||||||
itemLayoutId="@{viewModel.itemLayoutId}"
|
|
||||||
viewHolder="@{viewModel.itemViewHolder}"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
android:layout_weight="1">
|
||||||
tools:listitem="@layout/item_uld_list" />
|
|
||||||
|
|
||||||
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/rv"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:overScrollMode="never"
|
||||||
|
android:paddingBottom="80dp"
|
||||||
|
itemLayoutId="@{viewModel.itemLayoutId}"
|
||||||
|
viewHolder="@{viewModel.itemViewHolder}"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
tools:itemCount="4"
|
||||||
|
tools:listitem="@layout/item_uld_list" />
|
||||||
|
|
||||||
<LinearLayout
|
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="50dp"
|
|
||||||
android:background="@color/white"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:paddingHorizontal="15dp">
|
|
||||||
|
|
||||||
<TextView
|
<!-- ==================== 底部操作条:全选 + 已选统计 + 批量删除 ==================== -->
|
||||||
android:layout_width="0dp"
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneBottomBar
|
||||||
android:layout_height="wrap_content"
|
actionDanger="@{true}"
|
||||||
android:layout_weight="1"
|
actionText='@{"删除"}'
|
||||||
android:text='@{"合计:" + viewModel.count + "条"}'
|
allChecked="@{viewModel.isAllChecked}"
|
||||||
android:textColor="@color/bottom_tool_tips_text_color"
|
countText='@{"已选 " + viewModel.selectedCount + " / " + viewModel.count + " 项"}'
|
||||||
android:textSize="18sp"
|
setOnActionClick="@{(v)-> activity.showDeleteConfirmDialog()}"
|
||||||
android:textStyle="bold" />
|
setOnAllCheckClick="@{(v)-> viewModel.toggleSelectAll()}"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
<!-- ==================== 右下角浮动新增按钮 ==================== -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="56dp"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:layout_marginBottom="92dp"
|
||||||
|
android:background="@drawable/bg_phone_fab"
|
||||||
|
android:elevation="6dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
android:onClick="@{()-> viewModel.onAddClick()}"
|
||||||
|
android:text="+"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="32sp" />
|
||||||
|
|
||||||
|
<!-- ==================== 筛选弹层 ==================== -->
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneFilterPanel
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:elevation="8dp"
|
||||||
|
panelVisible="@{activity.filterPanelVisible}"
|
||||||
|
setOnConfirmClick="@{(v)-> activity.confirmFilter()}"
|
||||||
|
setOnDismissClick="@{(v)-> activity.toggleFilterPanel()}"
|
||||||
|
setOnResetClick="@{(v)-> activity.resetFilter()}"
|
||||||
|
title='@{"筛选条件"}'>
|
||||||
|
|
||||||
|
<!-- 入库时间(后端筛选入参暂不支持,已登记清单) -->
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
hint='@{"请输入入库时间"}'
|
||||||
|
title='@{"入库时间"}'
|
||||||
|
type="@{PhoneDataLayoutType.DATE}"
|
||||||
|
value="@={viewModel.checkInDateFilter}" />
|
||||||
|
|
||||||
|
<!-- 进港航班号(后端筛选入参暂不支持,已登记清单) -->
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
hint='@{"请输入进港航班号"}'
|
||||||
|
title='@{"进港航班号"}'
|
||||||
|
type="@{PhoneDataLayoutType.INPUT}"
|
||||||
|
value="@={viewModel.ifNoFilter}" />
|
||||||
|
|
||||||
|
<!-- 所属航司(后端入参 uldSuffix,真实生效) -->
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
hint='@{"请选择所属航司"}'
|
||||||
|
list="@{viewModel.carrierList}"
|
||||||
|
title='@{"所属航司"}'
|
||||||
|
type="@{PhoneDataLayoutType.SPINNER}"
|
||||||
|
value="@={viewModel.uldSuffix}" />
|
||||||
|
|
||||||
|
<!-- 来源(后端字段暂不支持,已登记清单) -->
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
hint='@{"请选择来源"}'
|
||||||
|
list="@{viewModel.sourceList}"
|
||||||
|
title='@{"来源"}'
|
||||||
|
type="@{PhoneDataLayoutType.SPINNER}"
|
||||||
|
value="@={viewModel.sourceFilter}" />
|
||||||
|
|
||||||
|
</com.lukouguoji.module_base.ui.weight.phone.PhoneFilterPanel>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
</layout>
|
</layout>
|
||||||
|
|||||||
@@ -1,245 +1,227 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
<!--
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
国内进港移库 —— 列表项 5.5 寸手持端布局(平板变体见 layout-sw600dp/ 同名文件)
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
|
||||||
|
一套布局覆盖设计稿两种卡片形态,按 bean.isMoved 切换(载入时按端点打标):
|
||||||
<data>
|
· 待移库:圆形勾选框 + 蓝色运单号 + 橙色「待移库」标签
|
||||||
|
· 已移库:无勾选框 + 深色运单号 + 绿色对勾「已移库」
|
||||||
<variable
|
长按卡片出「拍照」浮层(跳拍照上传页),点浮层空白处收起。
|
||||||
name="bean"
|
-->
|
||||||
type="com.lukouguoji.module_base.bean.MoveStashBean" />
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
</data>
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
<data>
|
||||||
android:id="@+id/ll"
|
|
||||||
android:layout_width="match_parent"
|
<import type="android.view.View" />
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="15dp"
|
<variable
|
||||||
android:layout_marginVertical="5dp"
|
name="bean"
|
||||||
android:background="@drawable/bg_item"
|
type="com.lukouguoji.module_base.bean.MoveStashBean" />
|
||||||
android:orientation="horizontal"
|
|
||||||
android:padding="10dp">
|
<variable
|
||||||
|
name="position"
|
||||||
<ImageView
|
type="Integer" />
|
||||||
android:id="@+id/iv_icon"
|
|
||||||
loadImage="@{bean.checked ? @drawable/img_plane_s : @drawable/img_plane}"
|
<variable
|
||||||
android:layout_width="40dp"
|
name="activity"
|
||||||
android:layout_height="40dp"
|
type="com.lukouguoji.aerologic.page.gnj.move.stash.list.GnjMoveStashListActivity" />
|
||||||
android:layout_gravity="center"
|
</data>
|
||||||
android:src="@drawable/img_plane" />
|
|
||||||
|
<FrameLayout
|
||||||
<LinearLayout
|
android:layout_width="match_parent"
|
||||||
android:layout_width="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_marginHorizontal="12dp"
|
||||||
android:layout_marginLeft="10dp"
|
android:layout_marginTop="12dp">
|
||||||
android:orientation="vertical">
|
|
||||||
|
<LinearLayout
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
android:layout_width="match_parent"
|
||||||
android:layout_width="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content">
|
android:background="@drawable/bg_phone_card"
|
||||||
|
android:onLongClick="@{()-> activity.showCardActionPhone(bean)}"
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
android:orientation="vertical"
|
||||||
android:layout_width="0dp"
|
android:padding="16dp">
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1.1"
|
<!-- ==================== 卡片头部:勾选框 + 运单号 + 状态 ==================== -->
|
||||||
android:gravity="center_vertical">
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
<TextView
|
android:layout_height="wrap_content"
|
||||||
completeSpace="@{4}"
|
android:gravity="center_vertical"
|
||||||
android:layout_width="wrap_content"
|
android:orientation="horizontal">
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="运单号:" />
|
<!-- 圆形勾选框(已移库的记录不可勾选,隐藏) -->
|
||||||
|
<ImageView
|
||||||
<TextView
|
android:id="@+id/iv_icon"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="20dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="20dp"
|
||||||
android:text="@{bean.wbNo}"
|
android:layout_marginEnd="8dp"
|
||||||
android:textColor="@color/colorPrimary"
|
android:src="@drawable/ic_phone_check_round_unchecked"
|
||||||
tools:text="789165431" />
|
android:visibility="@{bean.isMoved ? View.GONE : View.VISIBLE}"
|
||||||
|
loadImage="@{bean.checked.get() ? @drawable/ic_phone_check_round_checked : @drawable/ic_phone_check_round_unchecked}" />
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
|
||||||
|
<!-- 运单号 -->
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
<TextView
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:gravity="center_vertical">
|
android:text="@{bean.wbNo}"
|
||||||
|
android:textColor="@{bean.isMoved ? @color/phone_text_title : @color/phone_primary}"
|
||||||
<TextView
|
android:textSize="15sp"
|
||||||
completeSpace="@{4}"
|
android:textStyle="bold" />
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
<!-- 待移库:橙色状态标签 -->
|
||||||
android:text="件数:" />
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
<TextView
|
android:layout_height="20dp"
|
||||||
android:layout_width="wrap_content"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_height="wrap_content"
|
android:background="@drawable/bg_phone_tag_orange"
|
||||||
android:text='@{bean.pc}' />
|
android:gravity="center"
|
||||||
|
android:paddingHorizontal="8dp"
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
android:text="待移库"
|
||||||
|
android:textColor="@color/phone_tag_orange_text"
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
android:textSize="11sp"
|
||||||
android:layout_width="0dp"
|
android:visibility="@{bean.isMoved ? View.GONE : View.VISIBLE}" />
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
<!-- 已移库:对勾 + 状态文字 -->
|
||||||
android:gravity="center_vertical">
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
<TextView
|
android:layout_height="wrap_content"
|
||||||
completeSpace="@{4}"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_width="wrap_content"
|
android:gravity="center_vertical"
|
||||||
android:layout_height="wrap_content"
|
android:orientation="horizontal"
|
||||||
android:text="重量:" />
|
android:visibility="@{bean.isMoved ? View.VISIBLE : View.GONE}">
|
||||||
|
|
||||||
<TextView
|
<ImageView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="16dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="16dp"
|
||||||
android:text="@{bean.weight}" />
|
android:src="@drawable/ic_phone_check_circle" />
|
||||||
|
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="0dp"
|
android:layout_marginStart="4dp"
|
||||||
android:layout_height="wrap_content"
|
android:text="已移库"
|
||||||
android:layout_weight="1"
|
android:textColor="@color/phone_text_title"
|
||||||
android:gravity="center_vertical">
|
android:textSize="13sp" />
|
||||||
|
|
||||||
<TextView
|
</LinearLayout>
|
||||||
completeSpace="@{4}"
|
|
||||||
android:layout_width="wrap_content"
|
</LinearLayout>
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="代理人:" />
|
<!-- ==================== 航班信息行 ==================== -->
|
||||||
|
<LinearLayout
|
||||||
<TextView
|
android:layout_width="match_parent"
|
||||||
android:layout_width="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_marginTop="12dp"
|
||||||
android:text='@{bean.agentCode}' />
|
android:layout_marginBottom="12dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
<ImageView
|
||||||
android:layout_width="0dp"
|
android:layout_width="14dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="14dp"
|
||||||
android:layout_weight="1.1"
|
android:src="@drawable/ic_phone_airplane" />
|
||||||
android:gravity="center_vertical">
|
|
||||||
|
<TextView
|
||||||
<TextView
|
android:layout_width="0dp"
|
||||||
completeSpace="@{5}"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="wrap_content"
|
android:layout_marginStart="4dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_weight="1"
|
||||||
android:text="运单类型:" />
|
android:text='@{"航班信息:" + bean.orDash(bean.flight)}'
|
||||||
|
android:textColor="@color/phone_text_body"
|
||||||
<TextView
|
android:textSize="13sp"
|
||||||
android:layout_width="wrap_content"
|
tools:text="航班信息:20260709/MU2311" />
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text='@{bean.awbType}' />
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
<!-- ==================== 统计框:特码 / 件数 / 重量 ==================== -->
|
||||||
|
<com.lukouguoji.module_base.ui.weight.phone.PhoneStatBox
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
label1='@{"特码"}'
|
||||||
android:layout_width="match_parent"
|
label2='@{"件数"}'
|
||||||
android:layout_height="wrap_content"
|
label3='@{"重量"}'
|
||||||
android:layout_marginTop="10dp">
|
value1="@{bean.orDash(bean.spCode)}"
|
||||||
|
value2='@{bean.orDash(bean.pc) + "件"}'
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
value3='@{bean.orDash(bean.weight) + "kg"}' />
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
<!-- ==================== 出运路径 ==================== -->
|
||||||
android:layout_weight="1.1"
|
<LinearLayout
|
||||||
android:gravity="center_vertical">
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
<TextView
|
android:layout_marginTop="12dp"
|
||||||
completeSpace="@{4}"
|
android:gravity="center_vertical"
|
||||||
android:layout_width="wrap_content"
|
android:orientation="horizontal">
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="航班:" />
|
<ImageView
|
||||||
|
android:layout_width="14dp"
|
||||||
<TextView
|
android:layout_height="14dp"
|
||||||
android:layout_width="wrap_content"
|
android:src="@drawable/ic_phone_location" />
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@{bean.flight}" />
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
android:layout_weight="1"
|
||||||
android:layout_width="0dp"
|
android:text='@{"出运路径:" + bean.orDash(bean.range)}'
|
||||||
android:layout_height="wrap_content"
|
android:textColor="@color/phone_text_body"
|
||||||
android:layout_weight="1"
|
android:textSize="13sp" />
|
||||||
android:gravity="center_vertical">
|
|
||||||
|
</LinearLayout>
|
||||||
<TextView
|
|
||||||
completeSpace="@{4}"
|
<!-- ==================== 查看详情 ==================== -->
|
||||||
android:layout_width="wrap_content"
|
<View
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:text="始发港:" />
|
android:layout_height="1px"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
<TextView
|
android:background="@color/phone_stat_bg" />
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
<LinearLayout
|
||||||
android:text="@{bean.origin}" />
|
android:id="@+id/ll_detail"
|
||||||
|
android:layout_width="match_parent"
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical|end"
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
android:orientation="horizontal"
|
||||||
android:layout_width="0dp"
|
android:paddingTop="12dp">
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
<TextView
|
||||||
android:gravity="center_vertical">
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
<TextView
|
android:text="查看详情"
|
||||||
completeSpace="@{4}"
|
android:textColor="@color/phone_primary"
|
||||||
android:layout_width="wrap_content"
|
android:textSize="14sp" />
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="起始站:" />
|
<ImageView
|
||||||
|
android:layout_width="16dp"
|
||||||
<TextView
|
android:layout_height="16dp"
|
||||||
android:layout_width="wrap_content"
|
android:src="@drawable/ic_phone_chevron_right" />
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@{bean.dep}" />
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
</LinearLayout>
|
||||||
|
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
<!-- ==================== 长按操作浮层:拍照 ==================== -->
|
||||||
android:layout_width="0dp"
|
<FrameLayout
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_weight="1"
|
android:layout_height="match_parent"
|
||||||
android:gravity="center_vertical">
|
android:background="#66000000"
|
||||||
|
android:clickable="true"
|
||||||
<TextView
|
android:onClick="@{()-> activity.hideCardActionPhone(bean)}"
|
||||||
completeSpace="@{4}"
|
android:visibility="@{bean.actionMenuVisible ? View.VISIBLE : View.GONE}">
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
<TextView
|
||||||
android:text="目的港:" />
|
android:layout_width="56dp"
|
||||||
|
android:layout_height="56dp"
|
||||||
<TextView
|
android:layout_gravity="center"
|
||||||
android:layout_width="wrap_content"
|
android:background="@drawable/bg_phone_fab_purple"
|
||||||
android:layout_height="wrap_content"
|
android:gravity="center"
|
||||||
android:text="@{bean.dest}" />
|
android:onClick="@{()-> activity.openPhoto(bean)}"
|
||||||
|
android:text="拍照"
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
android:textColor="@color/white"
|
||||||
|
android:textSize="12sp"
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
android:textStyle="bold" />
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
</FrameLayout>
|
||||||
android:layout_weight="1.1"
|
|
||||||
android:gravity="center_vertical">
|
</FrameLayout>
|
||||||
|
|
||||||
<TextView
|
</layout>
|
||||||
completeSpace="@{5}"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="品名:" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@{bean.goods}" />
|
|
||||||
|
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
|
||||||
|
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
|
||||||
</layout>
|
|
||||||
|
|||||||
133
app/src/main/res/layout/item_log_query.xml
Normal file
133
app/src/main/res/layout/item_log_query.xml
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="bean"
|
||||||
|
type="com.lukouguoji.module_base.bean.LogBean" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="15dp"
|
||||||
|
android:layout_marginVertical="5dp"
|
||||||
|
android:background="@drawable/bg_item"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="10dp">
|
||||||
|
|
||||||
|
<!-- 第一行:关键字 | 日志类型 | 操作员 | 操作时间 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1.0"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="关键字:"
|
||||||
|
android:textSize="15sp"
|
||||||
|
completeSpace="@{4}" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{bean.key}"
|
||||||
|
android:textSize="15sp" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1.0"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="日志类型:"
|
||||||
|
android:textSize="15sp"
|
||||||
|
completeSpace="@{5}" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{bean.logType}"
|
||||||
|
android:textSize="15sp" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0.8"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="操作员:"
|
||||||
|
android:textSize="15sp"
|
||||||
|
completeSpace="@{4}" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{bean.opId}"
|
||||||
|
android:textSize="15sp" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1.3"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="操作时间:"
|
||||||
|
android:textSize="15sp"
|
||||||
|
completeSpace="@{5}" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{bean.opTime}"
|
||||||
|
android:textSize="15sp" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 第二行:操作内容 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="操作内容:"
|
||||||
|
android:textSize="15sp"
|
||||||
|
completeSpace="@{5}" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{bean.content}"
|
||||||
|
android:textSize="15sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</layout>
|
||||||
52
app/src/main/res/layout/item_log_step.xml
Normal file
52
app/src/main/res/layout/item_log_step.xml
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingHorizontal="4dp">
|
||||||
|
|
||||||
|
<!-- 步骤名称 -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_step_name"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
|
||||||
|
<!-- 圆点和连线区域 -->
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:layout_marginTop="6dp">
|
||||||
|
|
||||||
|
<!-- 左侧连线 -->
|
||||||
|
<View
|
||||||
|
android:id="@+id/view_line_left"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="2dp"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_toLeftOf="@+id/view_dot"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:background="#FF1C8CF5" />
|
||||||
|
|
||||||
|
<!-- 圆点 -->
|
||||||
|
<View
|
||||||
|
android:id="@+id/view_dot"
|
||||||
|
android:layout_width="10dp"
|
||||||
|
android:layout_height="10dp"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:background="@drawable/bg_step_dot_blue" />
|
||||||
|
|
||||||
|
<!-- 右侧连线 -->
|
||||||
|
<View
|
||||||
|
android:id="@+id/view_line_right"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="2dp"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_toRightOf="@+id/view_dot"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:background="#FF1C8CF5" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
68
app/src/main/res/layout/item_log_timeline.xml
Normal file
68
app/src/main/res/layout/item_log_timeline.xml
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="15dp">
|
||||||
|
|
||||||
|
<!-- 左侧:圆点 + 连线 -->
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginRight="12dp">
|
||||||
|
|
||||||
|
<!-- 顶部连线 -->
|
||||||
|
<View
|
||||||
|
android:id="@+id/view_line_top"
|
||||||
|
android:layout_width="1.5dp"
|
||||||
|
android:layout_height="8dp"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:background="#E0E0E0" />
|
||||||
|
|
||||||
|
<!-- 圆点 -->
|
||||||
|
<View
|
||||||
|
android:id="@+id/view_dot"
|
||||||
|
android:layout_width="10dp"
|
||||||
|
android:layout_height="10dp"
|
||||||
|
android:layout_below="@+id/view_line_top"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:background="@drawable/bg_timeline_dot_gray" />
|
||||||
|
|
||||||
|
<!-- 底部连线 -->
|
||||||
|
<View
|
||||||
|
android:id="@+id/view_line_bottom"
|
||||||
|
android:layout_width="1.5dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_below="@+id/view_dot"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:background="#E0E0E0" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<!-- 右侧:内容 + 时间 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingBottom="20dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_content"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="#333333"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_time"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:textColor="#999999"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@@ -1,240 +1,148 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
ULD管理 —— 列表项手机版布局(5.5 寸手持端,最小宽度 < 600dp 时生效)
|
||||||
|
|
||||||
|
平板版为同名文件 layout-sw600dp/item_uld_list.xml(SwipeMenuLayout 侧滑修改/删除),
|
||||||
|
两者是同一布局的资源变体,DataBinding 生成同一个 ItemUldListBinding 类。
|
||||||
|
|
||||||
|
变体之间必须满足:
|
||||||
|
· DataBinding 变量完全一致:bean
|
||||||
|
· 保留 ViewHolder / ViewModel 引用的 id:ll_content(点卡片进详情,复用平板 onItemClick 链路)
|
||||||
|
· 平板独有 id(tv_modify / tv_delete / iv_icon)与手机独有 id(iv_check)
|
||||||
|
在 Binding 基类中自动为 @Nullable,ViewHolder 判空使用
|
||||||
|
|
||||||
|
状态标签三色(设计稿):可用=浅绿 / 占用=浅橙 / 维修=浅红。
|
||||||
|
后端当前仅两态(0 可用 / 1 维修),「占用」为后端扩展枚举后的预留,见 ULDBean.statusPhoneName。
|
||||||
|
「来源」字段后端暂无(恒空显示 "-"),已登记 documents/后端接口对接问题清单.xlsx。
|
||||||
|
-->
|
||||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<data>
|
<data>
|
||||||
|
|
||||||
|
<import type="android.view.View" />
|
||||||
|
|
||||||
<variable
|
<variable
|
||||||
name="bean"
|
name="bean"
|
||||||
type="com.lukouguoji.module_base.bean.ULDBean" />
|
type="com.lukouguoji.module_base.bean.ULDBean" />
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:id="@+id/ll_content"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:layout_marginHorizontal="12dp"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:background="@drawable/bg_phone_card"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
<com.mcxtzhang.swipemenulib.SwipeMenuLayout
|
<!-- ==================== 头行:勾选框 + ULD编号 + 状态标签 + 箭头 ==================== -->
|
||||||
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<FrameLayout
|
<ImageView
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/iv_check"
|
||||||
android:layout_height="wrap_content">
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:src="@drawable/ic_phone_check_round_unchecked"
|
||||||
|
loadImage="@{bean.checked.get() ? @drawable/ic_phone_check_round_checked : @drawable/ic_phone_check_round_unchecked}" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
<TextView
|
||||||
android:id="@+id/ll_content"
|
android:layout_width="0dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_weight="1"
|
||||||
android:layout_marginHorizontal="15dp"
|
android:text="@{bean.uld}"
|
||||||
android:layout_marginVertical="5dp"
|
android:textColor="@color/phone_text_title"
|
||||||
android:background="@drawable/bg_item"
|
android:textSize="15sp"
|
||||||
android:orientation="horizontal"
|
android:textStyle="bold" />
|
||||||
android:padding="10dp">
|
|
||||||
|
|
||||||
<ImageView
|
<!-- 状态标签:可用(绿) / 占用(橙) / 维修(红,浅红底红字) -->
|
||||||
android:id="@+id/iv_icon"
|
<TextView
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:src="@drawable/img_plane"
|
|
||||||
tools:src="@drawable/img_plane" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginLeft="10dp"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<!-- 第一行 -->
|
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<!-- ULD编号 -->
|
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1.5"
|
|
||||||
android:gravity="center_vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
completeSpace="@{5}"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="ULD编号:" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@{bean.uld}"
|
|
||||||
android:textColor="@color/colorPrimary" />
|
|
||||||
|
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
|
||||||
|
|
||||||
<!-- 状态 -->
|
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="0.8"
|
|
||||||
android:gravity="center_vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
completeSpace="@{3}"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="状态:" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@{bean.statusName()}"
|
|
||||||
android:textColor='@{bean.status.equals("0") ? @color/text_normal : @color/red}' />
|
|
||||||
|
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
|
||||||
|
|
||||||
<!-- 自重 -->
|
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="0.8"
|
|
||||||
android:gravity="center_vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
completeSpace="@{3}"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="自重:" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@{bean.uldWeight}" />
|
|
||||||
|
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
|
||||||
|
|
||||||
<!-- 所属航司 -->
|
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="0.8"
|
|
||||||
android:gravity="center_vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
completeSpace="@{5}"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="所属航司:" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@{bean.carrier}" />
|
|
||||||
|
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
|
||||||
|
|
||||||
<!-- 最大装载容积 -->
|
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1.2"
|
|
||||||
android:gravity="center_vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
completeSpace="@{7}"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="最大装载容积:" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@{bean.maxVolume}" />
|
|
||||||
|
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
|
||||||
|
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
|
||||||
|
|
||||||
<!-- 第二行 -->
|
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="10dp">
|
|
||||||
|
|
||||||
<!-- 最大载重 -->
|
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1.5"
|
|
||||||
android:gravity="center_vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
completeSpace="@{5}"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="最大载重:" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@{bean.maxWeight}" />
|
|
||||||
|
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
|
||||||
|
|
||||||
<!-- 备注 -->
|
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="3.6"
|
|
||||||
android:gravity="center_vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
completeSpace="@{3}"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="备注:" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@{bean.remark}" />
|
|
||||||
|
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
|
||||||
|
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="30dp"
|
|
||||||
android:layout_height="30dp"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:layout_marginLeft="10dp"
|
|
||||||
android:src="@drawable/img_pda_right" />
|
|
||||||
|
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="20dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:background="@{bean.isStatusAvailable ? @drawable/bg_phone_tag_green : (bean.isStatusOccupied ? @drawable/bg_phone_tag_orange : @drawable/bg_phone_tag_red_light)}"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingHorizontal="8dp"
|
||||||
|
android:text="@{bean.statusPhoneName}"
|
||||||
|
android:textColor="@{bean.isStatusAvailable ? @color/phone_tag_green_text : (bean.isStatusOccupied ? @color/phone_tag_orange_text : @color/phone_danger_text)}"
|
||||||
|
android:textSize="11sp" />
|
||||||
|
|
||||||
<TextView
|
<ImageView
|
||||||
android:id="@+id/tv_modify"
|
android:layout_width="16dp"
|
||||||
style="@style/tv_item_action"
|
android:layout_height="16dp"
|
||||||
android:background="#8313ef"
|
android:layout_marginStart="6dp"
|
||||||
android:text="修改" />
|
android:src="@drawable/ic_phone_chevron_right" />
|
||||||
|
|
||||||
<TextView
|
</LinearLayout>
|
||||||
android:id="@+id/tv_delete"
|
|
||||||
style="@style/tv_item_action"
|
|
||||||
android:background="@color/red"
|
|
||||||
android:text="删除" />
|
|
||||||
|
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
<!-- ==================== 第二行:所属航司 / 来源 ==================== -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
</com.mcxtzhang.swipemenulib.SwipeMenuLayout>
|
<ImageView
|
||||||
|
android:layout_width="14dp"
|
||||||
|
android:layout_height="14dp"
|
||||||
|
android:src="@drawable/ic_phone_airplane" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text='@{"所属航司:" + (bean.carrier.empty ? "-" : bean.carrier)}'
|
||||||
|
android:textColor="@color/phone_text_body"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="14dp"
|
||||||
|
android:layout_height="14dp"
|
||||||
|
android:src="@drawable/ic_phone_location" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text='@{"来源:" + (bean.source.empty ? "-" : bean.source)}'
|
||||||
|
android:textColor="@color/phone_text_body"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- ==================== 第三行:入库时间 ==================== -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="14dp"
|
||||||
|
android:layout_height="14dp"
|
||||||
|
android:src="@drawable/ic_phone_calendar" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text='@{"入库时间:" + (bean.checkInDate.empty ? "-" : bean.checkInDate)}'
|
||||||
|
android:textColor="@color/phone_text_body"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
</layout>
|
</layout>
|
||||||
|
|||||||
55
documents/5.5寸手持端-后端字段补充清单.md
Normal file
55
documents/5.5寸手持端-后端字段补充清单.md
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# 5.5 寸手持端适配 —— 后端接口补充清单
|
||||||
|
|
||||||
|
适配手机端时,设计稿要求展示/筛选的部分内容,现有接口没有提供或未生效。
|
||||||
|
以下为**实机联调(内网真实数据)验证过**的结论,客户端侧已按设计稿把 UI 与参数都做好,
|
||||||
|
后端补齐后即可直接生效,客户端基本无需再改。
|
||||||
|
|
||||||
|
整理时间:2026-07-29 验证环境:内网 `192.168.1.250:8093`,账号 ADMIN
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、参数已发送但后端未生效(客户端已就绪,等后端支持)
|
||||||
|
|
||||||
|
| 接口 | 参数 | 用途 | 实测现象 |
|
||||||
|
|------|------|------|----------|
|
||||||
|
| `IntExpOutHandover/pageQuery`<br>`IntExpOutHandover/pageQueryTotal` | `hoState`<br>("0" 待交接 / "1" 已交接) | 出库交接页「待交接 / 已交接」Tab 过滤与角标计数 | 请求体确认携带 `"hoState":"0"` / `"1"`,但两个 Tab 返回**完全相同**的数据;`pageQueryTotal` 的 `wbNumber` 也不随之变化 |
|
||||||
|
| `IntExpMove/pageQuery`<br>`IntExpMove/pageQueryTotal` | `spCode`<br>(特码,如 "PER") | 出港移库页筛选弹层「特码」 | 请求体确认携带 `"spCode":"PER"`,但返回结果中仍含特码为 `PEF` 的记录,角标计数也无变化 |
|
||||||
|
|
||||||
|
> 对照参考:同一接口的 `moveState`、`by1`(承运人)、`awbType`(运单类型)**均正常生效**
|
||||||
|
> (实测承运人填 MU 后待移库数量 67 → 60),因此可以排除客户端传参方式的问题。
|
||||||
|
>
|
||||||
|
> 若贵方使用的参数名与上表不同,请告知正确名称,客户端改一处常量即可。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、接口未返回、设计稿需要展示的字段
|
||||||
|
|
||||||
|
以下字段目前接口完全不返回,或恒为 `null`。客户端已按设计稿保留完整 UI 结构,
|
||||||
|
数据为空时统一占位 `-`,后端补齐后自动显示。
|
||||||
|
|
||||||
|
### 2.1 `IntExpMove/pageQuery`(出港移库)
|
||||||
|
|
||||||
|
| 设计稿位置 | 需要的字段 | 当前状况 |
|
||||||
|
|------------|-----------|----------|
|
||||||
|
| 列表卡片第二行「航班信息:20260709/MU2311」 | 航班日期 + 航班号(如 `fdate` / `fno`) | **接口无任何航班相关字段** |
|
||||||
|
| 详情页「移库信息」卡片 —— 移库人 | 移库人**姓名**(现只有 `opId`) | `opId` 恒为 `null`,且即便有值也是 ID 而非姓名 |
|
||||||
|
| 详情页「移库信息」卡片 —— 移库时间 | `opdate` | 恒为 `null`,**已移库记录也是 null** |
|
||||||
|
| 详情页蓝色表头右侧时间戳 | 同上 `opdate` | 同上 |
|
||||||
|
| 详情页类型行右侧「普通货物运输」 | `businessType` 或 `cargoType` | 两者均恒为 `null` |
|
||||||
|
|
||||||
|
### 2.2 说明
|
||||||
|
|
||||||
|
- 出库交接页的详情所需字段(板型、库位、复磅人/时间等)接口均已返回,无需补充。
|
||||||
|
- 移库详情页红色标签绑的是 `awbTypeName`(真实值形如「国际出港(国际直航)」),已正常。
|
||||||
|
设计稿上写的「国际进港」经判断为设计稿笔误(该页属国际出港),未按字面实现。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、附:字典接口调用口径(客户端已按此对齐,仅作备忘)
|
||||||
|
|
||||||
|
`typeCode/getSpecialCodeByParam`(特码字典):
|
||||||
|
|
||||||
|
- `flag=1`(国际)+ `ieFlag=""`(**留空**)→ 正常返回 RXE/PER/PEM/PEF/LDP/GJJ/DGR 等
|
||||||
|
- `flag=1` + `ieFlag="E"` → 返回 `"data": []` 空数组
|
||||||
|
|
||||||
|
国际出港各页面统一使用 `ieFlag=""`。如该行为非预期,请后端确认 `ieFlag` 的取值约定。
|
||||||
195
documents/5.5寸手持端设计文件/00_全部入口总览.html
Normal file
195
documents/5.5寸手持端设计文件/00_全部入口总览.html
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<title>5.5 寸手持端设计稿 · 全部入口总览</title>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--cols: 4;
|
||||||
|
--scale: 1;
|
||||||
|
--pw: 430px;
|
||||||
|
--ph: 890px;
|
||||||
|
}
|
||||||
|
* { box-sizing: border-box; }
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 32px 48px;
|
||||||
|
background: #EEF1F6;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Arial, sans-serif;
|
||||||
|
color: #1F2937;
|
||||||
|
}
|
||||||
|
header {
|
||||||
|
padding: 32px 0 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 24px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 26px;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: .5px;
|
||||||
|
}
|
||||||
|
h1 small {
|
||||||
|
display: block;
|
||||||
|
margin-top: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #6B7280;
|
||||||
|
letter-spacing: 0;
|
||||||
|
}
|
||||||
|
.toolbar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 18px;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #E3E8F0;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 10px 16px;
|
||||||
|
font-size: 13px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,.05);
|
||||||
|
}
|
||||||
|
.toolbar label { color: #6B7280; margin-right: 6px; }
|
||||||
|
.toolbar select {
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
border: 1px solid #D8DEE9;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: #fff;
|
||||||
|
color: #1F2937;
|
||||||
|
}
|
||||||
|
.toolbar button {
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 5px 12px;
|
||||||
|
border: 1px solid #2563EB;
|
||||||
|
background: #2563EB;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.toolbar button:active { opacity: .8; }
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(var(--cols), max-content);
|
||||||
|
gap: 28px 24px;
|
||||||
|
justify-content: start;
|
||||||
|
}
|
||||||
|
.card {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #E3E8F0;
|
||||||
|
border-radius: 14px;
|
||||||
|
padding: 12px 12px 14px;
|
||||||
|
box-shadow: 0 2px 10px rgba(17,24,39,.06);
|
||||||
|
width: calc(var(--pw) * var(--scale) + 24px);
|
||||||
|
}
|
||||||
|
.cap {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin: 0 2px 10px;
|
||||||
|
}
|
||||||
|
.no {
|
||||||
|
flex: none;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: #2563EB;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.name { font-size: 15px; font-weight: 600; }
|
||||||
|
.tag {
|
||||||
|
margin-left: auto;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #2563EB;
|
||||||
|
background: #EAF1FE;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 2px 7px;
|
||||||
|
}
|
||||||
|
.frame {
|
||||||
|
width: calc(var(--pw) * var(--scale));
|
||||||
|
height: calc(var(--ph) * var(--scale));
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #E5E7EB;
|
||||||
|
}
|
||||||
|
.frame iframe {
|
||||||
|
width: var(--pw);
|
||||||
|
height: var(--ph);
|
||||||
|
border: 0;
|
||||||
|
display: block;
|
||||||
|
transform: scale(var(--scale));
|
||||||
|
transform-origin: top left;
|
||||||
|
}
|
||||||
|
body.clean .toolbar { display: none; }
|
||||||
|
body.clean header { padding-bottom: 14px; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<h1>5.5 寸手持端设计稿 · 全部入口总览
|
||||||
|
<small>共 11 个业务入口 · 单机画布 390 × 844</small>
|
||||||
|
</h1>
|
||||||
|
<div class="toolbar">
|
||||||
|
<span><label>列数</label>
|
||||||
|
<select id="cols" onchange="setVar('--cols', this.value)">
|
||||||
|
<option>2</option><option>3</option><option selected>4</option><option>5</option><option>6</option>
|
||||||
|
</select>
|
||||||
|
</span>
|
||||||
|
<span><label>缩放</label>
|
||||||
|
<select id="scale" onchange="setVar('--scale', this.value)">
|
||||||
|
<option value="1">100%</option>
|
||||||
|
<option value="0.85">85%</option>
|
||||||
|
<option value="0.75">75%</option>
|
||||||
|
<option value="0.6">60%</option>
|
||||||
|
<option value="0.5">50%</option>
|
||||||
|
</select>
|
||||||
|
</span>
|
||||||
|
<button onclick="document.body.classList.toggle('clean')">隐藏工具栏</button>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="grid" id="grid"></div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const PAGES = [
|
||||||
|
['01', 'ULD 管理', '综合管理', '01_ULD管理/ULD管理.html'],
|
||||||
|
['02', '出库交接', '国际出港', '02_出库交接/出库交接.html'],
|
||||||
|
['03', '出港计重', '国际出港', '03_出港计重/main.html'],
|
||||||
|
['04', '出港运抵', '国际出港', '04_出港运抵/main.html'],
|
||||||
|
['05', '出港移库', '国际出港', '05_出港移库/出港移库.html'],
|
||||||
|
['06', '出港查询', '国际出港', '06_出港查询/出港查询.html'],
|
||||||
|
['07', '出港仓库', '国际出港', '07_出港仓库/出港仓库.html'],
|
||||||
|
['08', '进港仓库', '国际进港', '08_进港仓库/进港仓库.html'],
|
||||||
|
['09', '提取出库', '国际进港', '09_提取出库/提取出库.html'],
|
||||||
|
['10', '进港查询', '国际进港', '10_进港查询/进港查询.html'],
|
||||||
|
['11', '进港移库', '国际进港', '11_进港移库/进港移库.html'],
|
||||||
|
];
|
||||||
|
|
||||||
|
document.getElementById('grid').innerHTML = PAGES.map(([no, name, menu, src]) => `
|
||||||
|
<div class="card">
|
||||||
|
<div class="cap">
|
||||||
|
<span class="no">${no}</span>
|
||||||
|
<span class="name">${name}</span>
|
||||||
|
<span class="tag">${menu}</span>
|
||||||
|
</div>
|
||||||
|
<div class="frame">
|
||||||
|
<iframe src="${src}" loading="eager" scrolling="no"></iframe>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`).join('');
|
||||||
|
|
||||||
|
function setVar(k, v) {
|
||||||
|
document.documentElement.style.setProperty(k, v);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
650
documents/5.5寸手持端设计文件/01_ULD管理/ULD管理.html
Normal file
650
documents/5.5寸手持端设计文件/01_ULD管理/ULD管理.html
Normal file
@@ -0,0 +1,650 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||||
|
<title>ULD管理</title>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/tailwindcss.js"></script>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/iconify-icon.min.js"></script>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||||
|
background-color: #F3F4F6;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.safe-bottom {
|
||||||
|
padding-bottom: env(safe-area-inset-bottom);
|
||||||
|
}
|
||||||
|
.custom-checkbox-round {
|
||||||
|
appearance: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
border-radius: 9999px;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
border: 2px solid #D1D5DB;
|
||||||
|
background-color: #fff;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.custom-checkbox-round:checked {
|
||||||
|
background-color: #0D6EFD;
|
||||||
|
border-color: #0D6EFD;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white'%3E%3Cpath d='M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z'/%3E%3C/svg%3E");
|
||||||
|
background-size: 14px 14px;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
.no-scrollbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.no-scrollbar {
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
.btn-active:active {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="bg-gray-200 min-h-screen flex items-center justify-center p-4">
|
||||||
|
<div class="relative w-[390px] h-[844px] bg-[#1a1a1a] rounded-[55px] shadow-2xl border-[6px] border-[#333] flex flex-col overflow-hidden">
|
||||||
|
<div class="flex-1 bg-white mt-0 mb-1 mx-1 rounded-[46px] overflow-hidden flex flex-col relative">
|
||||||
|
<div class="bg-[#2563EB] text-white h-11 px-7 flex items-end pb-2 justify-between text-[14px] font-medium z-50">
|
||||||
|
<span>09:41</span>
|
||||||
|
<div class="flex items-center gap-1.5 pb-0.5">
|
||||||
|
<iconify-icon icon="mdi:signal-cellular-3"></iconify-icon>
|
||||||
|
<iconify-icon icon="mdi:wifi"></iconify-icon>
|
||||||
|
<iconify-icon icon="mdi:battery"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 flex flex-col overflow-hidden relative bg-gray-100">
|
||||||
|
<header class="relative bg-[#2563EB] text-white flex items-center h-12 px-3 sticky top-0 z-50">
|
||||||
|
<div class="flex items-center btn-active" onclick="alert('返回首页')">
|
||||||
|
<iconify-icon icon="mdi:chevron-left" width="28"></iconify-icon>
|
||||||
|
<span class="text-sm font-medium text-white -ml-1">返回</span>
|
||||||
|
</div>
|
||||||
|
<h1 class="absolute left-1/2 -translate-x-1/2 text-lg font-bold text-white">ULD管理</h1>
|
||||||
|
</header>
|
||||||
|
<section class="px-4 pt-4 pb-3 flex-none">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-[12px] h-10 px-3 gap-2 flex-1 shadow-sm">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] text-lg flex-none" icon="mdi:magnify"></iconify-icon>
|
||||||
|
<input class="flex-1 bg-transparent text-[14px] text-gray-700 placeholder-gray-400 outline-none border-none rounded-lg px-2" placeholder="搜索ULD编号" type="text"/>
|
||||||
|
<button class="flex-none text-blue-500">
|
||||||
|
<iconify-icon class="text-lg" icon="mdi:qrcode-scan"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button class="bg-white p-2.5 rounded-full shadow-sm border border-gray-200 text-[#2563EB] flex items-center justify-center flex-none" onclick="toggleFilterDrawer(true)">
|
||||||
|
<iconify-icon class="text-lg" icon="mdi:filter-variant"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<main class="flex-1 overflow-y-auto px-4 pt-3 pb-[80px] no-scrollbar">
|
||||||
|
<!-- 卡片1 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm mb-3 p-4 relative cursor-pointer" onclick="showUldDetail('PMC78133363396', '占用', 'CA', '150', '12.5', '6800', 'CA1111', 'PEK', 'B区-05货位', '--')">
|
||||||
|
<div class="flex justify-between items-start mb-3">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<input class="item-checkbox custom-checkbox-round flex-none" onclick="event.stopPropagation(); handleCheckboxClick(this, event)" type="checkbox"/>
|
||||||
|
<span class="text-[15px] font-bold text-[#1F2937]">PMC78133363396</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="bg-[#FFF3E0] text-[#E67722] text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">占用</span>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:chevron-right" width="14"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-2 text-gray-500 text-[13px]">
|
||||||
|
<div class="grid grid-cols-2 gap-x-3">
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:office-building-outline"></iconify-icon>
|
||||||
|
<span>所属航司:CA</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:map-marker"></iconify-icon>
|
||||||
|
<span>来源:空运</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:calendar-clock"></iconify-icon>
|
||||||
|
<span>入库时间:2026-07-20 15:59:20</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片2 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm mb-3 p-4 relative cursor-pointer" onclick="showUldDetail('PMC78133363397', '可用', 'CA', '120', '10.0', '5500', 'CA2222', 'CAN', 'C区-12货位', '--')">
|
||||||
|
<div class="flex justify-between items-start mb-3">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<input class="item-checkbox custom-checkbox-round flex-none" onclick="event.stopPropagation(); handleCheckboxClick(this, event)" type="checkbox"/>
|
||||||
|
<span class="text-[15px] font-bold text-[#1F2937]">PMC78133363397</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="bg-green-100 text-green-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">可用</span>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:chevron-right" width="14"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-2 text-gray-500 text-[13px]">
|
||||||
|
<div class="grid grid-cols-2 gap-x-3">
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:office-building-outline"></iconify-icon>
|
||||||
|
<span>所属航司:CA</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:map-marker"></iconify-icon>
|
||||||
|
<span>来源:空运</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:calendar-clock"></iconify-icon>
|
||||||
|
<span>入库时间:2026-07-20 15:59:20</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片3 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm mb-3 p-4 relative cursor-pointer" onclick="showUldDetail('PMC78133363398', '维修', 'CA', '0', '0.0', '0', 'CA3333', 'PVG', '维修区', '维修中')">
|
||||||
|
<div class="flex justify-between items-start mb-3">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<input class="item-checkbox custom-checkbox-round flex-none" onclick="event.stopPropagation(); handleCheckboxClick(this, event)" type="checkbox"/>
|
||||||
|
<span class="text-[15px] font-bold text-[#1F2937]">PMC78133363398</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="bg-red-50 text-red-600 text-[11px] px-2 py-0.5 rounded font-medium">维修</span>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:chevron-right" width="14"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-2 text-gray-500 text-[13px]">
|
||||||
|
<div class="grid grid-cols-2 gap-x-3">
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:office-building-outline"></iconify-icon>
|
||||||
|
<span>所属航司:CA</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:map-marker"></iconify-icon>
|
||||||
|
<span>来源:陆运</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:calendar-clock"></iconify-icon>
|
||||||
|
<span>入库时间:2026-07-20 15:59:20</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片4 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm mb-3 p-4 relative cursor-pointer" onclick="showUldDetail('PMC78133363399', '占用', 'CA', '280', '20.0', '8500', 'CA4444', 'CTU', 'A区-08货位', '--')">
|
||||||
|
<div class="flex justify-between items-start mb-3">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<input class="item-checkbox custom-checkbox-round flex-none" onclick="event.stopPropagation(); handleCheckboxClick(this, event)" type="checkbox"/>
|
||||||
|
<span class="text-[15px] font-bold text-[#1F2937]">PMC78133363399</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="bg-[#FFF3E0] text-[#E67722] text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">占用</span>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:chevron-right" width="14"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-2 text-gray-500 text-[13px]">
|
||||||
|
<div class="grid grid-cols-2 gap-x-3">
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:office-building-outline"></iconify-icon>
|
||||||
|
<span>所属航司:CA</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:map-marker"></iconify-icon>
|
||||||
|
<span>来源:空运</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:calendar-clock"></iconify-icon>
|
||||||
|
<span>入库时间:2026-07-20 15:59:20</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<div class="absolute bottom-0 w-full bg-white border-t border-gray-200 z-40 flex flex-col pt-3 pb-3" id="bottom-toolbar" style="display: flex;">
|
||||||
|
<div class="absolute right-4 -top-[73px] z-50">
|
||||||
|
<button class="bg-[#2563EB] text-white w-11 h-11 rounded-full flex items-center justify-center shadow-lg shadow-blue-500/40" onclick="showAddDialog()">
|
||||||
|
<iconify-icon icon="mdi:plus" width="24"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="px-4 flex items-center w-full">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input class="custom-checkbox-round flex-none" id="select-all-cb" onclick="toggleSelectAll(this.checked)" type="checkbox"/>
|
||||||
|
<label class="text-[13px] text-[#1F2937] font-medium cursor-pointer" for="select-all-cb">全选</label>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1"></div>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<span class="text-[12px] text-[#9CA3AF]">已选 <span id="selected-count">0 / 4</span> 项</span>
|
||||||
|
<button class="bg-[#FDEDED] text-[#DC2626] text-[15px] font-bold px-5 py-2 rounded-[10px] flex items-center gap-1.5 btn-active" onclick="handleBatchDelete()">
|
||||||
|
<iconify-icon class="text-base" icon="mdi:delete-outline"></iconify-icon>
|
||||||
|
<span>删除</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 新增弹窗 -->
|
||||||
|
<div class="absolute inset-0 bg-gray-100 z-[60] flex flex-col hidden" id="addUldOverlay">
|
||||||
|
<div class="bg-[#2563EB] text-white h-11 px-7 flex items-end pb-2 justify-between text-[14px] font-medium z-50 flex-none">
|
||||||
|
<span>09:41</span>
|
||||||
|
<div class="flex items-center gap-1.5 pb-0.5">
|
||||||
|
<iconify-icon icon="mdi:signal-cellular-3"></iconify-icon>
|
||||||
|
<iconify-icon icon="mdi:wifi"></iconify-icon>
|
||||||
|
<iconify-icon icon="mdi:battery"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<header class="relative bg-[#2563EB] text-white flex items-center h-12 px-3 flex-none">
|
||||||
|
<div class="flex items-center btn-active" onclick="hideAddDialog()">
|
||||||
|
<iconify-icon icon="mdi:chevron-left" width="28"></iconify-icon>
|
||||||
|
<span class="text-sm font-medium text-white -ml-1">返回</span>
|
||||||
|
</div>
|
||||||
|
<h1 class="absolute left-1/2 -translate-x-1/2 text-lg font-bold text-white">ULD新增</h1>
|
||||||
|
</header>
|
||||||
|
<div class="flex-1 overflow-y-auto p-4 no-scrollbar">
|
||||||
|
<div class="bg-white rounded-xl shadow-[0_2px_12px_rgba(0,0,0,0.05)] overflow-hidden px-4">
|
||||||
|
<div class="flex items-center py-[14px] border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">ULD编号<span class="text-red-500 ml-0.5">*</span></span>
|
||||||
|
<input id="add-uldNo" class="flex-1 bg-transparent outline-none text-gray-800 placeholder-gray-400 text-[14px]" placeholder="请输入ULD编号" type="text"/>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center py-[14px] border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">状态</span>
|
||||||
|
<div class="flex-1 flex items-center justify-between cursor-pointer status-display" onclick="showSelectPanel('status', '请选择状态', ['可用', '占用', '维修'])">
|
||||||
|
<span id="add-status-text" class="text-[14px] text-gray-500">请选择状态</span>
|
||||||
|
<iconify-icon class="text-xl text-gray-500" icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center py-[14px] border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">所属航司</span>
|
||||||
|
<div class="flex-1 flex items-center justify-between cursor-pointer airline-display" onclick="showSelectPanel('airline', '请选择所属航司', ['CA', 'MU', 'CZ', '3U'])">
|
||||||
|
<span id="add-airline-text" class="text-[14px] text-gray-500">请选择所属航司</span>
|
||||||
|
<iconify-icon class="text-xl text-gray-500" icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center py-[14px] border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">来源</span>
|
||||||
|
<div class="flex-1 flex items-center justify-between cursor-pointer source-display" onclick="showSelectPanel('source', '请选择来源', ['空运', '陆运'])">
|
||||||
|
<span id="add-source-text" class="text-[14px] text-gray-500">请选择来源</span>
|
||||||
|
<iconify-icon class="text-xl text-gray-500" icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center py-[14px] border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">自重(kg)<span class="text-red-500 ml-0.5">*</span></span>
|
||||||
|
<input id="add-weight" class="flex-1 bg-transparent outline-none text-gray-800 placeholder-gray-400 text-[14px]" placeholder="请输入自重" type="number"/>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center py-[14px] border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">进港航班号</span>
|
||||||
|
<input id="add-flightNo" class="flex-1 bg-transparent outline-none text-gray-800 placeholder-gray-400 text-[14px]" placeholder="请输入进港航班号" type="text"/>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center py-[14px] border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">所在港</span>
|
||||||
|
<input id="add-port" class="flex-1 bg-transparent outline-none text-gray-800 placeholder-gray-400 text-[14px]" placeholder="HFE" type="text"/>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center py-[14px] border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">入库时间<span class="text-red-500 ml-0.5">*</span></span>
|
||||||
|
<input id="add-inTime" class="flex-1 bg-transparent outline-none text-gray-800 placeholder-gray-400 text-[14px]" placeholder="请输入入库时间" type="text"/>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center py-[14px]">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">备注</span>
|
||||||
|
<input id="add-remark" class="flex-1 bg-transparent outline-none text-gray-800 placeholder-gray-400 text-[14px]" placeholder="请输入备注" type="text"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="w-full mt-8 bg-[#2563EB] text-white py-3.5 rounded-[10px] font-bold text-[16px] shadow-lg shadow-blue-500/30 btn-active" onclick="saveUld()">保存</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 详情弹窗 -->
|
||||||
|
<div class="absolute inset-0 bg-gray-100 z-[70] flex flex-col hidden" id="detailOverlay">
|
||||||
|
<div class="bg-[#2563EB] text-white h-11 px-7 flex items-end pb-2 justify-between text-[14px] font-medium z-50 flex-none">
|
||||||
|
<span>09:41</span>
|
||||||
|
<div class="flex items-center gap-1.5 pb-0.5">
|
||||||
|
<iconify-icon icon="mdi:signal-cellular-3"></iconify-icon>
|
||||||
|
<iconify-icon icon="mdi:wifi"></iconify-icon>
|
||||||
|
<iconify-icon icon="mdi:battery"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<header class="relative bg-[#2563EB] text-white flex items-center h-12 px-3 flex-none">
|
||||||
|
<div class="flex items-center btn-active" onclick="hideUldDetail()">
|
||||||
|
<iconify-icon icon="mdi:chevron-left" width="28"></iconify-icon>
|
||||||
|
<span class="text-sm font-medium text-white -ml-1">返回</span>
|
||||||
|
</div>
|
||||||
|
<h1 class="absolute left-1/2 -translate-x-1/2 text-lg font-bold text-white">ULD详情</h1>
|
||||||
|
<button class="absolute right-4 top-1/2 -translate-y-1/2 text-white text-lg" onclick="openEdit()">
|
||||||
|
<iconify-icon icon="mdi:pencil" width="22"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</header>
|
||||||
|
<div class="flex-1 overflow-y-auto p-4 no-scrollbar">
|
||||||
|
<div class="bg-white rounded-xl shadow-sm overflow-hidden px-4 mb-6">
|
||||||
|
<div class="flex items-center justify-between py-3.5 border-b border-gray-100">
|
||||||
|
<span class="text-[13px] font-medium text-[#6B7280]">ULD编号</span>
|
||||||
|
<span class="text-[14px] font-normal text-[#111827]" id="detail-uldNo">--</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between py-3.5 border-b border-gray-100">
|
||||||
|
<span class="text-[13px] font-medium text-[#6B7280]">状态</span>
|
||||||
|
<span class="text-[13px] font-medium px-2 py-0.5 rounded-[6px]" id="detail-status">--</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between py-3.5 border-b border-gray-100">
|
||||||
|
<span class="text-[13px] font-medium text-[#6B7280]">所属航司</span>
|
||||||
|
<span class="text-[14px] font-normal text-[#111827]" id="detail-airline">--</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between py-3.5 border-b border-gray-100">
|
||||||
|
<span class="text-[13px] font-medium text-[#6B7280]">自重 (kg)</span>
|
||||||
|
<span class="text-[14px] font-normal text-[#111827]" id="detail-weight">--</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between py-3.5 border-b border-gray-100">
|
||||||
|
<span class="text-[13px] font-medium text-[#6B7280]">最大装载容积 (m³)</span>
|
||||||
|
<span class="text-[14px] font-normal text-[#111827]" id="detail-volume">--</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between py-3.5 border-b border-gray-100">
|
||||||
|
<span class="text-[13px] font-medium text-[#6B7280]">最大载重 (kg)</span>
|
||||||
|
<span class="text-[14px] font-normal text-[#111827]" id="detail-maxWeight">--</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between py-3.5 border-b border-gray-100">
|
||||||
|
<span class="text-[13px] font-medium text-[#6B7280]">进港航班号</span>
|
||||||
|
<span class="text-[14px] font-normal text-[#111827]" id="detail-flightNo">--</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between py-3.5 border-b border-gray-100">
|
||||||
|
<span class="text-[13px] font-medium text-[#6B7280]">所在港</span>
|
||||||
|
<span class="text-[14px] font-normal text-[#111827]" id="detail-port">--</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between py-3.5 border-b border-gray-100">
|
||||||
|
<span class="text-[13px] font-medium text-[#6B7280]">来源</span>
|
||||||
|
<span class="text-[14px] font-normal text-[#111827]" id="detail-source">--</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between py-3.5 border-b border-gray-100">
|
||||||
|
<span class="text-[13px] font-medium text-[#6B7280]">入库时间</span>
|
||||||
|
<span class="text-[14px] font-normal text-[#111827]" id="detail-inTime">--</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between py-3.5">
|
||||||
|
<span class="text-[13px] font-medium text-[#6B7280]">备注</span>
|
||||||
|
<span class="text-[14px] font-normal text-[#111827]" id="detail-remark">--</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 修改页面 -->
|
||||||
|
<div class="absolute inset-0 bg-gray-100 z-[80] flex flex-col hidden" id="editOverlay">
|
||||||
|
<div class="bg-[#2563EB] text-white h-11 px-7 flex items-end pb-2 justify-between text-[14px] font-medium z-50 flex-none">
|
||||||
|
<span>09:41</span>
|
||||||
|
<div class="flex items-center gap-1.5 pb-0.5">
|
||||||
|
<iconify-icon icon="mdi:signal-cellular-3"></iconify-icon>
|
||||||
|
<iconify-icon icon="mdi:wifi"></iconify-icon>
|
||||||
|
<iconify-icon icon="mdi:battery"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<header class="relative bg-[#2563EB] text-white flex items-center h-12 px-3 flex-none">
|
||||||
|
<div class="flex items-center btn-active" onclick="closeEdit()">
|
||||||
|
<iconify-icon icon="mdi:chevron-left" width="28"></iconify-icon>
|
||||||
|
<span class="text-sm font-medium text-white -ml-1">返回</span>
|
||||||
|
</div>
|
||||||
|
<h1 class="absolute left-1/2 -translate-x-1/2 text-lg font-bold text-white">ULD修改</h1>
|
||||||
|
</header>
|
||||||
|
<div class="flex-1 overflow-y-auto p-4 no-scrollbar">
|
||||||
|
<div class="bg-white rounded-xl shadow-[0_2px_12px_rgba(0,0,0,0.05)] overflow-hidden px-4">
|
||||||
|
<div class="flex items-center py-[14px] border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">ULD编号</span>
|
||||||
|
<input id="edit-uldNo" class="flex-1 bg-transparent outline-none text-gray-800 text-[14px]" type="text" readonly/>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center py-[14px] border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">状态</span>
|
||||||
|
<div class="flex-1 flex items-center justify-between cursor-pointer status-display" onclick="showSelectPanel('editStatus', '请选择状态', ['可用', '占用', '维修'])">
|
||||||
|
<span id="edit-status-text" class="text-[13px] font-medium px-2 py-0.5 rounded-[6px] text-gray-800">--</span>
|
||||||
|
<iconify-icon class="text-xl text-gray-500" icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center py-[14px] border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">所属航司</span>
|
||||||
|
<div class="flex-1 flex items-center justify-between cursor-pointer airline-display" onclick="showSelectPanel('editAirline', '请选择航司', ['CA', 'MU', 'CZ', '3U'])">
|
||||||
|
<span id="edit-airline-text" class="text-[14px] text-gray-800">--</span>
|
||||||
|
<iconify-icon class="text-xl text-gray-500" icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center py-[14px] border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">自重(kg)</span>
|
||||||
|
<input id="edit-weight" class="flex-1 bg-transparent outline-none text-gray-800 text-[14px]" type="number"/>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center py-[14px] border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">进港航班号</span>
|
||||||
|
<input id="edit-flightNo" class="flex-1 bg-transparent outline-none text-gray-800 text-[14px]" type="text"/>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center py-[14px] border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">所在港</span>
|
||||||
|
<input id="edit-port" class="flex-1 bg-transparent outline-none text-gray-800 text-[14px]" type="text"/>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center py-[14px] border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">来源</span>
|
||||||
|
<div class="flex-1 flex items-center justify-between cursor-pointer source-display" onclick="showSelectPanel('editSource', '请选择来源', ['空运', '陆运'])">
|
||||||
|
<span id="edit-source-text" class="text-[14px] text-gray-800">--</span>
|
||||||
|
<iconify-icon class="text-xl text-gray-500" icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center py-[14px] border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">入库时间</span>
|
||||||
|
<input id="edit-inTime" class="flex-1 bg-transparent outline-none text-gray-800 text-[14px]" type="text"/>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center py-[14px]">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">备注</span>
|
||||||
|
<input id="edit-remark" class="flex-1 bg-transparent outline-none text-gray-800 text-[14px]" type="text"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="w-full mt-8 bg-[#2563EB] text-white py-3.5 rounded-[10px] font-bold text-[16px] shadow-lg shadow-blue-500/30 btn-active" onclick="saveEdit()">保存</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 筛选弹窗 -->
|
||||||
|
<div class="absolute inset-0 z-[100] bg-black/50 flex items-end justify-center" id="filterOverlay" onclick="toggleFilterDrawer(false)" style="display: none;">
|
||||||
|
<div class="bg-white rounded-t-[20px] w-full max-w-[390px] px-5 pt-6 pb-8" onclick="event.stopPropagation()">
|
||||||
|
<div class="relative flex items-center justify-center mb-6">
|
||||||
|
<button class="absolute right-0 top-0 text-gray-400" onclick="toggleFilterDrawer(false)">
|
||||||
|
<iconify-icon class="text-2xl" icon="mdi:close"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
<h2 class="text-[18px] font-bold text-gray-900">筛选条件</h2>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-5">
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">入库时间</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 bg-transparent outline-none text-gray-800 placeholder-gray-400 text-[14px]" placeholder="请输入入库时间" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:calendar" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">进港航班号</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请输入进港航班号" type="text"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">所属航司</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择所属航司" readonly type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:chevron-down" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">来源</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择来源" readonly type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:chevron-down" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-3 mt-8">
|
||||||
|
<button class="flex-1 h-11 text-[15px] font-medium text-gray-600 bg-white border border-gray-200 rounded-[10px]" onclick="resetFilter()">重置</button>
|
||||||
|
<button class="flex-1 h-11 text-[15px] font-medium text-white bg-[#2563EB] rounded-[10px] shadow-sm" onclick="confirmFilter()">确认</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 选择面板 -->
|
||||||
|
<div class="fixed inset-0 z-[100] bg-black/40 flex items-end justify-center" id="selectPanel" onclick="hideSelectPanel(event)" style="display: none;">
|
||||||
|
<div class="bg-white rounded-t-[20px] w-full max-w-[390px] px-4 pt-4 pb-8" onclick="event.stopPropagation()">
|
||||||
|
<div class="flex items-center justify-between mb-4">
|
||||||
|
<div class="w-6"></div>
|
||||||
|
<div class="text-center text-[16px] font-bold text-gray-900" id="selectPanelTitle">请选择</div>
|
||||||
|
<button class="w-6 h-6 flex items-center justify-center text-gray-500" onclick="hideSelectPanel()">
|
||||||
|
<iconify-icon icon="mdi:close" width="20"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-1" id="selectPanelOptions"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let currentDetail = {};
|
||||||
|
|
||||||
|
function showUldDetail(uldNo, status, airline, weight, volume, maxWeight, flightNo, port, location, remark) {
|
||||||
|
currentDetail = { uldNo, status, airline, weight, volume, maxWeight, flightNo, port, location, remark };
|
||||||
|
document.getElementById('detail-uldNo').innerText = uldNo;
|
||||||
|
document.getElementById('detail-airline').innerText = airline;
|
||||||
|
document.getElementById('detail-weight').innerText = weight;
|
||||||
|
document.getElementById('detail-volume').innerText = volume;
|
||||||
|
document.getElementById('detail-maxWeight').innerText = maxWeight;
|
||||||
|
document.getElementById('detail-flightNo').innerText = flightNo;
|
||||||
|
document.getElementById('detail-port').innerText = port;
|
||||||
|
document.getElementById('detail-remark').innerText = remark;
|
||||||
|
document.getElementById('detail-inTime').innerText = "2026-07-20 15:59:20";
|
||||||
|
document.getElementById('detail-source').innerText = "空运";
|
||||||
|
|
||||||
|
const st = document.getElementById('detail-status');
|
||||||
|
st.innerText = status;
|
||||||
|
st.className = 'text-[11px] px-2 rounded-[6px] font-medium leading-none h-5 flex items-center';
|
||||||
|
if (status === '占用') {
|
||||||
|
st.classList.add('bg-orange-100', 'text-orange-600');
|
||||||
|
} else if (status === '可用') {
|
||||||
|
st.classList.add('bg-green-100','text-green-600');
|
||||||
|
} else if (status === '维修') {
|
||||||
|
st.classList.add('bg-red-100','text-red-600');
|
||||||
|
} else {
|
||||||
|
st.className = 'text-[14px] font-normal text-[#111827]';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('detailOverlay').classList.remove('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideUldDetail() {
|
||||||
|
document.getElementById('detailOverlay').classList.add('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
function openEdit() {
|
||||||
|
document.getElementById('editOverlay').classList.remove('hidden');
|
||||||
|
document.getElementById('edit-uldNo').value = currentDetail.uldNo;
|
||||||
|
document.getElementById('edit-weight').value = currentDetail.weight;
|
||||||
|
document.getElementById('edit-flightNo').value = currentDetail.flightNo;
|
||||||
|
document.getElementById('edit-port').value = currentDetail.port;
|
||||||
|
document.getElementById('edit-inTime').value = "2026-07-20 15:59:20";
|
||||||
|
document.getElementById('edit-remark').value = currentDetail.remark;
|
||||||
|
|
||||||
|
const st = document.getElementById('edit-status-text');
|
||||||
|
st.textContent = currentDetail.status;
|
||||||
|
st.className = 'text-[13px] font-medium px-2 py-0.5 rounded-[6px]';
|
||||||
|
if (currentDetail.status === '占用') {
|
||||||
|
st.classList.add('bg-[#FFF3E0]','text-[#E67722]');
|
||||||
|
} else if (currentDetail.status === '可用') {
|
||||||
|
st.classList.add('bg-green-100','text-green-600');
|
||||||
|
} else if (currentDetail.status === '维修') {
|
||||||
|
st.classList.add('bg-red-100','text-red-600');
|
||||||
|
} else {
|
||||||
|
st.classList.add('text-gray-800');
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('edit-airline-text').textContent = currentDetail.airline;
|
||||||
|
document.getElementById('edit-source-text').textContent = '空运';
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeEdit() {
|
||||||
|
document.getElementById('editOverlay').classList.add('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveEdit() {
|
||||||
|
alert('修改成功');
|
||||||
|
closeEdit();
|
||||||
|
hideUldDetail();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleFilterDrawer(show) {
|
||||||
|
document.getElementById('filterOverlay').style.display = show ? 'flex' : 'none';
|
||||||
|
}
|
||||||
|
function resetFilter() {
|
||||||
|
document.querySelectorAll('#filterOverlay input').forEach(i=>i.value='');
|
||||||
|
}
|
||||||
|
function confirmFilter() {
|
||||||
|
toggleFilterDrawer(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleSelectAll(checked) {
|
||||||
|
document.querySelectorAll('main .custom-checkbox-round').forEach(cb=>cb.checked=checked);
|
||||||
|
updateSelectedCount();
|
||||||
|
}
|
||||||
|
function handleCheckboxClick() {
|
||||||
|
updateSelectedCount();
|
||||||
|
}
|
||||||
|
function updateSelectedCount() {
|
||||||
|
const total = document.querySelectorAll('main .custom-checkbox-round').length;
|
||||||
|
const ckd = document.querySelectorAll('main .custom-checkbox-round:checked').length;
|
||||||
|
document.getElementById('selected-count').innerText = ckd+' / '+total;
|
||||||
|
document.getElementById('select-all-cb').checked = total > 0 && total === ckd;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showAddDialog() {
|
||||||
|
document.getElementById('addUldOverlay').classList.remove('hidden');
|
||||||
|
}
|
||||||
|
function hideAddDialog() {
|
||||||
|
document.getElementById('addUldOverlay').classList.add('hidden');
|
||||||
|
}
|
||||||
|
function saveUld() {
|
||||||
|
alert('保存成功');
|
||||||
|
hideAddDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
let currentSelectField = '';
|
||||||
|
function showSelectPanel(field, title, options) {
|
||||||
|
currentSelectField = field;
|
||||||
|
document.getElementById('selectPanelTitle').textContent = title;
|
||||||
|
const box = document.getElementById('selectPanelOptions');
|
||||||
|
box.innerHTML = '';
|
||||||
|
options.forEach(opt=>{
|
||||||
|
const d = document.createElement('div');
|
||||||
|
d.className = 'py-3 px-4 text-center border-b cursor-pointer hover:bg-gray-50';
|
||||||
|
if(field.includes('status')){
|
||||||
|
let cls = opt=='占用'?'bg-[#FFF3E0] text-[#E67722]':
|
||||||
|
opt=='可用'?'bg-green-100 text-green-600':'bg-red-100 text-red-600';
|
||||||
|
d.innerHTML = `<span class="${cls} px-2 py-0.5 rounded-[6px] text-sm font-medium">${opt}</span>`;
|
||||||
|
} else {
|
||||||
|
d.textContent = opt;
|
||||||
|
}
|
||||||
|
d.onclick = ()=>{
|
||||||
|
if(field === 'editStatus'){
|
||||||
|
const t = document.getElementById('edit-status-text');
|
||||||
|
t.textContent = opt;
|
||||||
|
t.className = 'text-[13px] font-medium px-2 py-0.5 rounded-[6px]';
|
||||||
|
if(opt=='占用'){
|
||||||
|
t.classList.add('bg-[#FFF3E0]','text-[#E67722]');
|
||||||
|
}
|
||||||
|
if(opt=='可用')t.classList.add('bg-green-100','text-green-600');
|
||||||
|
if(opt=='维修')t.classList.add('bg-red-100','text-red-600');
|
||||||
|
}
|
||||||
|
if(field === 'editAirline') document.getElementById('edit-airline-text').textContent = opt;
|
||||||
|
if(field === 'editSource') document.getElementById('edit-source-text').textContent = opt;
|
||||||
|
if(field === 'status') document.getElementById('add-status-text').textContent = opt;
|
||||||
|
if(field === 'airline') document.getElementById('add-airline-text').textContent = opt;
|
||||||
|
if(field === 'source') document.getElementById('add-source-text').textContent = opt;
|
||||||
|
hideSelectPanel();
|
||||||
|
};
|
||||||
|
box.appendChild(d);
|
||||||
|
});
|
||||||
|
document.getElementById('selectPanel').style.display = 'flex';
|
||||||
|
}
|
||||||
|
function hideSelectPanel() {
|
||||||
|
document.getElementById('selectPanel').style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleBatchDelete() {
|
||||||
|
const ckd = document.querySelectorAll('main .custom-checkbox-round:checked').length;
|
||||||
|
if(ckd===0)return alert('请选择');
|
||||||
|
if(confirm('确定删除?')) alert('删除成功');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
715
documents/5.5寸手持端设计文件/02_出库交接/出库交接.html
Normal file
715
documents/5.5寸手持端设计文件/02_出库交接/出库交接.html
Normal file
@@ -0,0 +1,715 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
|
||||||
|
<title>出库交接 - 移动端原型</title>
|
||||||
|
<!-- Tailwind CSS -->
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/tailwindcss.js"></script>
|
||||||
|
<!-- Iconify -->
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/iconify-icon.min.js"></script>
|
||||||
|
<style>
|
||||||
|
@font-face {
|
||||||
|
font-family: 'PingFang SC';
|
||||||
|
src: local('PingFang SC');
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: 'PingFang SC', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||||
|
background-color: #e2e8f0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
/* 模拟手机容器 */
|
||||||
|
.phone-container {
|
||||||
|
width: 375px;
|
||||||
|
height: 812px;
|
||||||
|
background-color: #f5f6fa;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
||||||
|
border: 8px solid #1a1a1a;
|
||||||
|
border-radius: 40px;
|
||||||
|
}
|
||||||
|
/* 隐藏滚动条但保留功能 */
|
||||||
|
.no-scrollbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.no-scrollbar {
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
/* 页面切换动画 */
|
||||||
|
.page {
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.page.active {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
/* 按钮点击态 */
|
||||||
|
.btn-active:active {
|
||||||
|
opacity: 0.7;
|
||||||
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
|
/* 复选框样式 */
|
||||||
|
.custom-checkbox {
|
||||||
|
appearance: none;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border: 2px solid #cbd5e1;
|
||||||
|
border-radius: 4px;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.2s;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
.custom-checkbox:checked {
|
||||||
|
background-color: #2563EB;
|
||||||
|
border-color: #2563EB;
|
||||||
|
}
|
||||||
|
.custom-checkbox:checked::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 6px;
|
||||||
|
top: 2px;
|
||||||
|
width: 5px;
|
||||||
|
height: 10px;
|
||||||
|
border: solid white;
|
||||||
|
border-width: 0 2px 2px 0;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
.custom-checkbox-round {
|
||||||
|
appearance: none;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border: 2px solid #cbd5e1;
|
||||||
|
border-radius: 50%;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.2s;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
.custom-checkbox-round:checked {
|
||||||
|
background-color: #2563EB;
|
||||||
|
border-color: #2563EB;
|
||||||
|
}
|
||||||
|
.custom-checkbox-round:checked::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 6px;
|
||||||
|
top: 2px;
|
||||||
|
width: 5px;
|
||||||
|
height: 10px;
|
||||||
|
border: solid white;
|
||||||
|
border-width: 0 2px 2px 0;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
/* 卡片选中样式已移除 */
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="phone-container">
|
||||||
|
<!-- 状态栏模拟 -->
|
||||||
|
<div class="h-10 w-full flex justify-between items-center px-8 flex-none bg-[#2563EB] text-white">
|
||||||
|
<span class="text-xs font-semibold">09:41</span>
|
||||||
|
<div class="flex space-x-1 items-center">
|
||||||
|
<iconify-icon icon="mdi:signal" width="14"></iconify-icon>
|
||||||
|
<iconify-icon icon="mdi:wifi" width="14"></iconify-icon>
|
||||||
|
<iconify-icon icon="mdi:battery" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 页面1: 货运列表首页 -->
|
||||||
|
<div class="page active" id="page-home">
|
||||||
|
<!-- 顶部导航 -->
|
||||||
|
<div class="bg-[#2563EB] text-white h-12 flex items-center justify-between px-4 flex-none">
|
||||||
|
<div class="flex items-center btn-active" onclick="alert('返回首页')">
|
||||||
|
<iconify-icon icon="mdi:chevron-left" width="28"></iconify-icon>
|
||||||
|
<span class="text-sm font-bold -ml-1">返回</span>
|
||||||
|
</div>
|
||||||
|
<h1 class="text-lg font-medium">出库交接</h1>
|
||||||
|
<div class="w-16"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 内容滚动区 -->
|
||||||
|
<div class="flex-1 overflow-y-auto no-scrollbar pb-24">
|
||||||
|
<!-- 搜索栏 -->
|
||||||
|
<section class="px-4 pt-4 pb-3 bg-white">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 shadow-sm rounded-[12px] h-10 px-3 gap-2 flex-1">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] text-lg flex-none" icon="mdi:magnify"></iconify-icon>
|
||||||
|
<input class="flex-1 bg-transparent text-[14px] text-gray-800 placeholder-gray-400 outline-none border-none rounded-lg px-2" placeholder="搜索ULD编号" type="text"/>
|
||||||
|
<button class="flex-none text-blue-500">
|
||||||
|
<iconify-icon class="text-lg" icon="mdi:qrcode-scan"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button class="bg-white p-2.5 rounded-full shadow-sm border border-gray-200 text-[#2563EB] flex items-center justify-center flex-none" onclick="toggleFilterDrawer(true)">
|
||||||
|
<iconify-icon class="text-xl" icon="mdi:filter-variant"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- 子Tab切换栏 -->
|
||||||
|
<div class="flex bg-white border-b sticky top-0 z-20">
|
||||||
|
<button class="flex-1 py-3 text-sm font-bold text-[#1F2937] border-b-2 border-[#1F2937] transition-all" id="tab-pending" onclick="switchTab('pending')">
|
||||||
|
待交接 <span class="bg-[#DBEAF6] text-[#2563EB] text-[11px] font-medium px-1.5 py-0.5 rounded-md ml-1.5">3</span>
|
||||||
|
</button>
|
||||||
|
<button class="flex-1 py-3 text-sm font-bold text-gray-500 text-[14px] border-b-2 border-transparent transition-all" id="tab-shipped" onclick="switchTab('shipped')">
|
||||||
|
已交接 <span class="bg-[#DBEAF6] text-[#2563EB] text-[11px] font-medium px-1.5 py-0.5 rounded-md ml-1.5">3</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 列表内容 -->
|
||||||
|
<div class="p-3 pt-4 space-y-3" id="list-pending">
|
||||||
|
<!-- 卡片 1 -->
|
||||||
|
<div class="pending-card bg-white rounded-xl shadow-sm p-4 mb-3 overflow-hidden">
|
||||||
|
<!-- 顶部行 -->
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input class="item-checkbox custom-checkbox-round flex-none" onclick="handleCheckboxClick(this, event)" type="checkbox"/>
|
||||||
|
<div class="text-[#2563EB] text-[15px] font-bold">PMC90901CZ</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-green-100 text-green-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">IMP代码</div>
|
||||||
|
</div>
|
||||||
|
<!-- 航班信息行 -->
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:airplane"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">航班信息:20260706/MU1111</span>
|
||||||
|
</div>
|
||||||
|
<!-- 统计框 -->
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">架子车号</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">076</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">目的港</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">LAX</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">装机重</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">200kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 库位信息行 -->
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:map-marker"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">库位:大棚A3</span>
|
||||||
|
</div>
|
||||||
|
<!-- 查看详情链接 -->
|
||||||
|
<div class="mt-4 flex justify-end border-t border-gray-100 pt-3">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer btn-active" onclick="showDetail({id: 'PMC87678MU', status: '待交接', rackNo: '076', location: 'A区-03货位', counterPerson: '--', counterTime: '--', outboundPerson: '', outboundTime: ''})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 卡片 2 -->
|
||||||
|
<div class="pending-card bg-white rounded-xl shadow-sm p-4 mb-3 overflow-hidden">
|
||||||
|
<!-- 顶部行 -->
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input class="item-checkbox custom-checkbox-round flex-none" onclick="handleCheckboxClick(this, event)" type="checkbox"/>
|
||||||
|
<div class="text-[#2563EB] text-[15px] font-bold">AKE87865MU</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-red-600 text-white text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">IMP代码</div>
|
||||||
|
</div>
|
||||||
|
<!-- 航班信息行 -->
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:airplane"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">航班信息:20260706/CA2222</span>
|
||||||
|
</div>
|
||||||
|
<!-- 统计框 -->
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">架子车号</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">066</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">目的港</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">LAX</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">装机重</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">150kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 库位信息行 -->
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:map-marker"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">库位:空侧-05</span>
|
||||||
|
</div>
|
||||||
|
<!-- 查看详情链接 -->
|
||||||
|
<div class="mt-4 flex justify-end border-t border-gray-100 pt-3">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer btn-active" onclick="showDetail({id: 'AKE87865MU', status: '待交接', agent: '043', flightDate: '20260706', flightNo: 'CA2222', pieces: '85', weight: '150', rackNo: '055', carrier: 'CA', origin: 'PEK', location: 'B区-05货位', code: '076', counterPerson: '--', counterTime: '--', outboundPerson: '', outboundTime: ''})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 卡片 3 -->
|
||||||
|
<div class="pending-card bg-white rounded-xl shadow-sm p-4 mb-3 overflow-hidden">
|
||||||
|
<!-- 顶部行 -->
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input class="item-checkbox custom-checkbox-round flex-none" onclick="handleCheckboxClick(this, event)" type="checkbox"/>
|
||||||
|
<div class="text-[#2563EB] text-[15px] font-bold">PMC87678MU</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-red-600 text-white text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">IMP代码</div>
|
||||||
|
</div>
|
||||||
|
<!-- 航班信息行 -->
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:airplane"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">航班信息:20260707/3U3333</span>
|
||||||
|
</div>
|
||||||
|
<!-- 统计框 -->
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">架子车号</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">055</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">目的港</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">LAX</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">装机重</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">450kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 库位信息行 -->
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:map-marker"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">库位:C区-01货位</span>
|
||||||
|
</div>
|
||||||
|
<!-- 查看详情链接 -->
|
||||||
|
<div class="mt-4 flex justify-end border-t border-gray-100 pt-3">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer btn-active" onclick="showDetail({id: 'PMC87678MU', status: '待交接', agent: 'DHL', flightDate: '20260707', flightNo: '3U3333', pieces: '200', weight: '450', rackNo: '055', carrier: '3U', origin: 'CTU', location: 'C区-01货位', code: '076', counterPerson: '--', counterTime: '--', outboundPerson: '', outboundTime: ''})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 已交接列表内容 -->
|
||||||
|
<div class="p-3 pt-4 space-y-3 hidden" id="list-shipped">
|
||||||
|
<!-- 卡片 1 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm p-4 mb-3">
|
||||||
|
<!-- 顶部行 -->
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="text-[#1F2937] text-[15px] font-bold">PMC90901CZ</div>
|
||||||
|
<div class="flex items-center gap-1 text-[#1F2937] text-[13px] font-medium">
|
||||||
|
<iconify-icon class="text-[#10B981]" icon="mdi:check-circle" width="16"></iconify-icon>
|
||||||
|
<span>已交接</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 操作信息行 -->
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:airplane"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">航班信息:20260704/MU1111</span>
|
||||||
|
</div>
|
||||||
|
<!-- 统计框 -->
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">架子车号</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">076</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">目的港</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">LAX</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">装机重</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">80kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 操作人信息 -->
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:account-outline"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">交接人:张三 · 交接时间:2026-07-05 11:45</span>
|
||||||
|
</div>
|
||||||
|
<!-- 查看详情链接 -->
|
||||||
|
<div class="mt-2 flex justify-end border-t border-gray-50 pt-2">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer" onclick="showDetail({id: 'PMC90901CZ', status: '已交接', agent: '076', rackNo: '076', location: 'B区-05货位', code: '076', counterTime: '2026-07-05 10:30', counterPerson: '张三', outboundTime: '2026-07-05 11:45', outboundPerson: '张三'})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 卡片 2 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm p-4 mb-3">
|
||||||
|
<!-- 顶部行 -->
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="text-[#1F2937] text-[15px] font-bold">AKE87865MU</div>
|
||||||
|
<div class="flex items-center gap-1 text-[#1F2937] text-[13px] font-medium">
|
||||||
|
<iconify-icon class="text-[#10B981]" icon="mdi:check-circle" width="16"></iconify-icon>
|
||||||
|
<span>已交接</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 操作信息行 -->
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:airplane"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">航班信息:20260705/CA2222</span>
|
||||||
|
</div>
|
||||||
|
<!-- 统计框 -->
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">架子车号</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">043</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">目的港</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">LAX</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">装机重</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">300kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 操作人信息 -->
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:account-outline"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">交接人:赵六 · 交接时间:2026-07-06 10:30</span>
|
||||||
|
</div>
|
||||||
|
<!-- 查看详情链接 -->
|
||||||
|
<div class="mt-2 flex justify-end border-t border-gray-50 pt-2">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer" onclick="showDetail({id: 'AKE87865MU', status: '已交接', agent: '043', flightDate: '20260705', flightNo: 'CA2222', pieces: '120', weight: '300', pickupNo: 'TH20260702002', rackNo: '鲜花绿植', carrier: 'CA', origin: 'SFO', location: 'A区-08货位', code: '076', counterTime: '2026-07-06 09:15', counterPerson: '王五', outboundTime: '2026-07-06 10:30', outboundPerson: '赵六'})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 卡片 3 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm p-4 mb-3">
|
||||||
|
<!-- 顶部行 -->
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="text-[#1F2937] text-[15px] font-bold">PMC87678MU</div>
|
||||||
|
<div class="flex items-center gap-1 text-[#1F2937] text-[13px] font-medium">
|
||||||
|
<iconify-icon class="text-[#10B981]" icon="mdi:check-circle" width="16"></iconify-icon>
|
||||||
|
<span>已交接</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 操作信息行 -->
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:airplane"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">航班信息:20260705/3U3333</span>
|
||||||
|
</div>
|
||||||
|
<!-- 统计框 -->
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">架子车号</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">077</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">目的港</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">LAX</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">装机重</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">160kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 操作人信息 -->
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:account-outline"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">交接人:孙八 · 交接时间:2026-07-06 15:20</span>
|
||||||
|
</div>
|
||||||
|
<!-- 查看详情链接 -->
|
||||||
|
<div class="mt-2 flex justify-end border-t border-gray-50 pt-2">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer" onclick="showDetail({id: 'PMC87678MU', status: '已交接', agent: 'DHL', flightDate: '20260705', flightNo: '3U3333', pieces: '75', weight: '160', pickupNo: 'TH20260703003', rackNo: '生鲜食品', carrier: '3U', origin: 'CDG', location: 'D区-02货位', code: 'NOR', counterTime: '2026-07-06 14:00', counterPerson: '钱七', outboundTime: '2026-07-06 15:20', outboundPerson: '孙八'})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 底部工具栏 -->
|
||||||
|
<div class="absolute bottom-0 w-full bg-white border-t border-gray-200 z-40 flex flex-col pt-4 pb-4" id="bottom-toolbar">
|
||||||
|
<!-- 操作区域 -->
|
||||||
|
<div class="px-4 flex items-center w-full">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input class="custom-checkbox-round" id="select-all-cb" onclick="toggleSelectAll(this.checked)" type="checkbox"/>
|
||||||
|
<label class="text-[13px] text-[#1F2937] font-medium cursor-pointer" for="select-all-cb">全选</label>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1"></div>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<span class="text-[12px] text-[#9CA3AF]">已选 <span id="selected-count">0</span> 项</span>
|
||||||
|
<button class="bg-[#2563EB] text-white text-[15px] font-bold px-5 py-2 rounded-[10px] shadow-lg shadow-blue-500/25 btn-active" onclick="alert('交接操作')">
|
||||||
|
交接
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 页面2: 详情页 -->
|
||||||
|
<div class="page" id="page-detail">
|
||||||
|
<!-- 顶部导航 -->
|
||||||
|
<div class="bg-[#2563EB] text-white h-12 flex items-center justify-between px-4 flex-none">
|
||||||
|
<div class="flex items-center btn-active" onclick="switchPage('home')">
|
||||||
|
<iconify-icon icon="mdi:chevron-left" width="28"></iconify-icon>
|
||||||
|
<span class="text-sm font-bold -ml-1">返回</span>
|
||||||
|
</div>
|
||||||
|
<h1 class="text-lg font-medium">板箱详情</h1>
|
||||||
|
<div class="w-16"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1 overflow-y-auto no-scrollbar pb-8 p-4">
|
||||||
|
<!-- 货运单据样式卡片 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm overflow-hidden border border-gray-100">
|
||||||
|
<!-- 1. 顶部蓝色条带 -->
|
||||||
|
<div class="bg-[#2563EB] px-4 py-3 flex justify-between items-center text-white">
|
||||||
|
<span class="font-bold text-[17px] leading-tight" id="detail-awb">781-22222620</span>
|
||||||
|
</div>
|
||||||
|
<div class="p-4">
|
||||||
|
<!-- 3. 货物名称 -->
|
||||||
|
<div class="text-[22px] font-bold text-[#111827] mb-3" id="detail-rack-no">076</div>
|
||||||
|
<!-- 4. 两列信息表格 -->
|
||||||
|
<div class="grid grid-cols-2 gap-x-8 gap-y-3">
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">装机重</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-count">55</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">航班日期</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-weight">20260706</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">航班号</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-carrier">MU2231</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">目的港</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-flight-date">LAX</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">IMP代码</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-carrier">X</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">板型</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-flight-date">QP</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">库位</div>
|
||||||
|
<div class="flex">
|
||||||
|
<span class="bg-orange-50 text-orange-600 px-1 rounded text-[15px] font-bold" id="detail-location">1111111</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">备注</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-flight-no">危险品</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 复磅信息卡片 -->
|
||||||
|
<div class="mt-4 bg-white rounded-xl shadow-sm overflow-hidden border border-gray-200 hidden" id="detail-outbound-card">
|
||||||
|
<div class="bg-[#10B981] px-4 py-2.5">
|
||||||
|
<span class="text-white font-semibold text-[15px]">复磅信息</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white px-4 py-3 grid grid-cols-2 gap-y-3">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[12px] text-[#9CA3AF] font-normal mb-[2px]">复磅人</span>
|
||||||
|
<span class="text-[14px] text-[#1F2937] font-medium" id="detail-counter-person">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[12px] text-[#9CA3AF] font-normal mb-[2px]">复磅时间</span>
|
||||||
|
<span class="text-[14px] text-[#1F2937] font-medium" id="detail-counter-time">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col" id="detail-outbound-person-row">
|
||||||
|
<span class="text-[12px] text-[#9CA3AF] font-normal mb-[2px]">交接人</span>
|
||||||
|
<span class="text-[14px] text-[#1F2937] font-medium" id="detail-outbound-person">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col" id="detail-outbound-time-row">
|
||||||
|
<span class="text-[12px] text-[#9CA3AF] font-normal mb-[2px]">交接时间</span>
|
||||||
|
<span class="text-[14px] text-[#1F2937] font-medium" id="detail-outbound-time">-</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 筛选条件弹窗(从ULD管理移植) -->
|
||||||
|
<div class="absolute inset-0 z-[100] bg-black/50 flex items-end justify-center" id="filterOverlay" onclick="toggleFilterDrawer(false)" style="display: none;">
|
||||||
|
<div class="bg-white rounded-t-[20px] w-full max-w-[375px] px-5 pt-6 pb-8" onclick="event.stopPropagation()">
|
||||||
|
<!-- 标题 -->
|
||||||
|
<div class="relative flex items-center justify-center mb-6">
|
||||||
|
<button class="absolute right-0 top-0 text-gray-400" onclick="toggleFilterDrawer(false)">
|
||||||
|
<iconify-icon class="text-2xl" icon="mdi:close"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
<h2 class="text-[18px] font-bold text-gray-900">筛选条件</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-5">
|
||||||
|
<!-- 航班日期 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">航班日期</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择航班日期" readonly type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:calendar" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 进港航班号 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">航班号</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请输入航班号" type="text"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 交接人 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">交接人</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择交接人" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:chevron-down" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 底部按钮 -->
|
||||||
|
<div class="flex gap-3 mt-8">
|
||||||
|
<button class="flex-1 h-11 text-[15px] font-medium text-gray-600 bg-white border border-gray-200 rounded-[10px]" onclick="resetFilter()">重置</button>
|
||||||
|
<button class="flex-1 h-11 text-[15px] font-medium text-white bg-[#2563EB] rounded-[10px] shadow-sm" onclick="confirmFilter()">确认</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// 页面切换逻辑
|
||||||
|
function switchPage(pageId) {
|
||||||
|
document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
|
||||||
|
document.getElementById('page-' + pageId).classList.add('active');
|
||||||
|
if(pageId === 'detail') {
|
||||||
|
document.querySelector('#page-detail .overflow-y-auto').scrollTop = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 子Tab切换逻辑
|
||||||
|
function switchTab(type) {
|
||||||
|
const tabPending = document.getElementById('tab-pending');
|
||||||
|
const tabShipped = document.getElementById('tab-shipped');
|
||||||
|
const listPending = document.getElementById('list-pending');
|
||||||
|
const listShipped = document.getElementById('list-shipped');
|
||||||
|
const bottomToolbar = document.getElementById('bottom-toolbar');
|
||||||
|
|
||||||
|
if (type === 'pending') {
|
||||||
|
// 待交接
|
||||||
|
tabPending.classList.add('text-[#1F2937]', 'border-[#1F2937]');
|
||||||
|
tabPending.classList.remove('text-gray-500', 'border-transparent');
|
||||||
|
|
||||||
|
tabShipped.classList.add('text-gray-500', 'border-transparent');
|
||||||
|
tabShipped.classList.remove('text-[#1F2937]', 'border-[#1F2937]');
|
||||||
|
|
||||||
|
listPending.classList.remove('hidden');
|
||||||
|
listShipped.classList.add('hidden');
|
||||||
|
bottomToolbar.style.display = 'flex';
|
||||||
|
} else {
|
||||||
|
// 已交接
|
||||||
|
tabShipped.classList.add('text-[#1F2937]', 'border-[#1F2937]');
|
||||||
|
tabShipped.classList.remove('text-gray-500', 'border-transparent');
|
||||||
|
|
||||||
|
tabPending.classList.add('text-gray-500', 'border-transparent');
|
||||||
|
tabPending.classList.remove('text-[#1F2937]', 'border-[#1F2937]');
|
||||||
|
|
||||||
|
listShipped.classList.remove('hidden');
|
||||||
|
listPending.classList.add('hidden');
|
||||||
|
bottomToolbar.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全选/取消全选
|
||||||
|
function toggleSelectAll(checked) {
|
||||||
|
const checkboxes = document.querySelectorAll('.item-checkbox');
|
||||||
|
checkboxes.forEach(cb => {
|
||||||
|
cb.checked = checked;
|
||||||
|
});
|
||||||
|
updateSelectionCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理卡片复选框点击
|
||||||
|
function handleCheckboxClick(checkbox, event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
updateSelectionCount();
|
||||||
|
const checkboxes = document.querySelectorAll('.item-checkbox');
|
||||||
|
const selectAllCb = document.getElementById('select-all-cb');
|
||||||
|
const allChecked = Array.from(checkboxes).every(cb => cb.checked);
|
||||||
|
selectAllCb.checked = allChecked;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新选中计数
|
||||||
|
function updateSelectionCount() {
|
||||||
|
const checkedCount = document.querySelectorAll('.item-checkbox:checked').length;
|
||||||
|
document.getElementById('selected-count').textContent = checkedCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示详情页并填充数据
|
||||||
|
function showDetail(data) {
|
||||||
|
if (!data) return;
|
||||||
|
const setText = (id, text) => {
|
||||||
|
const el = document.getElementById(id);
|
||||||
|
if (el) el.textContent = text || '-';
|
||||||
|
};
|
||||||
|
|
||||||
|
setText('detail-awb', data.id);
|
||||||
|
setText('detail-rack-no', data.rackNo);
|
||||||
|
setText('detail-weight', (data.weight || '') + (data.weight && !data.weight.toString().includes('kg') ? ' kg' : ''));
|
||||||
|
setText('detail-flight-date', data.flightDate);
|
||||||
|
setText('detail-flight-no', data.flightNo);
|
||||||
|
setText('detail-location', data.location);
|
||||||
|
|
||||||
|
const outboundCard = document.getElementById('detail-outbound-card');
|
||||||
|
if (outboundCard) {
|
||||||
|
outboundCard.classList.remove('hidden');
|
||||||
|
setText('detail-counter-person', data.counterPerson);
|
||||||
|
setText('detail-counter-time', data.counterTime);
|
||||||
|
setText('detail-outbound-person', data.outboundPerson);
|
||||||
|
setText('detail-outbound-time', data.outboundTime);
|
||||||
|
|
||||||
|
const outboundPersonRow = document.getElementById('detail-outbound-person-row');
|
||||||
|
const outboundTimeRow = document.getElementById('detail-outbound-time-row');
|
||||||
|
|
||||||
|
if (data.status === '已交接') {
|
||||||
|
outboundPersonRow.classList.remove('hidden');
|
||||||
|
outboundTimeRow.classList.remove('hidden');
|
||||||
|
} else {
|
||||||
|
outboundPersonRow.classList.add('hidden');
|
||||||
|
outboundTimeRow.classList.add('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switchPage('detail');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选面板(移植自ULD管理)
|
||||||
|
function toggleFilterDrawer(show) {
|
||||||
|
const overlay = document.getElementById('filterOverlay');
|
||||||
|
overlay.style.display = show ? 'flex' : 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetFilter() {
|
||||||
|
const inputs = document.querySelectorAll('#filterOverlay input');
|
||||||
|
inputs.forEach(input => input.value = '');
|
||||||
|
}
|
||||||
|
|
||||||
|
function confirmFilter() {
|
||||||
|
toggleFilterDrawer(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化日期
|
||||||
|
const today = new Date().toISOString().split('T')[0];
|
||||||
|
console.log("System date initialized:", today);
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
151
documents/5.5寸手持端设计文件/03_出港计重/detail.html
Normal file
151
documents/5.5寸手持端设计文件/03_出港计重/detail.html
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
|
||||||
|
<title>运单详情</title>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/tailwindcss.js"></script>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/iconify-icon.min.js"></script>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background: #F3F4F6;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "PingFang SC", "Helvetica Neue", sans-serif;
|
||||||
|
}
|
||||||
|
/* 统一手机外壳容器 */
|
||||||
|
.phone-container {
|
||||||
|
width: 390px;
|
||||||
|
height: 844px;
|
||||||
|
background: #1a1a1a;
|
||||||
|
border-radius: 55px;
|
||||||
|
border: 8px solid #1F2937;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-shadow: 0 30px 60px rgba(0,0,0,0.3);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
/* 手机内部屏幕区域 */
|
||||||
|
.phone-screen {
|
||||||
|
flex: 1;
|
||||||
|
background: #F2F5F9;
|
||||||
|
margin: 0 4px 4px 4px;
|
||||||
|
border-radius: 46px;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.content-scroll {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.content-scroll::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="phone-container">
|
||||||
|
<div class="phone-screen">
|
||||||
|
|
||||||
|
<!-- 状态栏 + 导航栏 蓝色连体区域 -->
|
||||||
|
<div class="bg-[#2563EB] flex flex-col flex-none">
|
||||||
|
<!-- 手机状态栏 -->
|
||||||
|
<div class="flex items-center justify-between h-[28px] text-white text-[12px] px-6">
|
||||||
|
<span class="text-white font-medium tracking-wide">09:10</span>
|
||||||
|
<div class="flex items-center gap-[5px]">
|
||||||
|
<iconify-icon class="text-white text-[13px]" icon="mdi:signal-cellular-3"></iconify-icon>
|
||||||
|
<iconify-icon class="text-white text-[13px]" icon="mdi:wifi"></iconify-icon>
|
||||||
|
<iconify-icon class="text-white text-[15px]" icon="mdi:battery"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 导航栏 -->
|
||||||
|
<div class="text-white h-12 flex items-center px-4">
|
||||||
|
<a class="flex items-center gap-1" href="records.html">
|
||||||
|
<iconify-icon class="text-xl" icon="mdi:chevron-left"></iconify-icon>
|
||||||
|
<span class="text-[16px]">返回</span>
|
||||||
|
</a>
|
||||||
|
<h1 class="flex-1 text-center text-[17px] font-semibold mr-10">运单详情</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content-scroll">
|
||||||
|
<!-- 卡片1 — 运单概览 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-md mb-4 overflow-hidden border border-gray-100 mx-4 mt-4">
|
||||||
|
|
||||||
|
<div class="px-4 py-2.5 flex items-center border-b border-gray-100">
|
||||||
|
<div class="w-1 h-4 bg-blue-500 rounded-full inline-block mr-2"></div>
|
||||||
|
<span class="text-xs font-semibold text-gray-800" id="det-uldTitle">基本信息</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="p-3 grid grid-cols-2 gap-y-3 gap-x-4 border-t border-gray-50 pt-3">
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 mb-0.5">运单号</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-billNo">78111112222</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 mb-0.5">件数</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-piece">85</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 mb-0.5">重量</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-weight">156 kg</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 mb-0.5">特码</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-code">DGR</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 mb-0.5">代理</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-agent">ATR</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 mb-0.5">航班日期</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-flightDate">2026-07-03</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 mb-0.5">航班号</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-flightNo">MU2222</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 mb-0.5">航程</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-route">PVG - CAN</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 mb-0.5">业务类型</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-type">普通货物运输</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 mb-0.5">通道号</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-channel">出港收运1</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 mb-0.5">品名</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-itemName">电子产品</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center col-span-2">
|
||||||
|
<span class="text-[10px] text-gray-500 mb-0.5">备注</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-remark">测试</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pb-6"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- iOS 底部指示条 -->
|
||||||
|
<div class="h-5 bg-[#F2F5F9] flex justify-center items-center flex-none">
|
||||||
|
<div class="w-[134px] h-[5px] bg-gray-300 rounded-full"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
419
documents/5.5寸手持端设计文件/03_出港计重/main.html
Normal file
419
documents/5.5寸手持端设计文件/03_出港计重/main.html
Normal file
@@ -0,0 +1,419 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
|
||||||
|
<title>出港待计重</title>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/tailwindcss.js"></script>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/iconify-icon.min.js"></script>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background: #F3F4F6;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "PingFang SC", "Helvetica Neue", sans-serif;
|
||||||
|
}
|
||||||
|
/* 统一手机外壳容器 */
|
||||||
|
.phone-container {
|
||||||
|
width: 390px;
|
||||||
|
height: 844px;
|
||||||
|
background: #1a1a1a;
|
||||||
|
border-radius: 55px;
|
||||||
|
border: 8px solid #1F2937;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-shadow: 0 30px 60px rgba(0,0,0,0.3);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
/* 手机内部屏幕区域 */
|
||||||
|
.phone-screen {
|
||||||
|
flex: 1;
|
||||||
|
background: #F2F5F9;
|
||||||
|
margin: 0 4px 4px 4px;
|
||||||
|
border-radius: 46px;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
/* 隐藏滚动条 */
|
||||||
|
.no-scrollbar::-webkit-scrollbar { display: none; }
|
||||||
|
.no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
|
||||||
|
/* 卡片淡入动画 */
|
||||||
|
@keyframes fadeInUp {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(18px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.card-animate {
|
||||||
|
animation: fadeInUp 0.5s ease-out both;
|
||||||
|
}
|
||||||
|
.card-animate:nth-child(1) { animation-delay: 0.05s; }
|
||||||
|
.card-animate:nth-child(2) { animation-delay: 0.12s; }
|
||||||
|
.card-animate:nth-child(3) { animation-delay: 0.19s; }
|
||||||
|
.card-animate:nth-child(4) { animation-delay: 0.26s; }
|
||||||
|
/* 卡片点击涟漪效果 */
|
||||||
|
.card-item {
|
||||||
|
transition: transform 0.15s ease, box-shadow 0.15s ease;
|
||||||
|
}
|
||||||
|
.card-item:active {
|
||||||
|
transform: scale(0.985);
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
|
||||||
|
}
|
||||||
|
/* 筛选弹窗动画 */
|
||||||
|
.filter-modal {
|
||||||
|
transition: transform 0.3s ease-out;
|
||||||
|
transform: translateY(100%);
|
||||||
|
}
|
||||||
|
.filter-modal.show {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
.filter-overlay {
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.filter-overlay.show {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="phone-container">
|
||||||
|
<div class="phone-screen">
|
||||||
|
<!-- ===== 顶部连体蓝色区域【状态栏+导航栏】 ===== -->
|
||||||
|
<div class="bg-[#2563EB] flex flex-col flex-none">
|
||||||
|
<!-- 手机状态栏 -->
|
||||||
|
<div class="flex items-center justify-between h-[28px] text-white text-[12px] px-6">
|
||||||
|
<span class="text-white font-medium tracking-wide">09:10</span>
|
||||||
|
<div class="flex items-center gap-[5px]">
|
||||||
|
<iconify-icon class="text-white text-[13px]" icon="mdi:signal-cellular-3"></iconify-icon>
|
||||||
|
<iconify-icon class="text-white text-[13px]" icon="mdi:wifi"></iconify-icon>
|
||||||
|
<iconify-icon class="text-white text-[15px]" icon="mdi:battery"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 导航栏 -->
|
||||||
|
<header class="text-white h-12 flex items-center px-4">
|
||||||
|
<button class="flex items-center text-[15px] gap-0.5" onclick="window.history.back()">
|
||||||
|
<iconify-icon class="text-xl" icon="mdi:chevron-left"></iconify-icon>
|
||||||
|
<span>返回</span>
|
||||||
|
</button>
|
||||||
|
<h1 class="flex-1 text-center text-[17px] font-semibold">出港待计重</h1>
|
||||||
|
<div class="w-12"></div>
|
||||||
|
</header>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ===== 主内容区 ===== -->
|
||||||
|
<main class="flex-1 overflow-y-auto no-scrollbar bg-[#F2F5F9]">
|
||||||
|
<!-- 搜索栏 -->
|
||||||
|
<div class="h-[3px] bg-blue-500 mx-0"></div>
|
||||||
|
<section class="px-4 pt-4 pb-3">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 shadow-sm rounded-[12px] h-10 px-3 gap-2 flex-1">
|
||||||
|
<iconify-icon class="text-gray-400 text-lg flex-none" icon="mdi:magnify"></iconify-icon>
|
||||||
|
<input class="flex-1 bg-transparent text-[14px] text-gray-800 placeholder-gray-400 outline-none border-none rounded-lg px-2" placeholder="搜索运单号/航班号..." type="text"/>
|
||||||
|
<button class="flex-none text-blue-500">
|
||||||
|
<iconify-icon class="text-lg" icon="mdi:qrcode-scan"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button class="bg-white p-2.5 rounded-full shadow-sm border border-gray-200 text-[#2563EB] flex items-center justify-center flex-none" onclick="toggleFilterDrawer(true)">
|
||||||
|
<iconify-icon class="text-xl" icon="mdi:filter-variant"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- 统计标签 -->
|
||||||
|
<div class="flex items-center gap-2 px-4 pb-3">
|
||||||
|
<div class="flex-1 bg-white rounded-lg px-3 py-2.5 shadow-sm border-l-[4px] border-l-[#2563EB]">
|
||||||
|
<div class="text-[11px] text-gray-500">总票数</div>
|
||||||
|
<div class="text-[22px] font-bold text-[#2563EB] leading-tight mt-0.5">4</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 bg-white rounded-lg px-3 py-2.5 shadow-sm border-l-[4px] border-l-orange-500">
|
||||||
|
<div class="text-[11px] text-gray-500">待计重</div>
|
||||||
|
<div class="text-[22px] font-bold text-orange-500 leading-tight mt-0.5">2</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 bg-white rounded-lg px-3 py-2.5 shadow-sm border-l-[4px] border-l-[#10B981]">
|
||||||
|
<div class="text-[11px] text-gray-500">计重中</div>
|
||||||
|
<div class="text-[22px] font-bold text-[#10B981] leading-tight mt-0.5">2</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ===== 运单卡片列表 ===== -->
|
||||||
|
<div class="px-0 pt-3 pb-8">
|
||||||
|
<!-- 卡片 1 -->
|
||||||
|
<div class="card-item card-animate bg-white rounded-2xl shadow-sm shadow-black/5 px-4 py-3.5 mx-4 mb-2.5 cursor-pointer" onclick="window.location.href='weighing.html'">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<div class="flex-1 min-w-0">
|
||||||
|
<div class="flex justify-between items-start mb-3">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<span class="text-[15px] font-bold text-[#1F2937]">78133363398</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="bg-orange-100 text-orange-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">未计重</span>
|
||||||
|
<iconify-icon class="text-gray-400" icon="mdi:chevron-right" width="14"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-y-2 text-[13px] text-gray-500">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:airplane"></iconify-icon>
|
||||||
|
<span>日期:20260721</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:map-marker"></iconify-icon>
|
||||||
|
<span>航程:HFE-LAX</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:truck-outline"></iconify-icon>
|
||||||
|
<span>代理:中外运</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:tag-outline"></iconify-icon>
|
||||||
|
<span>特码:DGR</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2">
|
||||||
|
<button class="w-full bg-[#EFF6FF] text-[#2563EB] text-xs py-2 rounded-[6px] font-medium h-8 flex items-center justify-center" onclick="event.stopPropagation(); this.disabled=true; this.classList.remove('bg-[#EFF6FF]','text-[#2563EB]'); this.classList.add('bg-gray-100','text-gray-400','cursor-not-allowed'); showToast('执行提前运抵:运单号 78133363396')">
|
||||||
|
提前运抵
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 卡片 2 -->
|
||||||
|
<div class="card-item card-animate bg-white rounded-2xl shadow-sm shadow-black/5 px-4 py-3.5 mx-4 mb-2.5 cursor-pointer" onclick="window.location.href='weighing.html'">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<div class="flex-1 min-w-0">
|
||||||
|
<div class="flex justify-between items-start mb-3">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<span class="text-[15px] font-bold text-[#1F2937]">78133363399</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="bg-green-100 text-green-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">计重中</span>
|
||||||
|
<iconify-icon class="text-gray-400" icon="mdi:chevron-right" width="14"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-y-2 text-[13px] text-gray-500">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:airplane"></iconify-icon>
|
||||||
|
<span>日期:20260721</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:map-marker"></iconify-icon>
|
||||||
|
<span>航程:HFE-LAX</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:truck-outline"></iconify-icon>
|
||||||
|
<span>代理:中外运</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:tag-outline"></iconify-icon>
|
||||||
|
<span>特码:DGR</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2">
|
||||||
|
<button class="w-full bg-[#EFF6FF] text-[#2563EB] text-xs py-2 rounded-[6px] font-medium h-8 flex items-center justify-center" onclick="event.stopPropagation(); this.disabled=true; this.classList.remove('bg-[#EFF6FF]','text-[#2563EB]'); this.classList.add('bg-gray-100','text-gray-400','cursor-not-allowed'); showToast('执行提前运抵:运单号 78133363397')">
|
||||||
|
提前运抵
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 卡片 3 -->
|
||||||
|
<div class="card-item card-animate bg-white rounded-2xl shadow-sm shadow-black/5 px-4 py-3.5 mx-4 mb-2.5 cursor-pointer" onclick="window.location.href='weighing.html'">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<div class="flex-1 min-w-0">
|
||||||
|
<div class="flex justify-between items-start mb-3">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<span class="text-[15px] font-bold text-[#1F2937]">78133363398</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="bg-orange-100 text-orange-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">未计重</span>
|
||||||
|
<iconify-icon class="text-gray-400" icon="mdi:chevron-right" width="14"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-y-2 text-[13px] text-gray-500">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:airplane"></iconify-icon>
|
||||||
|
<span>日期:20260721</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:map-marker"></iconify-icon>
|
||||||
|
<span>航程:HFE-LAX</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:truck-outline"></iconify-icon>
|
||||||
|
<span>代理:中外运</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:tag-outline"></iconify-icon>
|
||||||
|
<span>特码:DGR</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2">
|
||||||
|
<button class="w-full bg-[#EFF6FF] text-[#2563EB] text-xs py-2 rounded-[6px] font-medium h-8 flex items-center justify-center" onclick="event.stopPropagation(); this.disabled=true; this.classList.remove('bg-[#EFF6FF]','text-[#2563EB]'); this.classList.add('bg-gray-100','text-gray-400','cursor-not-allowed'); showToast('执行提前运抵:运单号 78133363398')">
|
||||||
|
提前运抵
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 卡片 4 -->
|
||||||
|
<div class="card-item card-animate bg-white rounded-2xl shadow-sm shadow-black/5 px-4 py-3.5 mx-4 mb-2.5 cursor-pointer" onclick="window.location.href='weighing.html'">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<div class="flex-1 min-w-0">
|
||||||
|
<div class="flex justify-between items-start mb-3">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<span class="text-[15px] font-bold text-[#1F2937]">78133363399</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="bg-green-100 text-green-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">计重中</span>
|
||||||
|
<iconify-icon class="text-gray-400 text-lg shrink-0" icon="mdi:chevron-right"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-y-2 text-[13px] text-gray-500">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:airplane"></iconify-icon>
|
||||||
|
<span>日期:20260721</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:map-marker"></iconify-icon>
|
||||||
|
<span>航程:HFE-LAX</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:truck-outline"></iconify-icon>
|
||||||
|
<span>代理:中外运</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:tag-outline"></iconify-icon>
|
||||||
|
<span>特码:DGR</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2">
|
||||||
|
<button class="w-full bg-[#EFF6FF] text-[#2563EB] text-xs py-2 rounded-[6px] font-medium h-8 flex items-center justify-center" onclick="event.stopPropagation(); this.disabled=true; this.classList.remove('bg-[#EFF6FF]','text-[#2563EB]'); this.classList.add('bg-gray-100','text-gray-400','cursor-not-allowed'); showToast('执行提前运抵:运单号 78133363399')">
|
||||||
|
提前运抵
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<!-- ===== iOS 底部指示条 ===== -->
|
||||||
|
<div class="h-5 bg-[#F2F5F9] flex justify-center items-center flex-none">
|
||||||
|
<div class="w-[134px] h-[5px] bg-gray-300 rounded-full"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 计重记录悬浮按钮 -->
|
||||||
|
<a class="absolute bottom-[20px] right-[20px] w-[52px] h-[52px] bg-[#2563EB] rounded-full shadow-lg shadow-blue-500/30 flex items-center justify-center z-50 hover:bg-[#1d4ed8] active:scale-95 transition-transform" href="records.html">
|
||||||
|
<iconify-icon class="text-white text-[24px]" icon="mdi:clipboard-text-clock"></iconify-icon>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- ================== 筛选弹窗(底部弹出) ================== -->
|
||||||
|
<div class="filter-overlay absolute inset-0 bg-black/40 z-40" id="filterOverlay" onclick="toggleFilterDrawer(false)"></div>
|
||||||
|
<div class="filter-modal absolute bottom-0 left-0 right-0 bg-white rounded-t-3xl z-50 p-6 shadow-2xl" id="filter-panel">
|
||||||
|
<div class="relative flex items-center justify-center mb-6">
|
||||||
|
<h2 class="text-center text-[18px] font-bold text-gray-900">筛选条件</h2>
|
||||||
|
<button class="absolute right-0 top-0 text-gray-400" onclick="toggleFilterDrawer(false)">
|
||||||
|
<iconify-icon class="text-2xl" icon="mdi:close"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">通道号</label>
|
||||||
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-3 flex items-center justify-between text-gray-400">
|
||||||
|
<span class="text-sm">请选择通道号</span>
|
||||||
|
<iconify-icon icon="mdi:chevron-down"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-4 mt-4">
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">承运人</label>
|
||||||
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-3 flex items-center justify-between text-gray-800">
|
||||||
|
<span class="text-sm font-medium">MU</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">运单类型</label>
|
||||||
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-3 flex items-center justify-between text-gray-400">
|
||||||
|
<span class="text-sm">请选择运单类型</span>
|
||||||
|
<iconify-icon icon="mdi:chevron-down"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">代理人</label>
|
||||||
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-3 flex items-center justify-between text-gray-400">
|
||||||
|
<span class="text-sm">请选择代理人</span>
|
||||||
|
<iconify-icon icon="mdi:chevron-down"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-4 pt-2">
|
||||||
|
<button class="flex-1 bg-white border border-gray-300 text-gray-600 py-3.5 rounded-xl font-bold" onclick="resetFilter()">
|
||||||
|
重置
|
||||||
|
</button>
|
||||||
|
<button class="flex-1 bg-[#2563EB] text-white py-3.5 rounded-xl font-bold shadow-lg shadow-blue-500/20" onclick="confirmFilter()">
|
||||||
|
确认
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="h-8"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Toast 提示函数
|
||||||
|
function showToast(msg) {
|
||||||
|
var existing = document.querySelector('.custom-toast');
|
||||||
|
if (existing) existing.remove();
|
||||||
|
var toast = document.createElement('div');
|
||||||
|
toast.className = 'custom-toast fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-gray-900 text-white text-sm px-5 py-3 rounded-xl shadow-lg z-50 transition-opacity duration-200';
|
||||||
|
toast.style.maxWidth = '280px';
|
||||||
|
toast.style.textAlign = 'center';
|
||||||
|
toast.style.pointerEvents = 'none';
|
||||||
|
toast.textContent = msg;
|
||||||
|
document.body.appendChild(toast);
|
||||||
|
setTimeout(function() { toast.style.opacity = '0'; setTimeout(function() { toast.remove(); }, 200); }, 1500);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选弹窗显示/隐藏
|
||||||
|
function toggleFilterDrawer(show) {
|
||||||
|
const overlay = document.getElementById('filterOverlay');
|
||||||
|
const modal = document.getElementById('filter-panel');
|
||||||
|
if (show) {
|
||||||
|
overlay.classList.add('show');
|
||||||
|
modal.classList.add('show');
|
||||||
|
} else {
|
||||||
|
overlay.classList.remove('show');
|
||||||
|
modal.classList.remove('show');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置筛选
|
||||||
|
function resetFilter() {
|
||||||
|
showToast('已重置筛选条件');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确认筛选
|
||||||
|
function confirmFilter() {
|
||||||
|
toggleFilterDrawer(false);
|
||||||
|
showToast('已应用筛选条件');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
282
documents/5.5寸手持端设计文件/03_出港计重/records.html
Normal file
282
documents/5.5寸手持端设计文件/03_出港计重/records.html
Normal file
@@ -0,0 +1,282 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||||
|
<title>计重记录 - 国际货运管理系统</title>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/tailwindcss.js"></script>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/iconify-icon.min.js"></script>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
}
|
||||||
|
.hide-scrollbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.hide-scrollbar {
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
.filter-modal {
|
||||||
|
transition: transform 0.3s ease-out;
|
||||||
|
transform: translateY(100%);
|
||||||
|
}
|
||||||
|
.filter-modal.show {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
.filter-overlay {
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.filter-overlay.show {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
.btn-active:active {
|
||||||
|
opacity: 0.7;
|
||||||
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="bg-gray-200 min-h-screen flex justify-center items-center p-4">
|
||||||
|
<!-- 手机容器 -->
|
||||||
|
<div class="w-[375px] h-[812px] bg-[#F3F4F6] overflow-hidden rounded-[40px] border-[8px] border-gray-800 shadow-2xl relative flex flex-col">
|
||||||
|
<!-- iOS 状态栏 -->
|
||||||
|
<div class="flex-none bg-[#2563EB] text-white h-11 px-6 flex justify-between items-center z-50">
|
||||||
|
<span class="text-sm font-semibold">09:10</span>
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-lg" icon="mdi:signal"></iconify-icon>
|
||||||
|
<iconify-icon class="text-lg" icon="mdi:wifi"></iconify-icon>
|
||||||
|
<iconify-icon class="text-lg rotate-90" icon="mdi:battery"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 导航栏 -->
|
||||||
|
<div class="flex-none bg-[#2563EB] h-12 flex items-center px-4 relative">
|
||||||
|
<button class="flex items-center text-white text-base btn-active" onclick="window.location.href='main.html'">
|
||||||
|
<iconify-icon class="text-2xl" icon="mdi:chevron-left"></iconify-icon>
|
||||||
|
<span>返回</span>
|
||||||
|
</button>
|
||||||
|
<h1 class="absolute left-1/2 -translate-x-1/2 text-white font-medium text-lg">计重记录</h1>
|
||||||
|
<!-- 导航栏地磅按钮已移除 -->
|
||||||
|
</div>
|
||||||
|
<!-- 内容滚动区域 -->
|
||||||
|
<div class="flex-1 overflow-y-auto hide-scrollbar pb-10">
|
||||||
|
<!-- 搜索栏 -->
|
||||||
|
<div class="h-[3px] bg-blue-500 mx-0"></div>
|
||||||
|
<section class="px-4 pt-4 pb-3">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 shadow-sm rounded-[12px] h-10 px-3 gap-2 flex-1">
|
||||||
|
<iconify-icon class="text-gray-400 text-lg flex-none" icon="mdi:magnify"></iconify-icon>
|
||||||
|
<input class="flex-1 bg-transparent text-[14px] text-gray-800 placeholder-gray-400 outline-none border-none rounded-lg px-2" placeholder="搜索运单号" type="text"/>
|
||||||
|
<button class="flex-none text-gray-500 btn-active">
|
||||||
|
<iconify-icon class="text-lg" icon="mdi:qrcode-scan"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button class="bg-white p-2.5 rounded-full shadow-sm border border-gray-200 text-[#2563EB] flex items-center justify-center flex-none btn-active" onclick="toggleFilterDrawer(true)">
|
||||||
|
<iconify-icon class="text-xl" icon="mdi:filter-variant"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- 统计标签 -->
|
||||||
|
<div class="px-4 mb-4">
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<!-- 总票数 -->
|
||||||
|
<div class="flex-1 bg-white p-3 rounded-lg border-l-4 border-blue-500 shadow-sm flex flex-col items-center">
|
||||||
|
<span class="text-[11px] text-gray-500 mb-1">总票数</span>
|
||||||
|
<span class="text-xl font-bold text-blue-600">3</span>
|
||||||
|
</div>
|
||||||
|
<!-- 总件数 -->
|
||||||
|
<div class="flex-1 bg-white p-3 rounded-lg border-l-4 border-orange-500 shadow-sm flex flex-col items-center">
|
||||||
|
<span class="text-[11px] text-gray-500 mb-1">总件数</span>
|
||||||
|
<span class="text-xl font-bold text-orange-600">1</span>
|
||||||
|
</div>
|
||||||
|
<!-- 总重量 -->
|
||||||
|
<div class="flex-1 bg-white p-3 rounded-lg border-l-4 border-green-500 shadow-sm flex flex-col items-center">
|
||||||
|
<span class="text-[11px] text-gray-500 mb-1">总重量</span>
|
||||||
|
<span class="text-xl font-bold text-green-600">2</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 记录列表 -->
|
||||||
|
<div class="px-4 flex flex-col gap-4">
|
||||||
|
<!-- 卡片1 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm p-4 mb-3 overflow-hidden">
|
||||||
|
<div class="flex justify-between items-start mb-3">
|
||||||
|
<span class="text-[15px] font-bold text-gray-800">78133363396</span>
|
||||||
|
<!-- 绿色地磅图标,跳转称重明细 -->
|
||||||
|
<button class="btn-active" onclick="window.location.href='weight-detail.html'">
|
||||||
|
<iconify-icon class="text-2xl text-gray-500" icon="mdi:weight"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2 text-gray-500 text-[13px] mb-3">
|
||||||
|
<iconify-icon inline icon="mdi:truck-outline" width="14" height="14"></iconify-icon>
|
||||||
|
<span>代理 : 马道</span>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-3 gap-2 bg-gray-50 p-3 rounded-md mb-3">
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<span class="text-[11px] text-gray-400">运抵件数</span>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="text-[14px] font-semibold text-gray-700">85件</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center border-x border-gray-200 px-2">
|
||||||
|
<span class="text-[11px] text-gray-400">运抵重量</span>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="text-[14px] font-semibold text-gray-700">1560kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<span class="text-[11px] text-gray-400">运抵体积</span>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="text-[14px] font-semibold text-gray-700">12.5m³</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2 text-gray-500 text-[13px] mb-3">
|
||||||
|
<iconify-icon inline icon="mdi:account-outline" width="16" height="16"></iconify-icon>
|
||||||
|
<span>计重人:张三 · 计重时间:2026-07-05 11:45</span>
|
||||||
|
</div>
|
||||||
|
<div class="mt-4 flex justify-end border-t border-gray-100 pt-3">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer btn-active" onclick="window.location.href='detail.html'">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片2 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm p-4 mb-3 overflow-hidden">
|
||||||
|
<div class="flex justify-between items-start mb-3">
|
||||||
|
<span class="text-[15px] font-bold text-gray-800">78133363398</span>
|
||||||
|
<!-- 绿色地磅图标 -->
|
||||||
|
<button class="btn-active" onclick="window.location.href='weight-detail.html'">
|
||||||
|
<iconify-icon class="text-2xl text-gray-500" icon="mdi:weight"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2 text-gray-500 text-[13px] mb-3">
|
||||||
|
<iconify-icon inline icon="mdi:truck-outline" width="14" height="14"></iconify-icon>
|
||||||
|
<span>代理 : 徽远</span>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-3 gap-2 bg-gray-50 p-3 rounded-md mb-3">
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<span class="text-[11px] text-gray-400">运抵件数</span>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="text-[14px] font-semibold text-gray-700">60件</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center border-x border-gray-200 px-2">
|
||||||
|
<span class="text-[11px] text-gray-400">运抵重量</span>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="text-[14px] font-semibold text-gray-700">920kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<span class="text-[11px] text-gray-400">运抵体积</span>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="text-[14px] font-semibold text-gray-700">8.1m³</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2 text-gray-500 text-[13px] mb-3">
|
||||||
|
<iconify-icon inline icon="mdi:account-outline" width="16" height="16"></iconify-icon>
|
||||||
|
<span>计重人:张三 · 计重时间:2026-07-05 11:45</span>
|
||||||
|
</div>
|
||||||
|
<div class="mt-4 flex justify-end border-t border-gray-100 pt-3">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer btn-active" onclick="window.location.href='detail.html'">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Toast 提示容器 -->
|
||||||
|
<div class="absolute left-1/2 -translate-x-1/2 bottom-20 bg-black/80 text-white text-[13px] px-4 py-2 rounded-full opacity-0 transition-opacity pointer-events-none z-[100]" id="toast"></div>
|
||||||
|
|
||||||
|
<!-- 筛选遮罩层 -->
|
||||||
|
<div class="filter-overlay absolute inset-0 bg-black/40 z-40" id="filterOverlay" onclick="toggleFilterDrawer(false)"></div>
|
||||||
|
|
||||||
|
<!-- 筛选弹窗 -->
|
||||||
|
<div class="filter-modal absolute bottom-0 left-0 right-0 bg-white rounded-t-3xl z-50 p-6 shadow-2xl" id="filter-panel">
|
||||||
|
<div class="relative flex items-center justify-center mb-6">
|
||||||
|
<h2 class="text-center text-[18px] font-bold text-gray-900">筛选条件</h2>
|
||||||
|
<button class="absolute right-0 top-0 text-gray-400 btn-active" onclick="toggleFilterDrawer(false)">
|
||||||
|
<iconify-icon class="text-2xl" icon="mdi:close"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">入库日期起</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择入库日期" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:calendar" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">入库日期止</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择入库日期" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:calendar" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">代理人</label>
|
||||||
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-3 flex items-center justify-between text-gray-400">
|
||||||
|
<span class="text-[14px]">全部</span>
|
||||||
|
<iconify-icon icon="mdi:chevron-down"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">特码</label>
|
||||||
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-3 flex items-center justify-between text-gray-400">
|
||||||
|
<span class="text-[14px]">全部</span>
|
||||||
|
<iconify-icon icon="mdi:chevron-down"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">目的站</label>
|
||||||
|
<input type="text" class="w-full bg-gray-50 border border-gray-200 rounded-lg px-3 py-3 text-[14px] outline-none" placeholder="请输入目的站">
|
||||||
|
</div>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">计重人</label>
|
||||||
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-3 flex items-center justify-between text-gray-400">
|
||||||
|
<span class="text-[14px]">全部</span>
|
||||||
|
<iconify-icon icon="mdi:chevron-down"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-4 pt-2">
|
||||||
|
<button class="flex-1 bg-white border border-gray-300 text-gray-600 py-3.5 rounded-xl font-bold btn-active" onclick="showToast('已重置筛选');toggleFilterDrawer(false)">
|
||||||
|
重置
|
||||||
|
</button>
|
||||||
|
<button class="flex-1 bg-[#2563EB] text-white py-3.5 rounded-xl font-bold shadow-lg btn-active" onclick="toggleFilterDrawer(false);showToast('已应用筛选')">
|
||||||
|
确认
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="h-8"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function showToast(message) {
|
||||||
|
const toast = document.getElementById('toast');
|
||||||
|
toast.textContent = message;
|
||||||
|
toast.classList.add('opacity-100');
|
||||||
|
setTimeout(() => {
|
||||||
|
toast.classList.remove('opacity-100');
|
||||||
|
}, 1500);
|
||||||
|
}
|
||||||
|
function toggleFilterDrawer(show) {
|
||||||
|
const overlay = document.getElementById('filterOverlay');
|
||||||
|
const modal = document.getElementById('filter-panel');
|
||||||
|
if (show) {
|
||||||
|
overlay.classList.add('show');
|
||||||
|
modal.classList.add('show');
|
||||||
|
} else {
|
||||||
|
overlay.classList.remove('show');
|
||||||
|
modal.classList.remove('show');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
256
documents/5.5寸手持端设计文件/03_出港计重/weighing.html
Normal file
256
documents/5.5寸手持端设计文件/03_出港计重/weighing.html
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
|
||||||
|
<title>开始计重 - 货运管理系统</title>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/tailwindcss.js"></script>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/iconify-icon.min.js"></script>
|
||||||
|
<style>
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
body {
|
||||||
|
background: #F3F4F6;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "PingFang SC", "Helvetica Neue", sans-serif;
|
||||||
|
}
|
||||||
|
/* 统一手机外壳容器 */
|
||||||
|
.phone-container {
|
||||||
|
width: 390px;
|
||||||
|
height: 844px;
|
||||||
|
background: #1a1a1a;
|
||||||
|
border-radius: 55px;
|
||||||
|
border: 8px solid #1F2937;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-shadow: 0 30px 60px rgba(0,0,0,0.3);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
/* 手机内部屏幕区域 */
|
||||||
|
.phone-screen {
|
||||||
|
flex: 1;
|
||||||
|
background: #F2F5F9;
|
||||||
|
margin: 0 4px 4px 4px;
|
||||||
|
border-radius: 46px;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.no-scrollbar::-webkit-scrollbar { display: none; }
|
||||||
|
.no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
|
||||||
|
@keyframes fadeInUp {
|
||||||
|
from { opacity: 0; transform: translateY(10px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
.card-animate {
|
||||||
|
animation: fadeInUp 0.35s ease forwards;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.card-animate:nth-child(1) { animation-delay: 0s; }
|
||||||
|
.card-animate:nth-child(2) { animation-delay: 0.05s; }
|
||||||
|
.card-animate:nth-child(3) { animation-delay: 0.1s; }
|
||||||
|
.card-animate:nth-child(4) { animation-delay: 0.15s; }
|
||||||
|
@keyframes slideUp {
|
||||||
|
from { transform: translateY(100%); }
|
||||||
|
to { transform: translateY(0); }
|
||||||
|
}
|
||||||
|
.animate-slideUp { animation: slideUp 0.3s ease-out; }
|
||||||
|
input { transition: all 0.2s ease; }
|
||||||
|
input:focus { transition: all 0.2s ease; }
|
||||||
|
::-webkit-scrollbar { display: none; }
|
||||||
|
* { -ms-overflow-style: none; scrollbar-width: none; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="phone-container">
|
||||||
|
<div class="phone-screen">
|
||||||
|
|
||||||
|
<!-- ===== ① 顶部连体蓝色区域(状态栏+导航栏) ===== -->
|
||||||
|
<div class="bg-[#2563EB] flex flex-col flex-none">
|
||||||
|
<!-- 手机状态栏 -->
|
||||||
|
<div class="flex items-center justify-between h-[28px] text-white text-[12px] px-6">
|
||||||
|
<span class="text-white font-medium tracking-wide">09:10</span>
|
||||||
|
<div class="flex items-center gap-[5px]">
|
||||||
|
<iconify-icon class="text-white text-[13px]" icon="mdi:signal-cellular-3"></iconify-icon>
|
||||||
|
<iconify-icon class="text-white text-[13px]" icon="mdi:wifi"></iconify-icon>
|
||||||
|
<iconify-icon class="text-white text-[15px]" icon="mdi:battery"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 导航栏 -->
|
||||||
|
<header class="text-white h-12 flex items-center px-4">
|
||||||
|
<button class="flex items-center gap-0.5 text-white font-medium text-[15px] active:opacity-70 transition-opacity" onclick="window.location.href='main.html'">
|
||||||
|
<iconify-icon class="text-white" height="24" icon="mdi:chevron-left" width="24"></iconify-icon>
|
||||||
|
<span>返回</span>
|
||||||
|
</button>
|
||||||
|
<h1 class="flex-1 text-center text-[17px] font-semibold">开始计重</h1>
|
||||||
|
<div class="w-[60px]"></div>
|
||||||
|
</header>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ===== ③ 主内容区(滚动) ===== -->
|
||||||
|
<main class="flex-1 overflow-y-auto no-scrollbar bg-[#F2F5F9] pb-4">
|
||||||
|
<!-- 顶部运单卡片(原样不动) -->
|
||||||
|
<div class="mx-4 mt-4 card-animate">
|
||||||
|
<div class="bg-white rounded-2xl shadow-md shadow-black/5 overflow-hidden relative">
|
||||||
|
<!-- 顶部渐变装饰条 -->
|
||||||
|
<div class="h-1" style="background: linear-gradient(90deg, #2563EB, #60A5FA, #2563EB);"></div>
|
||||||
|
<!-- 内容区 -->
|
||||||
|
<div class="px-5 py-4">
|
||||||
|
<!-- 第一行:运单号 + 状态徽标 -->
|
||||||
|
<div class="flex items-center justify-between mb-3">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-blue-500 animate-pulse"></div>
|
||||||
|
<span class="text-[20px] font-bold text-gray-900 tracking-wider">781333617</span>
|
||||||
|
</div>
|
||||||
|
<span class="text-[11px] font-medium text-blue-600 bg-blue-50 px-2.5 py-1 rounded-full border border-blue-100">国际出港</span>
|
||||||
|
</div>
|
||||||
|
<!-- 分割线 -->
|
||||||
|
<div class="border-t border-gray-50 mb-3"></div>
|
||||||
|
<!-- 统一信息区域:浅灰底圆角容器,包含预配 -->
|
||||||
|
<div class="bg-gray-50/70 rounded-xl px-4 py-3">
|
||||||
|
<!-- 预配信息三列 -->
|
||||||
|
<div class="grid grid-cols-3 gap-2">
|
||||||
|
<div class="text-center">
|
||||||
|
<p class="text-[10px] text-gray-400 mb-0.5">预配件数</p>
|
||||||
|
<p class="text-[15px] font-bold text-gray-800">85</p>
|
||||||
|
</div>
|
||||||
|
<div class="text-center">
|
||||||
|
<p class="text-[10px] text-gray-400 mb-0.5">预配重量</p>
|
||||||
|
<p class="text-[15px] font-bold text-gray-800">156 kg</p>
|
||||||
|
</div>
|
||||||
|
<div class="text-center">
|
||||||
|
<p class="text-[10px] text-gray-400 mb-0.5">预配体积</p>
|
||||||
|
<p class="text-[15px] font-bold text-gray-800">4.52 m³</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ===== 统一表单大卡片(字体样式统一为APP风格) ===== -->
|
||||||
|
<div class="mx-4 mt-3 bg-white rounded-2xl shadow-sm shadow-black/5 overflow-hidden card-animate">
|
||||||
|
<!-- 1. 通道号(必填)-->
|
||||||
|
<div class="flex items-center h-12 px-4 border-b border-gray-100 cursor-pointer active:bg-gray-50" onclick="openChannelPicker()">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">通道号<span class="text-red-500 ml-0.5">*</span></span>
|
||||||
|
<span class="flex-1 text-[14px] text-gray-500 text-left" id="channelDisplay">请选择通道号</span>
|
||||||
|
<iconify-icon class="text-gray-400 shrink-0" icon="mdi:chevron-right"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
<!-- 2. 代理人 -->
|
||||||
|
<div class="flex items-center h-12 px-4 border-b border-gray-100 cursor-pointer active:bg-gray-50" onclick="openAgentPicker()">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">代理人</span>
|
||||||
|
<span class="flex-1 text-[14px] text-gray-500 text-left" id="agentDisplay">请选择代理人</span>
|
||||||
|
<iconify-icon class="text-gray-400 shrink-0" icon="mdi:chevron-right"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
<!-- 3. 特码 -->
|
||||||
|
<div class="flex items-center h-12 px-4 border-b border-gray-100 cursor-pointer active:bg-gray-50" onclick="openCodePicker()">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">特码</span>
|
||||||
|
<span class="flex-1 text-[14px] text-gray-500 text-left" id="codeDisplay">请选择特码</span>
|
||||||
|
<iconify-icon class="text-gray-400 shrink-0" icon="mdi:chevron-right"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
<!-- 4. 运抵件数 -->
|
||||||
|
<div class="flex items-center h-12 px-4 border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">运抵件数</span>
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 bg-transparent border-none outline-none text-left" placeholder="请输入运抵件数" type="text"/>
|
||||||
|
</div>
|
||||||
|
<!-- 5. 运抵重量 -->
|
||||||
|
<div class="flex items-center h-12 px-4 border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">运抵重量</span>
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 bg-transparent border-none outline-none text-left" type="text" value="0"/>
|
||||||
|
</div>
|
||||||
|
<!-- 6. 运抵体积 -->
|
||||||
|
<div class="flex items-center h-12 px-4 border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">运抵体积</span>
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 bg-transparent border-none outline-none text-left" type="text" value="0.00"/>
|
||||||
|
</div>
|
||||||
|
<!-- 7. 托盘数量 -->
|
||||||
|
<div class="flex items-center h-12 px-4 border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">托盘数量</span>
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 bg-transparent border-none outline-none text-left" placeholder="请输入托盘数量" type="text"/>
|
||||||
|
</div>
|
||||||
|
<!-- 8. 托盘自重 -->
|
||||||
|
<div class="flex items-center h-12 px-4 border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">托盘自重</span>
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 bg-transparent border-none outline-none text-left" value="18" placeholder="请输入托盘自重" type="text"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 航班信息 -->
|
||||||
|
<div class="flex items-center h-12 px-4 border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">航班日期</span>
|
||||||
|
<span class="flex-1 text-[14px] text-gray-800 text-left">20260703</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center h-12 px-4 border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">航班号</span>
|
||||||
|
<span class="flex-1 text-[14px] text-gray-800 text-left">MU1111</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center h-12 px-4 border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">航程</span>
|
||||||
|
<span class="flex-1 text-[14px] text-gray-800 text-left">HFE-LAX</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 业务类型 -->
|
||||||
|
<div class="flex items-center h-12 px-4 border-b border-gray-100 cursor-pointer active:bg-gray-50" onclick="openBizPicker()">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">业务类型</span>
|
||||||
|
<span class="flex-1 text-[14px] text-gray-800 text-left" id="bizDisplay">普通货物运输</span>
|
||||||
|
<iconify-icon class="text-gray-400 shrink-0" icon="mdi:chevron-right"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 备注 -->
|
||||||
|
<div class="flex items-start h-auto min-h-[80px] px-4 py-3 border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0 pt-1">备注</span>
|
||||||
|
<textarea class="flex-1 text-[14px] text-gray-800 bg-transparent rounded-lg py-2 h-[60px] resize-none outline-none text-left" placeholder="请输入备注信息"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 底部按钮 -->
|
||||||
|
<div class="px-4 mt-4 mb-2">
|
||||||
|
<div class="flex gap-3">
|
||||||
|
<button class="flex-1 h-[52px] rounded-2xl text-[17px] font-semibold active:opacity-90 transition-all text-blue-600" style="background: #fff; border: 2px solid #2563EB;">
|
||||||
|
分托计重
|
||||||
|
</button>
|
||||||
|
<button class="flex-1 h-[52px] rounded-2xl bg-[#2563EB] text-white text-[17px] font-semibold active:opacity-90 shadow-lg shadow-blue-200 transition-all" onclick="submitWeight()">
|
||||||
|
完成计重
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<!-- iOS 底部指示条 -->
|
||||||
|
<div class="h-5 bg-[#F2F5F9] flex justify-center items-center flex-none">
|
||||||
|
<div class="w-[134px] h-[5px] bg-gray-300 rounded-full"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function openChannelPicker() {
|
||||||
|
const options = ['A-01', 'A-02', 'B-01', 'B-02', 'C-01'];
|
||||||
|
document.getElementById('channelDisplay').innerText = "A-01";
|
||||||
|
document.getElementById('channelDisplay').classList.remove('text-gray-500');
|
||||||
|
document.getElementById('channelDisplay').classList.add('text-gray-800');
|
||||||
|
}
|
||||||
|
|
||||||
|
function openAgentPicker() {
|
||||||
|
document.getElementById('agentDisplay').innerText = "上海中远海运物流";
|
||||||
|
document.getElementById('agentDisplay').classList.remove('text-gray-500');
|
||||||
|
document.getElementById('agentDisplay').classList.add('text-gray-800');
|
||||||
|
}
|
||||||
|
|
||||||
|
function openCodePicker() {
|
||||||
|
document.getElementById('codeDisplay').innerText = "GEN (普货)";
|
||||||
|
document.getElementById('codeDisplay').classList.remove('text-gray-500');
|
||||||
|
document.getElementById('codeDisplay').classList.add('text-gray-800');
|
||||||
|
}
|
||||||
|
|
||||||
|
function openBizPicker() {
|
||||||
|
}
|
||||||
|
|
||||||
|
function submitWeight() {
|
||||||
|
alert("提交成功");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
306
documents/5.5寸手持端设计文件/03_出港计重/weight-detail.html
Normal file
306
documents/5.5寸手持端设计文件/03_出港计重/weight-detail.html
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||||
|
<title>计重明细</title>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/tailwindcss.js"></script>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/iconify-icon.min.js"></script>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||||
|
background-color: #F3F4F6;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.safe-bottom {
|
||||||
|
padding-bottom: env(safe-area-inset-bottom);
|
||||||
|
}
|
||||||
|
.no-scrollbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.no-scrollbar {
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
.btn-active:active {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="bg-gray-200 min-h-screen flex items-center justify-center p-4">
|
||||||
|
<div class="relative w-[390px] h-[844px] bg-[#1a1a1a] rounded-[55px] shadow-2xl border-[6px] border-[#333] flex flex-col overflow-hidden">
|
||||||
|
<div class="flex-1 bg-white mt-0 mb-1 mx-1 rounded-[46px] overflow-hidden flex flex-col relative">
|
||||||
|
|
||||||
|
<!-- 状态栏 -->
|
||||||
|
<div class="bg-[#2563EB] text-white h-11 px-7 flex items-end pb-2 justify-between text-[14px] font-medium z-50">
|
||||||
|
<span>09:41</span>
|
||||||
|
<div class="flex items-center gap-1.5 pb-0.5">
|
||||||
|
<iconify-icon icon="mdi:signal-cellular-3"></iconify-icon>
|
||||||
|
<iconify-icon icon="mdi:wifi"></iconify-icon>
|
||||||
|
<iconify-icon icon="mdi:battery"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 列表页 -->
|
||||||
|
<div id="listPage" class="flex-1 flex flex-col overflow-hidden relative bg-gray-100">
|
||||||
|
<header class="relative bg-[#2563EB] text-white flex items-center h-12 px-3 sticky top-0 z-50">
|
||||||
|
<div class="flex items-center btn-active" onclick="window.location.href='records.html'">
|
||||||
|
<iconify-icon icon="mdi:chevron-left" width="28"></iconify-icon>
|
||||||
|
<span class="text-sm font-medium text-white -ml-1">返回</span>
|
||||||
|
</div>
|
||||||
|
<h1 class="absolute left-1/2 -translate-x-1/2 text-lg font-bold text-white">计重明细</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="flex-1 overflow-y-auto p-4 no-scrollbar">
|
||||||
|
<!-- 运单卡片(与 781333617 样式统一) -->
|
||||||
|
<div class="bg-white rounded-2xl shadow-md shadow-black/5 overflow-hidden relative mb-3">
|
||||||
|
<!-- 顶部渐变装饰条 -->
|
||||||
|
<div class="h-1" style="background: linear-gradient(90deg, #2563EB, #60A5FA, #2563EB);"></div>
|
||||||
|
<!-- 内容区 -->
|
||||||
|
<div class="px-5 py-4">
|
||||||
|
<!-- 第一行:运单号 + 状态徽标 -->
|
||||||
|
<div class="flex items-center justify-between mb-3">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-blue-500 animate-pulse"></div>
|
||||||
|
<span class="text-[20px] font-bold text-gray-900 tracking-wider">78133363396</span>
|
||||||
|
</div>
|
||||||
|
<span class="text-[11px] font-medium text-blue-600 bg-blue-50 px-2.5 py-1 rounded-full border border-blue-100">国际出港</span>
|
||||||
|
</div>
|
||||||
|
<!-- 分割线 -->
|
||||||
|
<div class="border-t border-gray-50 mb-3"></div>
|
||||||
|
<!-- 统一信息区域:浅灰底圆角容器 -->
|
||||||
|
<div class="bg-gray-50/70 rounded-xl px-4 py-3">
|
||||||
|
<div class="grid grid-cols-3 gap-2 text-center">
|
||||||
|
<div>
|
||||||
|
<p class="text-[10px] text-gray-400 mb-0.5">总件数</p>
|
||||||
|
<p class="text-[15px] font-bold text-gray-800">85</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-[10px] text-gray-400 mb-0.5">总重量(kg)</p>
|
||||||
|
<p class="text-[15px] font-bold text-gray-800">1560</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-[10px] text-gray-400 mb-0.5">托盘总重(kg)</p>
|
||||||
|
<p class="text-[15px] font-bold text-gray-800">54</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 左滑卡片1 -->
|
||||||
|
<div class="swipe-item bg-white rounded-xl shadow-sm mb-3 overflow-hidden relative" data-id="1">
|
||||||
|
<div class="swipe-content p-4 relative z-10 bg-white">
|
||||||
|
<div class="flex justify-between py-2">
|
||||||
|
<span class="text-gray-600">运抵件数</span>
|
||||||
|
<span class="font-medium piece">20</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between py-2">
|
||||||
|
<span class="text-gray-600">运抵重量(kg)</span>
|
||||||
|
<span class="font-medium weight">320</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between py-2">
|
||||||
|
<span class="text-gray-500">托盘自重(kg)</span>
|
||||||
|
<span class="text-gray-600">18</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between py-2">
|
||||||
|
<span class="text-gray-500">计重人</span>
|
||||||
|
<span class="text-gray-600 user">张三</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between py-2">
|
||||||
|
<span class="text-gray-500">计重时间</span>
|
||||||
|
<span class="text-gray-600 time">2026-07-05 10:02:15</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="swipe-action absolute top-0 right-0 bottom-0 w-[60px] bg-[#2563EB] flex items-center justify-center z-0">
|
||||||
|
<button class="text-white text-sm" onclick="goEdit(1)">修改</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 卡片2 -->
|
||||||
|
<div class="swipe-item bg-white rounded-xl shadow-sm mb-3 overflow-hidden relative" data-id="2">
|
||||||
|
<div class="swipe-content p-4 relative z-10 bg-white">
|
||||||
|
<div class="flex justify-between py-2">
|
||||||
|
<span class="text-gray-600">运抵件数</span>
|
||||||
|
<span class="font-medium piece">35</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between py-2">
|
||||||
|
<span class="text-gray-600">运抵重量(kg)</span>
|
||||||
|
<span class="font-medium weight">590</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between py-2">
|
||||||
|
<span class="text-gray-500">托盘自重(kg)</span>
|
||||||
|
<span class="text-gray-600">18</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between py-2">
|
||||||
|
<span class="text-gray-500">计重人</span>
|
||||||
|
<span class="text-gray-600 user">张三</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between py-2">
|
||||||
|
<span class="text-gray-500">计重时间</span>
|
||||||
|
<span class="text-gray-600 time">2026-07-05 10:25:30</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="swipe-action absolute top-0 right-0 bottom-0 w-[60px] bg-[#2563EB] flex items-center justify-center z-0">
|
||||||
|
<button class="text-white text-sm" onclick="goEdit(2)">修改</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 卡片3 -->
|
||||||
|
<div class="swipe-item bg-white rounded-xl shadow-sm mb-3 overflow-hidden relative" data-id="3">
|
||||||
|
<div class="swipe-content p-4 relative z-10 bg-white">
|
||||||
|
<div class="flex justify-between py-2">
|
||||||
|
<span class="text-gray-600">运抵件数</span>
|
||||||
|
<span class="font-medium piece">30</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between py-2">
|
||||||
|
<span class="text-gray-600">运抵重量(kg)</span>
|
||||||
|
<span class="font-medium weight">650</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between py-2">
|
||||||
|
<span class="text-gray-500">托盘自重(kg)</span>
|
||||||
|
<span class="text-gray-600">18</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between py-2">
|
||||||
|
<span class="text-gray-500">计重人</span>
|
||||||
|
<span class="text-gray-600 user">张三</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between py-2">
|
||||||
|
<span class="text-gray-500">计重时间</span>
|
||||||
|
<span class="text-gray-600 time">2026-07-05 11:45:08</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="swipe-action absolute top-0 right-0 bottom-0 w-[60px] bg-[#2563EB] flex items-center justify-center z-0">
|
||||||
|
<button class="text-white text-sm" onclick="goEdit(3)">修改</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 修改记录页面(完全在手机容器内) -->
|
||||||
|
<div id="editPage" class="absolute inset-0 bg-gray-100 z-[60] flex flex-col hidden">
|
||||||
|
<div class="bg-[#2563EB] text-white h-11 px-7 flex items-end pb-2 justify-between text-[14px] font-medium z-50 flex-none">
|
||||||
|
<span>09:41</span>
|
||||||
|
<div class="flex items-center gap-1.5 pb-0.5">
|
||||||
|
<iconify-icon icon="mdi:signal-cellular-3"></iconify-icon>
|
||||||
|
<iconify-icon icon="mdi:wifi"></iconify-icon>
|
||||||
|
<iconify-icon icon="mdi:battery"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<header class="relative bg-[#2563EB] text-white flex items-center h-12 px-3 flex-none">
|
||||||
|
<div class="flex items-center btn-active" onclick="closeEditPage()">
|
||||||
|
<iconify-icon icon="mdi:chevron-left" width="28"></iconify-icon>
|
||||||
|
<span class="text-sm font-medium text-white -ml-1">返回</span>
|
||||||
|
</div>
|
||||||
|
<h1 class="absolute left-1/2 -translate-x-1/2 text-lg font-bold text-white">修改记录</h1>
|
||||||
|
</header>
|
||||||
|
<div class="flex-1 overflow-y-auto p-4 no-scrollbar">
|
||||||
|
<div class="bg-white rounded-xl shadow-sm overflow-hidden px-4">
|
||||||
|
<div class="flex items-center py-[14px] border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">运抵件数<span class="text-red-500 ml-0.5">*</span></span>
|
||||||
|
<input id="edit_piece" class="flex-1 bg-transparent outline-none text-gray-800 text-[14px]">
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center py-[14px] border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">运抵重量(kg)<span class="text-red-500 ml-0.5">*</span></span>
|
||||||
|
<input id="edit_weight" class="flex-1 bg-transparent outline-none text-gray-800 text-[14px]">
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center py-[14px] border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">托盘自重(kg)<span class="text-red-500 ml-0.5">*</span></span>
|
||||||
|
<input value="18" class="flex-1 bg-transparent outline-none text-gray-800 text-[14px]">
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center py-[14px] border-b border-gray-100">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">计重人</span>
|
||||||
|
<input id="edit_user" disabled class="flex-1 bg-transparent outline-none text-gray-500 text-[14px]">
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center py-[14px]">
|
||||||
|
<span class="w-[90px] text-[13px] font-medium text-[#6B7280] shrink-0">计重时间</span>
|
||||||
|
<input id="edit_time" disabled class="flex-1 bg-transparent outline-none text-gray-500 text-[14px]">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="w-full mt-8 bg-[#2563EB] text-white py-3.5 rounded-[10px] font-bold text-[16px] shadow-lg shadow-blue-500/30 btn-active" onclick="saveEdit()">保存</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let currentEditId = null
|
||||||
|
|
||||||
|
// 左滑效果(鼠标+触摸)
|
||||||
|
document.querySelectorAll('.swipe-item').forEach(item => {
|
||||||
|
const content = item.querySelector('.swipe-content')
|
||||||
|
let startX = 0
|
||||||
|
let isDragging = false
|
||||||
|
|
||||||
|
item.addEventListener('mousedown', e => {
|
||||||
|
isDragging = true
|
||||||
|
startX = e.clientX
|
||||||
|
e.preventDefault()
|
||||||
|
})
|
||||||
|
|
||||||
|
window.addEventListener('mousemove', e => {
|
||||||
|
if (!isDragging) return
|
||||||
|
const dx = startX - e.clientX
|
||||||
|
if (dx > 0) {
|
||||||
|
const off = Math.min(dx, 60)
|
||||||
|
content.style.transform = `translateX(-${off}px)`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
window.addEventListener('mouseup', () => {
|
||||||
|
if (!isDragging) return
|
||||||
|
isDragging = false
|
||||||
|
const dx = startX - event.clientX
|
||||||
|
if (dx > 30) {
|
||||||
|
content.style.transform = 'translateX(-60px)'
|
||||||
|
} else {
|
||||||
|
content.style.transform = ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
item.addEventListener('touchstart', e => {
|
||||||
|
startX = e.touches[0].clientX
|
||||||
|
})
|
||||||
|
|
||||||
|
item.addEventListener('touchmove', e => {
|
||||||
|
const dx = startX - e.touches[0].clientX
|
||||||
|
if (dx > 0) {
|
||||||
|
const off = Math.min(dx, 60)
|
||||||
|
content.style.transform = `translateX(-${off}px)`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
item.addEventListener('touchend', () => {
|
||||||
|
const dx = startX - event.changedTouches[0].clientX
|
||||||
|
content.style.transform = dx > 30 ? 'translateX(-60px)' : ''
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
function goEdit(id) {
|
||||||
|
currentEditId = id
|
||||||
|
const item = document.querySelector(`.swipe-item[data-id="${id}"]`)
|
||||||
|
document.getElementById('edit_piece').value = item.querySelector('.piece').innerText
|
||||||
|
document.getElementById('edit_weight').value = item.querySelector('.weight').innerText
|
||||||
|
document.getElementById('edit_user').value = item.querySelector('.user').innerText
|
||||||
|
document.getElementById('edit_time').value = item.querySelector('.time').innerText
|
||||||
|
document.getElementById('listPage').classList.add('hidden')
|
||||||
|
document.getElementById('editPage').classList.remove('hidden')
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeEditPage() {
|
||||||
|
document.getElementById('editPage').classList.add('hidden')
|
||||||
|
document.getElementById('listPage').classList.remove('hidden')
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveEdit() {
|
||||||
|
const p = document.getElementById('edit_piece').value
|
||||||
|
const w = document.getElementById('edit_weight').value
|
||||||
|
const item = document.querySelector(`.swipe-item[data-id="${currentEditId}"]`)
|
||||||
|
item.querySelector('.piece').innerText = p
|
||||||
|
item.querySelector('.weight').innerText = w
|
||||||
|
closeEditPage()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
535
documents/5.5寸手持端设计文件/04_出港运抵/main.html
Normal file
535
documents/5.5寸手持端设计文件/04_出港运抵/main.html
Normal file
@@ -0,0 +1,535 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||||
|
<title>出港运抵</title>
|
||||||
|
<!-- Tailwind CSS -->
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<!-- Iconify -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/iconify-icon@2.1.0/dist/iconify-icon.min.js"></script>
|
||||||
|
<style>
|
||||||
|
.no-scrollbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background-color: #f3f6f8;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from { opacity: 0; transform: translate(-50%, 10px); }
|
||||||
|
to { opacity: 1; transform: translate(-50%, 0); }
|
||||||
|
}
|
||||||
|
.animate-fadeIn {
|
||||||
|
animation: fadeIn 0.3s ease-out;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="bg-gray-100">
|
||||||
|
<div class="phone-shell w-[375px] h-[812px] bg-[#F5F5F7] overflow-hidden flex flex-col relative rounded-[48px] border-[10px] border-gray-900">
|
||||||
|
<div class="bg-[#2563EB] flex-none">
|
||||||
|
<div class="h-[44px] flex justify-between items-center px-8 text-white">
|
||||||
|
<span class="text-[15px] font-semibold">09:41</span>
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-lg" icon="mdi:signal-cellular-3"></iconify-icon>
|
||||||
|
<iconify-icon class="text-lg" icon="mdi:wifi"></iconify-icon>
|
||||||
|
<iconify-icon class="text-xl" icon="mdi:battery"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="h-[44px] flex items-center px-4 relative">
|
||||||
|
<div class="flex items-center text-white cursor-pointer" onclick="window.history.back()">
|
||||||
|
<iconify-icon class="text-2xl" icon="mdi:chevron-left"></iconify-icon>
|
||||||
|
<span class="text-sm">返回</span>
|
||||||
|
</div>
|
||||||
|
<div class="absolute inset-0 flex items-center justify-center pointer-events-none">
|
||||||
|
<h1 class="text-white text-lg font-bold">出港运抵</h1>
|
||||||
|
</div>
|
||||||
|
<div class="ml-auto w-10"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1 overflow-y-auto no-scrollbar">
|
||||||
|
<section class="px-4 pt-4 pb-3 bg-white">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 shadow-sm rounded-[12px] h-10 px-3 gap-2 flex-1">
|
||||||
|
<iconify-icon class="text-gray-400 text-lg flex-none" icon="mdi:magnify"></iconify-icon>
|
||||||
|
<input class="flex-1 bg-transparent text-[14px] text-gray-800 placeholder-gray-400 outline-none border-none rounded-lg px-2" placeholder="搜索运单号" type="text"/>
|
||||||
|
<button class="flex-none text-blue-500">
|
||||||
|
<iconify-icon class="text-lg" icon="mdi:qrcode-scan"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button class="bg-white p-2.5 rounded-full shadow-sm border border-gray-200 text-[#2563EB] flex items-center justify-center flex-none" onclick="showFilterSheet2()">
|
||||||
|
<iconify-icon class="text-lg" icon="mdi:filter-variant"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="flex bg-white border-b sticky top-0 z-20">
|
||||||
|
<button class="tab-btn flex-1 py-3 text-sm font-bold border-b-2 transition-all text-[#1F2937] border-[#1F2937]" id="tab-pending" onclick="switchTab('pending')">
|
||||||
|
待运抵 <span class="bg-[#DBEAF6] text-[#2563EB] text-[11px] font-medium px-1.5 py-0.5 rounded-md ml-1.5" id="count-pending">1</span>
|
||||||
|
</button>
|
||||||
|
<button class="tab-btn flex-1 py-3 text-sm font-bold border-b-2 transition-all text-gray-400 border-transparent" id="tab-shipped" onclick="switchTab('shipped')">
|
||||||
|
已运抵 <span class="bg-[#DBEAF6] text-[#2563EB] text-[11px] font-medium px-1.5 py-0.5 rounded-md ml-1.5" id="count-shipped">4</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="px-5 pb-5 pt-3">
|
||||||
|
<div class="flex flex-col items-center justify-center py-16 text-gray-400 hidden" id="empty-pending">
|
||||||
|
<svg class="w-16 h-16 text-gray-300 mb-4" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24">
|
||||||
|
<path d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||||
|
</svg>
|
||||||
|
<p class="text-sm">暂无待运抵的运单</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 待运抵卡片(长按显示补充按钮) -->
|
||||||
|
<div class="bg-white rounded-2xl p-5 shadow-sm border border-gray-100/50 mb-4 uld-card relative" data-status="pending">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="radio-btn border-2 border-gray-300 rounded-full w-5 h-5 inline-flex items-center justify-center flex-none cursor-pointer"></span>
|
||||||
|
<div class="flex items-baseline">
|
||||||
|
<span class="text-sm font-bold text-gray-900">78133363396</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="bg-red-500 text-white text-[11px] font-medium px-2.5 py-0.5 rounded-full">提前运抵</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-y-2 text-gray-500 text-[13px] mt-3">
|
||||||
|
<div><span>代理:</span><span>马道</span></div>
|
||||||
|
<div><span>件数:</span><span>444</span></div>
|
||||||
|
<div><span>重量:</span><span>150kg</span></div>
|
||||||
|
<div><span>航班日期:</span><span>20260713</span></div>
|
||||||
|
<div><span>航班号:</span><span>MU2033</span></div>
|
||||||
|
<div><span>航程:</span><span>HFE-LAX</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2">
|
||||||
|
<button class="w-full bg-[#EFF6FF] text-[#2563EB] text-xs py-2 rounded-[6px] font-medium h-8 flex items-center justify-center gap-2" onclick="event.stopPropagation(); window.location.href='suborder.html'">
|
||||||
|
查看分单
|
||||||
|
<span class="text-[#2563EB] text-[10px] font-bold">3</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- 长按弹出操作层 -->
|
||||||
|
<div class="card-action-overlay absolute inset-0 bg-black/40 rounded-2xl z-10 hidden flex items-center justify-center pointer-events-none">
|
||||||
|
<div class="flex items-center gap-4 pointer-events-auto shipped-actions hidden">
|
||||||
|
<button class="bg-amber-500 text-white text-[10px] font-bold w-14 h-14 rounded-full shadow-lg shadow-amber-500/30 flex items-center justify-center leading-tight" onclick="event.stopPropagation(); this.closest('.card-action-overlay').classList.add('hidden'); setTimeout(() => showResetStatusSheet(), 200)">重置</button>
|
||||||
|
<button class="bg-emerald-500 text-white text-[10px] font-bold w-14 h-14 rounded-full shadow-lg shadow-emerald-500/30 flex items-center justify-center leading-tight" onclick="event.stopPropagation(); window.location.href='receipt.html'">回执</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 已运抵卡片1 -->
|
||||||
|
<div class="bg-white rounded-2xl p-5 shadow-sm border border-gray-100/50 mb-4 uld-card relative" data-status="shipped" style="display: none;">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="text-sm font-bold text-gray-900">78133363397</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="bg-indigo-100 text-indigo-500 text-[11px] font-medium px-2.5 py-0.5 rounded-full">W</span>
|
||||||
|
<span class="bg-green-100 text-green-600 text-[11px] font-medium px-2 py-0.5 rounded-md">11</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-y-2 text-gray-500 text-[13px] mt-3">
|
||||||
|
<div><span>代理:</span><span>徽远</span></div>
|
||||||
|
<div><span>件数:</span><span>300</span></div>
|
||||||
|
<div><span>重量:</span><span>120kg</span></div>
|
||||||
|
<div><span>航班日期:</span><span>20260713</span></div>
|
||||||
|
<div><span>航班号:</span><span>MU2033</span></div>
|
||||||
|
<div><span>航程:</span><span>HFE-LAX</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2">
|
||||||
|
<button class="w-full bg-[#EFF6FF] text-[#2563EB] text-xs py-2 rounded-[6px] font-medium h-8 flex items-center justify-center gap-2" onclick="event.stopPropagation(); window.location.href='suborder.html'">
|
||||||
|
查看分单
|
||||||
|
<span class="text-[#2563EB] text-[10px] font-bold">2</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="card-action-overlay absolute inset-0 bg-black/40 rounded-2xl z-10 hidden flex items-center justify-center pointer-events-none">
|
||||||
|
<div class="flex items-center gap-4 pointer-events-auto pending-actions hidden">
|
||||||
|
<button class="bg-purple-500 text-white text-[10px] font-bold w-14 h-14 rounded-full shadow-lg shadow-purple-500/30 flex items-center justify-center leading-tight" onclick="event.stopPropagation(); this.closest('.card-action-overlay').classList.add('hidden'); window.location.href='supplement.html'">补充</button>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-4 pointer-events-auto shipped-actions hidden">
|
||||||
|
<button class="bg-amber-500 text-white text-[10px] font-bold w-14 h-14 rounded-full shadow-lg shadow-amber-500/30 flex items-center justify-center leading-tight" onclick="event.stopPropagation(); this.closest('.card-action-overlay').classList.add('hidden'); setTimeout(() => showResetStatusSheet(), 200)">重置</button>
|
||||||
|
<button class="bg-emerald-500 text-white text-[10px] font-bold w-14 h-14 rounded-full shadow-lg shadow-emerald-500/30 flex items-center justify-center leading-tight" onclick="event.stopPropagation(); window.location.href='receipt.html'">回执</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 已运抵卡片2 -->
|
||||||
|
<div class="bg-white rounded-2xl p-5 shadow-sm border border-gray-100/50 mb-4 uld-card relative" data-status="shipped" style="display: none;">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="text-sm font-bold text-gray-900">78133363398</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="bg-green-100 text-green-600 text-[11px] font-medium px-2.5 py-0.5 rounded-full">01</span>
|
||||||
|
<span class="bg-green-100 text-green-600 text-[11px] font-medium px-2 py-0.5 rounded-md">11</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-y-2 text-gray-500 text-[13px] mt-3">
|
||||||
|
<div><span>代理:</span><span>中外运</span></div>
|
||||||
|
<div><span>件数:</span><span>130</span></div>
|
||||||
|
<div><span>重量:</span><span>130kg</span></div>
|
||||||
|
<div><span>航班日期:</span><span>20260713</span></div>
|
||||||
|
<div><span>航班号:</span><span>MU2033</span></div>
|
||||||
|
<div><span>航程:</span><span>HFE-LAX</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2">
|
||||||
|
<button class="w-full bg-[#EFF6FF] text-[#2563EB] text-xs py-2 rounded-[6px] font-medium h-8 flex items-center justify-center gap-2" onclick="event.stopPropagation(); window.location.href='suborder.html'">
|
||||||
|
查看分单
|
||||||
|
<span class="text-[#2563EB] text-[10px] font-bold">2</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="card-action-overlay absolute inset-0 bg-black/40 rounded-2xl z-10 hidden flex items-center justify-center pointer-events-none">
|
||||||
|
<div class="flex items-center gap-4 pointer-events-auto pending-actions hidden">
|
||||||
|
<button class="bg-purple-500 text-white text-[10px] font-bold w-14 h-14 rounded-full shadow-lg shadow-purple-500/30 flex items-center justify-center leading-tight" onclick="event.stopPropagation(); this.closest('.card-action-overlay').classList.add('hidden'); window.location.href='supplement.html'">补充</button>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-4 pointer-events-auto shipped-actions hidden">
|
||||||
|
<button class="bg-amber-500 text-white text-[10px] font-bold w-14 h-14 rounded-full shadow-lg shadow-amber-500/30 flex items-center justify-center leading-tight" onclick="event.stopPropagation(); this.closest('.card-action-overlay').classList.add('hidden'); setTimeout(() => showResetStatusSheet(), 200)">重置</button>
|
||||||
|
<button class="bg-emerald-500 text-white text-[10px] font-bold w-14 h-14 rounded-full shadow-lg shadow-emerald-500/30 flex items-center justify-center leading-tight" onclick="event.stopPropagation(); window.location.href='receipt.html'">回执</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 已运抵卡片3:78133363399 -->
|
||||||
|
<div class="bg-white rounded-2xl p-5 shadow-sm border border-gray-100/50 mb-4 uld-card relative" data-status="shipped" style="display: none;">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="text-sm font-bold text-gray-900">78133363399</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="bg-amber-100 text-amber-600 text-[11px] font-medium px-2.5 py-0.5 rounded-full">E</span>
|
||||||
|
<span class="bg-green-100 text-green-600 text-[11px] font-medium px-2 py-0.5 rounded-md">11</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-y-2 text-gray-500 text-[13px] mt-3">
|
||||||
|
<div><span>代理:</span><span>MU</span></div>
|
||||||
|
<div><span>件数:</span><span>300</span></div>
|
||||||
|
<div><span>重量:</span><span>110kg</span></div>
|
||||||
|
<div><span>航班日期:</span><span>20260713</span></div>
|
||||||
|
<div><span>航班号:</span><span>MU2034</span></div>
|
||||||
|
<div><span>航程:</span><span>HFE-LAX</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2">
|
||||||
|
<button class="w-full bg-[#EFF6FF] text-[#2563EB] text-xs py-2 rounded-[6px] font-medium h-8 flex items-center justify-center gap-2" onclick="event.stopPropagation(); window.location.href='https://modao.cc/agent-py/workspace/6a50a1993333bc5bbd8ee054/waybill-arrival.html/suborder.html?render_html=true'">
|
||||||
|
查看分单
|
||||||
|
<span class="text-[#2563EB] text-[10px] font-bold">1</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片操作菜单(默认隐藏) -->
|
||||||
|
<div class="card-action-overlay absolute inset-0 bg-black/40 rounded-2xl z-10 hidden flex items-center justify-center pointer-events-none">
|
||||||
|
<!-- 已运抵按钮容器(显示重置+回执) -->
|
||||||
|
<div class="flex items-center gap-4 pointer-events-auto shipped-actions hidden">
|
||||||
|
<button class="bg-amber-500 text-white text-[10px] font-bold w-14 h-14 rounded-full shadow-lg shadow-amber-500/30 flex items-center justify-center leading-tight" onclick="event.stopPropagation(); this.closest('.card-action-overlay').classList.add('hidden'); setTimeout(() => showResetStatusSheet(), 200)">
|
||||||
|
重置
|
||||||
|
</button>
|
||||||
|
<button class="bg-emerald-500 text-white text-[10px] font-bold w-14 h-14 rounded-full shadow-lg shadow-emerald-500/30 flex items-center justify-center leading-tight" onclick="event.stopPropagation(); window.location.href='https://modao.cc/agent-py/workspace/6a50a1993333bc5bbd8ee054/waybill-arrival.html/receipt.html?render_html=true'">
|
||||||
|
回执
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 底部操作栏 -->
|
||||||
|
<div class="flex-none bg-white border-t border-gray-100" id="bottom-action-bar">
|
||||||
|
<div class="flex items-center justify-between px-5 py-3">
|
||||||
|
<div class="flex items-center gap-2 select-all cursor-pointer">
|
||||||
|
<span class="radio-select-all w-5 h-5 rounded-full border-2 border-gray-300 bg-white flex items-center justify-center"></span>
|
||||||
|
<span class="text-sm text-gray-700 font-medium">全选</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3 bottom-action-container">
|
||||||
|
<span class="text-[12px] text-[#9CA3AF]">已选 <span id="selected-count">0</span> 项</span>
|
||||||
|
<button class="bg-[#2563EB] text-white text-[15px] font-bold px-5 py-2 rounded-[10px] shadow-lg shadow-blue-500/25" onclick="alert('运抵申报')">申报</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pb-2 flex justify-center">
|
||||||
|
<div class="w-32 h-1.5 bg-gray-200 rounded-full"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 筛选弹窗 -->
|
||||||
|
<div class="absolute inset-0 bg-black/40 z-50 hidden" id="filter-sheet2-overlay" onclick="hideFilterSheet2()"></div>
|
||||||
|
<div class="absolute bottom-0 left-0 right-0 bg-white rounded-t-2xl shadow-2xl z-50 transform translate-y-full transition-transform duration-300 ease-in-out" id="filter-sheet2">
|
||||||
|
<div class="px-5 pt-5 pb-8">
|
||||||
|
<div class="flex items-center justify-center mb-6 relative">
|
||||||
|
<h3 class="text-base font-bold text-gray-900">筛选条件</h3>
|
||||||
|
<button class="absolute right-0 w-8 h-8 rounded-full bg-gray-100 flex items-center justify-center" onclick="hideFilterSheet2()">
|
||||||
|
<svg class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24">
|
||||||
|
<line x1="18" x2="6" y1="6" y2="18"></line>
|
||||||
|
<line x1="6" x2="18" y1="6" y2="18"></line>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label class="text-sm text-gray-500 font-medium mb-1.5 block">航班日期</label>
|
||||||
|
<div class="flex items-center bg-gray-50 border border-gray-200 rounded-xl h-10 px-3">
|
||||||
|
<iconify-icon class="text-gray-400 text-lg flex-none" icon="mdi:calendar"></iconify-icon>
|
||||||
|
<input class="flex-1 bg-transparent text-[14px] text-gray-800 placeholder-gray-400 outline-none border-none px-2" placeholder="选择日期" type="text" value="2026-07-10"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="text-sm text-gray-500 font-medium mb-1.5 block">航班号</label>
|
||||||
|
<div class="flex items-center bg-gray-50 border border-gray-200 rounded-xl h-10 px-3">
|
||||||
|
<input class="flex-1 bg-transparent text-[14px] text-gray-800 placeholder-gray-400 outline-none border-none" placeholder="请输入航班号" type="text"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="text-sm text-gray-500 font-medium mb-1.5 block">代理</label>
|
||||||
|
<select class="w-full bg-gray-50 border border-gray-200 rounded-xl h-10 px-3 text-[14px] text-gray-800 outline-none appearance-none bg-[url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2212%22%20height%3D%2212%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22%239CA3AF%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpolyline%20points%3D%226%209%2012%2015%2018%209%22%3E%3C%2Fpolyline%3E%3C%2Fsvg%3E')] bg-[length:14px] bg-[right_12px_center] bg-no-repeat">
|
||||||
|
<option disabled selected value="">请选择代理</option>
|
||||||
|
<option value="马道">马道</option>
|
||||||
|
<option value="徽远">徽远</option>
|
||||||
|
<option value="中外运">中外运</option>
|
||||||
|
<option value="MU">MU</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-3 mt-6">
|
||||||
|
<button class="flex-1 py-3 text-sm font-medium text-gray-500 bg-gray-100 rounded-xl" onclick="hideFilterSheet2()">重置</button>
|
||||||
|
<button class="flex-1 py-3 text-sm font-medium text-white bg-[#2563EB] rounded-xl" onclick="hideFilterSheet2()">确定</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 重置状态弹窗 -->
|
||||||
|
<div class="absolute inset-0 bg-black/40 z-50 hidden" id="reset-sheet-overlay" onclick="hideResetStatusSheet()"></div>
|
||||||
|
<div class="absolute bottom-0 left-0 right-0 bg-white rounded-t-2xl shadow-2xl z-50 transform translate-y-full transition-transform duration-300 ease-in-out" id="reset-sheet">
|
||||||
|
<div class="px-5 pt-5 pb-8">
|
||||||
|
<div class="flex items-center justify-center mb-6 relative">
|
||||||
|
<h3 class="text-base font-bold text-gray-900">重置状态</h3>
|
||||||
|
<button class="absolute right-0 w-8 h-8 rounded-full bg-gray-100 flex items-center justify-center" onclick="hideResetStatusSheet()">
|
||||||
|
<svg class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24">
|
||||||
|
<line x1="18" x2="6" y1="6" y2="18"></line>
|
||||||
|
<line x1="6" x2="18" y1="6" y2="18"></line>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="text-sm text-gray-500 font-medium mb-1.5 block">状态</label>
|
||||||
|
<select class="w-full bg-gray-50 border border-gray-200 rounded-xl h-10 px-3 text-[14px] text-gray-800 outline-none appearance-none bg-[url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2212%22%20height%3D%2212%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22%239CA3AF%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpolyline%20points%3D%226%209%2012%2015%2018%209%22%3E%3C%2Fpolyline%3E%3C%2Fsvg%3E')] bg-[length:14px] bg-[right_12px_center] bg-no-repeat" id="reset-status-select">
|
||||||
|
<option disabled selected value="">请选择状态</option>
|
||||||
|
<option value="">空</option>
|
||||||
|
<option value="01">01</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<button class="w-full mt-6 py-3 text-sm font-medium text-white bg-[#2563EB] rounded-xl" onclick="confirmResetStatus()">确定</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let currentTab = 'pending';
|
||||||
|
let longPressTimer = null;
|
||||||
|
let isLongPress = false;
|
||||||
|
|
||||||
|
// Toast提示
|
||||||
|
function showToast(message) {
|
||||||
|
const existingToast = document.querySelector('.custom-toast');
|
||||||
|
if (existingToast) existingToast.remove();
|
||||||
|
const toast = document.createElement('div');
|
||||||
|
toast.className = 'custom-toast fixed bottom-32 left-1/2 -translate-x-1/2 bg-gray-800 text-white text-sm px-5 py-3 rounded-xl shadow-lg z-50 animate-fadeIn';
|
||||||
|
toast.textContent = message;
|
||||||
|
document.body.appendChild(toast);
|
||||||
|
setTimeout(() => {
|
||||||
|
toast.style.opacity = '0';
|
||||||
|
toast.style.transition = 'opacity 0.3s';
|
||||||
|
setTimeout(() => toast.remove(), 300);
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空所有选中
|
||||||
|
function resetAllSelections() {
|
||||||
|
document.querySelectorAll('.radio-btn').forEach(radio => toggleRadio(radio, false));
|
||||||
|
const selectAllRadio = document.querySelector('.radio-select-all');
|
||||||
|
toggleRadio(selectAllRadio, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换标签页
|
||||||
|
function switchTab(tab) {
|
||||||
|
currentTab = tab;
|
||||||
|
const tabPending = document.getElementById('tab-pending');
|
||||||
|
const tabShipped = document.getElementById('tab-shipped');
|
||||||
|
const bottomBar = document.getElementById('bottom-action-bar');
|
||||||
|
const emptyTip = document.getElementById('empty-pending');
|
||||||
|
|
||||||
|
// 切换tab样式
|
||||||
|
if (tab === 'pending') {
|
||||||
|
tabPending.classList.remove('text-gray-400', 'border-transparent');
|
||||||
|
tabPending.classList.add('text-[#1F2937]', 'border-[#1F2937]');
|
||||||
|
tabShipped.classList.remove('text-[#1F2937]', 'border-[#1F2937]');
|
||||||
|
tabShipped.classList.add('text-gray-400', 'border-transparent');
|
||||||
|
bottomBar.classList.remove('hidden');
|
||||||
|
} else {
|
||||||
|
tabPending.classList.remove('text-[#1F2937]', 'border-[#1F2937]');
|
||||||
|
tabPending.classList.add('text-gray-400', 'border-transparent');
|
||||||
|
tabShipped.classList.remove('text-gray-400', 'border-transparent');
|
||||||
|
tabShipped.classList.add('text-[#1F2937]', 'border-[#1F2937]');
|
||||||
|
bottomBar.classList.add('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换卡片显示
|
||||||
|
const allCards = document.querySelectorAll('.uld-card');
|
||||||
|
let showCount = 0;
|
||||||
|
allCards.forEach(card => {
|
||||||
|
if (card.dataset.status === tab) {
|
||||||
|
card.style.display = 'block';
|
||||||
|
showCount++;
|
||||||
|
} else {
|
||||||
|
card.style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
emptyTip.classList.toggle('hidden', showCount > 0);
|
||||||
|
resetAllSelections();
|
||||||
|
updateSelectCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新选中数量
|
||||||
|
function updateSelectCount() {
|
||||||
|
const list = document.querySelectorAll(`.uld-card[data-status="${currentTab}"] .radio-btn.bg-blue-500`);
|
||||||
|
document.getElementById('selected-count').textContent = list.length;
|
||||||
|
syncSelectAllStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同步全选按钮样式
|
||||||
|
function syncSelectAllStatus() {
|
||||||
|
const allCards = document.querySelectorAll(`.uld-card[data-status="${currentTab}"]`);
|
||||||
|
const selectedCards = document.querySelectorAll(`.uld-card[data-status="${currentTab}"] .radio-btn.bg-blue-500`);
|
||||||
|
const selectAllBtn = document.querySelector('.radio-select-all');
|
||||||
|
if (allCards.length > 0 && allCards.length === selectedCards.length) {
|
||||||
|
selectAllBtn.classList.add('bg-blue-500', 'border-blue-500');
|
||||||
|
selectAllBtn.classList.remove('border-gray-300', 'bg-white');
|
||||||
|
selectAllBtn.innerHTML = `<svg class="w-3 h-3 text-white" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>`;
|
||||||
|
} else {
|
||||||
|
selectAllBtn.classList.remove('bg-blue-500', 'border-blue-500');
|
||||||
|
selectAllBtn.classList.add('border-gray-300', 'bg-white');
|
||||||
|
selectAllBtn.innerHTML = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单选按钮切换
|
||||||
|
function toggleRadio(el, force) {
|
||||||
|
const isChecked = force != null ? force : !el.classList.contains('bg-blue-500');
|
||||||
|
if (isChecked) {
|
||||||
|
el.classList.add('bg-blue-500', 'border-blue-500');
|
||||||
|
el.classList.remove('border-gray-300', 'bg-white');
|
||||||
|
el.innerHTML = `<svg class="w-3 h-3 text-white" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>`;
|
||||||
|
} else {
|
||||||
|
el.classList.remove('bg-blue-500', 'border-blue-500');
|
||||||
|
el.classList.add('border-gray-300', 'bg-white');
|
||||||
|
el.innerHTML = '';
|
||||||
|
}
|
||||||
|
updateSelectCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单个单选点击
|
||||||
|
document.querySelectorAll('.radio-btn').forEach(radio => {
|
||||||
|
radio.onclick = (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
toggleRadio(radio);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// 全选按钮
|
||||||
|
document.querySelector('.select-all').onclick = function() {
|
||||||
|
const currentCards = document.querySelectorAll(`.uld-card[data-status="${currentTab}"] .radio-btn`);
|
||||||
|
const allSelected = Array.from(currentCards).every(item => item.classList.contains('bg-blue-500'));
|
||||||
|
currentCards.forEach(radio => toggleRadio(radio, !allSelected));
|
||||||
|
};
|
||||||
|
|
||||||
|
// ========== 完整长按逻辑(待运抵弹出补充,已运抵弹出重置回执) ==========
|
||||||
|
document.querySelectorAll('.uld-card').forEach(card => {
|
||||||
|
// 触摸长按
|
||||||
|
card.addEventListener('touchstart', (e) => {
|
||||||
|
// 点击单选框、按钮不触发长按
|
||||||
|
if (e.target.closest('.radio-btn') || e.target.closest('button')) return;
|
||||||
|
isLongPress = false;
|
||||||
|
longPressTimer = setTimeout(() => {
|
||||||
|
isLongPress = true;
|
||||||
|
showCardAction(card);
|
||||||
|
}, 600);
|
||||||
|
});
|
||||||
|
card.addEventListener('touchend', () => clearTimeout(longPressTimer));
|
||||||
|
card.addEventListener('touchmove', () => clearTimeout(longPressTimer));
|
||||||
|
|
||||||
|
// 鼠标长按兼容
|
||||||
|
card.addEventListener('mousedown', (e) => {
|
||||||
|
if (e.target.closest('.radio-btn') || e.target.closest('button')) return;
|
||||||
|
isLongPress = false;
|
||||||
|
longPressTimer = setTimeout(() => {
|
||||||
|
isLongPress = true;
|
||||||
|
showCardAction(card);
|
||||||
|
}, 600);
|
||||||
|
});
|
||||||
|
card.addEventListener('mouseup', () => clearTimeout(longPressTimer));
|
||||||
|
card.addEventListener('mouseleave', () => clearTimeout(longPressTimer));
|
||||||
|
});
|
||||||
|
|
||||||
|
// 展示卡片操作面板
|
||||||
|
function showCardAction(card) {
|
||||||
|
// 关闭所有卡片操作层
|
||||||
|
document.querySelectorAll('.card-action-overlay').forEach(overlay => overlay.classList.add('hidden'));
|
||||||
|
const overlay = card.querySelector('.card-action-overlay');
|
||||||
|
const pendingAction = overlay.querySelector('.pending-actions');
|
||||||
|
const shippedAction = overlay.querySelector('.shipped-actions');
|
||||||
|
pendingAction.classList.add('hidden');
|
||||||
|
shippedAction.classList.add('hidden');
|
||||||
|
// 根据状态展示对应按钮
|
||||||
|
if (card.dataset.status === 'pending') {
|
||||||
|
pendingAction.classList.remove('hidden');
|
||||||
|
} else {
|
||||||
|
shippedAction.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
overlay.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 点击空白区域关闭操作弹窗
|
||||||
|
document.addEventListener('click', (e) => {
|
||||||
|
if (!e.target.closest('.uld-card') && !e.target.closest('.card-action-overlay')) {
|
||||||
|
document.querySelectorAll('.card-action-overlay').forEach(overlay => overlay.classList.add('hidden'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 筛选弹窗
|
||||||
|
function showFilterSheet2() {
|
||||||
|
const overlay = document.getElementById('filter-sheet2-overlay');
|
||||||
|
const sheet = document.getElementById('filter-sheet2');
|
||||||
|
overlay.classList.remove('hidden');
|
||||||
|
setTimeout(() => sheet.classList.remove('translate-y-full'), 10);
|
||||||
|
}
|
||||||
|
function hideFilterSheet2() {
|
||||||
|
const overlay = document.getElementById('filter-sheet2-overlay');
|
||||||
|
const sheet = document.getElementById('filter-sheet2');
|
||||||
|
sheet.classList.add('translate-y-full');
|
||||||
|
setTimeout(() => overlay.classList.add('hidden'), 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置状态弹窗
|
||||||
|
function showResetStatusSheet() {
|
||||||
|
document.getElementById('reset-sheet-overlay').classList.remove('hidden');
|
||||||
|
document.getElementById('reset-sheet').classList.remove('translate-y-full');
|
||||||
|
}
|
||||||
|
function hideResetStatusSheet() {
|
||||||
|
document.getElementById('reset-sheet-overlay').classList.add('hidden');
|
||||||
|
document.getElementById('reset-sheet').classList.add('translate-y-full');
|
||||||
|
}
|
||||||
|
function confirmResetStatus() {
|
||||||
|
const selectVal = document.getElementById('reset-status-select').value;
|
||||||
|
if (!selectVal) {
|
||||||
|
alert('请选择状态');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
alert('已选择状态:' + (selectVal === '' ? '置空' : selectVal));
|
||||||
|
hideResetStatusSheet();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面初始化
|
||||||
|
switchTab('pending');
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
73
documents/5.5寸手持端设计文件/04_出港运抵/receipt.html
Normal file
73
documents/5.5寸手持端设计文件/04_出港运抵/receipt.html
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||||
|
<title>回执内容</title>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/tailwindcss.js"></script>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/iconify-icon.min.js"></script>
|
||||||
|
</head>
|
||||||
|
<body class="bg-gray-100 min-h-screen flex items-center justify-center font-sans">
|
||||||
|
<div class="phone-shell w-[375px] h-[812px] bg-[#F5F5F7] rounded-[48px] border-[10px] border-gray-900 overflow-hidden relative flex flex-col shadow-2xl">
|
||||||
|
<!-- 状态栏 -->
|
||||||
|
<div class="bg-blue-600 text-white text-xs px-6 py-1 flex justify-between items-center shrink-0 h-[44px]">
|
||||||
|
<span class="text-[15px] font-semibold">09:41</span>
|
||||||
|
<div class="flex gap-1.5 items-center">
|
||||||
|
<iconify-icon class="text-lg" icon="mdi:signal-cellular-3"></iconify-icon>
|
||||||
|
<iconify-icon class="text-lg" icon="mdi:wifi"></iconify-icon>
|
||||||
|
<iconify-icon class="text-xl" icon="mdi:battery"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 导航栏 -->
|
||||||
|
<div class="bg-blue-600 px-4 py-3 flex items-center gap-2 text-white shrink-0 h-[44px]">
|
||||||
|
<a class="text-white text-sm flex items-center gap-1" href="main.html">
|
||||||
|
<iconify-icon class="text-2xl" icon="mdi:chevron-left"></iconify-icon>
|
||||||
|
返回
|
||||||
|
</a>
|
||||||
|
<span class="flex-1 text-center text-white font-bold text-base">回执内容</span>
|
||||||
|
<div class="w-12"></div>
|
||||||
|
</div>
|
||||||
|
<!-- 内容列表 -->
|
||||||
|
<div class="p-4 space-y-3 flex-1 overflow-y-auto no-scrollbar">
|
||||||
|
<!-- 回执 1 -->
|
||||||
|
<div class="bg-white rounded-lg p-4 shadow-sm">
|
||||||
|
<p class="text-gray-700 text-sm leading-relaxed">
|
||||||
|
<span class="inline-block w-2 h-2 bg-blue-500 rounded-full mr-2.5 align-middle"></span>
|
||||||
|
单一窗口回执内容:45201 空运出口运抵报告传输成功。比对结果为:运抵正常。
|
||||||
|
</p>
|
||||||
|
<p class="text-gray-400 text-xs mt-2 ml-[18px]">2026-07-10 11:03:38</p>
|
||||||
|
</div>
|
||||||
|
<!-- 回执 2 -->
|
||||||
|
<div class="bg-white rounded-lg p-4 shadow-sm">
|
||||||
|
<p class="text-gray-700 text-sm leading-relaxed">
|
||||||
|
<span class="inline-block w-2 h-2 bg-blue-500 rounded-full mr-2.5 align-middle"></span>
|
||||||
|
单一窗口回执内容:45202 空运出口运抵报告传输成功。比对结果为:运抵正常。
|
||||||
|
</p>
|
||||||
|
<p class="text-gray-400 text-xs mt-2 ml-[18px]">2026-07-10 11:02:15</p>
|
||||||
|
</div>
|
||||||
|
<!-- 回执 3 -->
|
||||||
|
<div class="bg-white rounded-lg p-4 shadow-sm">
|
||||||
|
<p class="text-gray-700 text-sm leading-relaxed">
|
||||||
|
<span class="inline-block w-2 h-2 bg-blue-500 rounded-full mr-2.5 align-middle"></span>
|
||||||
|
单一窗口回执内容:45203 空运出口运抵报告传输成功。比对结果为:运抵正常。
|
||||||
|
</p>
|
||||||
|
<p class="text-gray-400 text-xs mt-2 ml-[18px]">2026-07-10 10:58:42</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Home Indicator -->
|
||||||
|
<div class="h-8 w-full flex items-center justify-center shrink-0">
|
||||||
|
<div class="w-32 h-1.5 bg-gray-300 rounded-full"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.no-scrollbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.no-scrollbar {
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
413
documents/5.5寸手持端设计文件/04_出港运抵/suborder.html
Normal file
413
documents/5.5寸手持端设计文件/04_出港运抵/suborder.html
Normal file
@@ -0,0 +1,413 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||||
|
<title>分单明细 - 出港运抵</title>
|
||||||
|
<!-- Tailwind CSS -->
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/tailwindcss.js"></script>
|
||||||
|
<!-- Iconify -->
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/iconify-icon.min.js"></script>
|
||||||
|
<style>
|
||||||
|
.no-scrollbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.phone-shell {
|
||||||
|
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="bg-gray-200 h-screen flex items-center justify-center font-sans">
|
||||||
|
<!-- 手机外壳容器 -->
|
||||||
|
<div class="phone-shell w-[375px] h-[812px] bg-[#F5F5F7] rounded-[48px] border-[10px] border-gray-900 overflow-hidden flex flex-col relative">
|
||||||
|
<!-- 顶部蓝色背景区域 -->
|
||||||
|
<div class="bg-[#1A73E8] flex-none">
|
||||||
|
<!-- 状态栏 -->
|
||||||
|
<div class="h-11 w-full flex justify-between items-center px-8 text-white">
|
||||||
|
<span class="text-sm font-medium">09:41</span>
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<iconify-icon icon="mingcute:signal-fill" width="16"></iconify-icon>
|
||||||
|
<iconify-icon icon="mingcute:wifi-line" width="16"></iconify-icon>
|
||||||
|
<iconify-icon class="rotate-90" icon="mingcute:battery-fill" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 导航栏 -->
|
||||||
|
<div class="h-[44px] px-4 flex items-center justify-between text-white">
|
||||||
|
<button class="flex items-center gap-1 text-sm" onclick="window.location.href='main.html'">
|
||||||
|
<iconify-icon icon="lucide:chevron-left" width="20"></iconify-icon>
|
||||||
|
<span>返回</span>
|
||||||
|
</button>
|
||||||
|
<h1 class="text-lg font-bold">分单明细</h1>
|
||||||
|
<div class="w-10"></div> <!-- 占位 -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 搜索栏 -->
|
||||||
|
<section class="px-5 pt-4 pb-3">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 shadow-sm rounded-[12px] h-10 px-3 gap-2 flex-1">
|
||||||
|
<iconify-icon class="text-gray-400 text-lg flex-none" icon="mdi:magnify"></iconify-icon>
|
||||||
|
<input class="flex-1 bg-transparent text-[14px] text-gray-800 placeholder-gray-400 outline-none border-none rounded-lg px-2" placeholder="搜索运单号" type="text"/>
|
||||||
|
<button class="flex-none text-blue-500">
|
||||||
|
<iconify-icon class="text-lg" icon="mdi:qrcode-scan"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button class="bg-white p-2.5 rounded-full shadow-sm border border-gray-200 text-[#2563EB] flex items-center justify-center flex-none" onclick="showFilterSheet()">
|
||||||
|
<iconify-icon class="text-lg" icon="mdi:filter-variant"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- 可滚动内容区 -->
|
||||||
|
<div class="flex-1 overflow-y-auto no-scrollbar px-5 pb-24 pt-2">
|
||||||
|
<!-- 分单列表内容 -->
|
||||||
|
<div class="space-y-4" id="suborder-list">
|
||||||
|
<!-- 分单1 -->
|
||||||
|
<div class="suborder-card bg-white rounded-2xl p-5 shadow-sm border border-gray-100/50 mb-4 cursor-pointer transition-all relative active:scale-[0.98]" data-id="10001" onclick="toggleSuborderSelect(this)">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="select-indicator border-2 border-gray-300 bg-white rounded-full w-5 h-5 inline-flex items-center justify-center flex-none cursor-pointer transition-colors"></span>
|
||||||
|
<span class="text-sm font-bold text-gray-900">10001</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="bg-indigo-100 text-indigo-500 text-[11px] font-medium px-2.5 py-0.5 rounded-full">W</span>
|
||||||
|
<span class="bg-green-100 text-green-600 text-[11px] font-medium px-2 py-0.5 rounded-md">11</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-y-2 text-gray-500 text-[13px] mt-3">
|
||||||
|
<div>
|
||||||
|
<span>件数:</span><span>150</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>重量:</span><span>50kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片操作菜单(默认隐藏) -->
|
||||||
|
<div class="card-action-overlay absolute inset-0 bg-black/40 rounded-2xl z-10 hidden flex items-center justify-center pointer-events-none">
|
||||||
|
<div class="flex items-center gap-4 pointer-events-auto">
|
||||||
|
<!-- 重置按钮 -->
|
||||||
|
<button class="bg-amber-500 text-white text-[10px] font-bold w-14 h-14 rounded-full shadow-lg shadow-amber-500/30 flex items-center justify-center leading-tight" onclick="event.stopPropagation(); this.closest('.card-action-overlay').classList.add('hidden'); setTimeout(() => showResetStatusSheet(), 200)">
|
||||||
|
重置
|
||||||
|
</button>
|
||||||
|
<!-- 回执按钮 -->
|
||||||
|
<button class="bg-emerald-500 text-white text-[10px] font-bold w-14 h-14 rounded-full shadow-lg shadow-emerald-500/30 flex items-center justify-center leading-tight" onclick="event.stopPropagation(); window.location.href='receipt.html'">
|
||||||
|
回执
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 分单2 -->
|
||||||
|
<div class="suborder-card bg-white rounded-2xl p-5 shadow-sm border border-gray-100/50 mb-4 cursor-pointer transition-all relative active:scale-[0.98]" data-id="10002" onclick="toggleSuborderSelect(this)">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="select-indicator border-2 border-gray-300 bg-white rounded-full w-5 h-5 inline-flex items-center justify-center flex-none cursor-pointer transition-colors"></span>
|
||||||
|
<span class="text-sm font-bold text-gray-900">10002</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="bg-amber-100 text-amber-600 text-[11px] font-medium px-2.5 py-0.5 rounded-full">E</span>
|
||||||
|
<span class="bg-green-100 text-green-600 text-[11px] font-medium px-2 py-0.5 rounded-md">11</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-y-2 text-gray-500 text-[13px] mt-3">
|
||||||
|
<div>
|
||||||
|
<span>件数:</span><span>120</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>重量:</span><span>40kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片操作菜单(默认隐藏) -->
|
||||||
|
<div class="card-action-overlay absolute inset-0 bg-black/40 rounded-2xl z-10 hidden flex items-center justify-center pointer-events-none">
|
||||||
|
<div class="flex items-center gap-4 pointer-events-auto">
|
||||||
|
<!-- 重置按钮 -->
|
||||||
|
<button class="bg-amber-500 text-white text-[10px] font-bold w-14 h-14 rounded-full shadow-lg shadow-amber-500/30 flex items-center justify-center leading-tight" onclick="event.stopPropagation(); this.closest('.card-action-overlay').classList.add('hidden'); setTimeout(() => showResetStatusSheet(), 200)">
|
||||||
|
重置
|
||||||
|
</button>
|
||||||
|
<!-- 回执按钮 -->
|
||||||
|
<button class="bg-emerald-500 text-white text-[10px] font-bold w-14 h-14 rounded-full shadow-lg shadow-emerald-500/30 flex items-center justify-center leading-tight" onclick="event.stopPropagation(); window.location.href='receipt.html'">
|
||||||
|
回执
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 分单3 -->
|
||||||
|
<div class="suborder-card bg-white rounded-2xl p-5 shadow-sm border border-gray-100/50 mb-4 cursor-pointer transition-all relative active:scale-[0.98]" data-id="10003" onclick="toggleSuborderSelect(this)">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="select-indicator border-2 border-gray-300 bg-white rounded-full w-5 h-5 inline-flex items-center justify-center flex-none cursor-pointer transition-colors"></span>
|
||||||
|
<span class="text-sm font-bold text-gray-900">10003</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="bg-green-100 text-green-600 text-[11px] font-medium px-2.5 py-0.5 rounded-full">01</span>
|
||||||
|
<span class="bg-green-100 text-green-600 text-[11px] font-medium px-2 py-0.5 rounded-md">11</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-y-2 text-gray-500 text-[13px] mt-3">
|
||||||
|
<div>
|
||||||
|
<span>件数:</span><span>174</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>重量:</span><span>60kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片操作菜单(默认隐藏) -->
|
||||||
|
<div class="card-action-overlay absolute inset-0 bg-black/40 rounded-2xl z-10 hidden flex items-center justify-center pointer-events-none">
|
||||||
|
<div class="flex items-center gap-4 pointer-events-auto">
|
||||||
|
<!-- 重置按钮 -->
|
||||||
|
<button class="bg-amber-500 text-white text-[10px] font-bold w-14 h-14 rounded-full shadow-lg shadow-amber-500/30 flex items-center justify-center leading-tight" onclick="event.stopPropagation(); this.closest('.card-action-overlay').classList.add('hidden'); setTimeout(() => showResetStatusSheet(), 200)">
|
||||||
|
重置
|
||||||
|
</button>
|
||||||
|
<!-- 回执按钮 -->
|
||||||
|
<button class="bg-emerald-500 text-white text-[10px] font-bold w-14 h-14 rounded-full shadow-lg shadow-emerald-500/30 flex items-center justify-center leading-tight" onclick="event.stopPropagation(); window.location.href='receipt.html'">
|
||||||
|
回执
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 底部操作栏 -->
|
||||||
|
<div class="flex-none bg-white border-t border-gray-100">
|
||||||
|
<div class="flex items-center justify-between px-5 py-3">
|
||||||
|
<div class="flex items-center gap-2 select-all-container cursor-pointer" onclick="toggleSuborderSelectAll(this)">
|
||||||
|
<span class="radio-select-all w-5 h-5 rounded-full border-2 border-gray-300 bg-white flex items-center justify-center transition-colors"></span>
|
||||||
|
<span class="text-sm text-gray-700 font-medium">全选</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<span class="text-[12px] text-[#9CA3AF]" id="suborder-count">已选 0 / 3 项</span>
|
||||||
|
<button class="bg-[#2563EB] text-white text-[15px] font-bold px-5 py-2 rounded-[10px] shadow-lg shadow-blue-500/25 active:scale-95 transition-transform" onclick="alert('申报成功')">申报</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 筛选弹框遮罩 -->
|
||||||
|
<div class="absolute inset-0 bg-black/40 z-30 hidden" id="filter-sheet-overlay" onclick="hideFilterSheet()"></div>
|
||||||
|
<!-- 筛选弹框 -->
|
||||||
|
<div class="absolute bottom-0 left-0 right-0 bg-white rounded-t-2xl shadow-2xl z-40 transform translate-y-full transition-transform duration-300 ease-in-out" id="filter-sheet">
|
||||||
|
<div class="px-5 pt-5 pb-8">
|
||||||
|
<!-- 标题 -->
|
||||||
|
<div class="flex items-center justify-center mb-6 relative">
|
||||||
|
<h3 class="text-base font-bold text-gray-900">筛选条件</h3>
|
||||||
|
<button class="absolute right-0 w-8 h-8 rounded-full bg-gray-100 flex items-center justify-center" onclick="hideFilterSheet()">
|
||||||
|
<svg class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24">
|
||||||
|
<line x1="18" x2="6" y1="6" y2="18"></line>
|
||||||
|
<line x1="6" x2="18" y1="6" y2="18"></line>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- 筛选条件区域 -->
|
||||||
|
<div class="space-y-4">
|
||||||
|
<!-- 航班日期 -->
|
||||||
|
<div>
|
||||||
|
<label class="text-sm text-gray-500 font-medium mb-1.5 block">航班日期</label>
|
||||||
|
<div class="flex items-center bg-gray-50 border border-gray-200 rounded-xl h-10 px-3">
|
||||||
|
<iconify-icon class="text-gray-400 text-lg flex-none" icon="mdi:calendar"></iconify-icon>
|
||||||
|
<input class="flex-1 bg-transparent text-[14px] text-gray-800 placeholder-gray-400 outline-none border-none px-2" placeholder="选择日期" type="text" value="2026-07-10"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 航班号 -->
|
||||||
|
<div>
|
||||||
|
<label class="text-sm text-gray-500 font-medium mb-1.5 block">航班号</label>
|
||||||
|
<div class="flex items-center bg-gray-50 border border-gray-200 rounded-xl h-10 px-3">
|
||||||
|
<input class="flex-1 bg-transparent text-[14px] text-gray-800 placeholder-gray-400 outline-none border-none" placeholder="请输入航班号" type="text"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 代理(已改为下拉框) -->
|
||||||
|
<div>
|
||||||
|
<label class="text-sm text-gray-500 font-medium mb-1.5 block">代理</label>
|
||||||
|
<div class="relative">
|
||||||
|
<select class="w-full bg-gray-50 border border-gray-200 rounded-xl h-10 px-3 text-[14px] text-gray-800 outline-none appearance-none focus:border-blue-500 focus:bg-white transition-all">
|
||||||
|
<option disabled selected value="">请选择代理</option>
|
||||||
|
<option value="马道">马道</option>
|
||||||
|
<option value="徽远">徽远</option>
|
||||||
|
<option value="中外运">中外运</option>
|
||||||
|
</select>
|
||||||
|
<iconify-icon class="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 pointer-events-none text-xl" icon="mdi:chevron-down"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 分单号 -->
|
||||||
|
<div>
|
||||||
|
<label class="text-sm text-gray-500 font-medium mb-1.5 block">分单号</label>
|
||||||
|
<div class="flex items-center bg-gray-50 border border-gray-200 rounded-xl h-10 px-3">
|
||||||
|
<input class="flex-1 bg-transparent text-[14px] text-gray-800 placeholder-gray-400 outline-none border-none" placeholder="请输入分单号" type="text"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 底部操作按钮 -->
|
||||||
|
<div class="flex gap-3 mt-6">
|
||||||
|
<button class="flex-1 py-3 text-sm font-medium text-gray-500 bg-gray-100 rounded-xl" onclick="hideFilterSheet()">重置</button>
|
||||||
|
<button class="flex-1 py-3 text-sm font-medium text-white bg-[#2563EB] rounded-xl" onclick="hideFilterSheet()">确定</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Home Indicator 底部横条 -->
|
||||||
|
<div class="h-8 w-full flex justify-center items-center">
|
||||||
|
<div class="w-32 h-1.5 bg-black rounded-full opacity-20"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 重置状态弹框 -->
|
||||||
|
<div class="absolute inset-0 bg-black/40 z-30 hidden" id="reset-sheet-overlay" onclick="hideResetStatusSheet()"></div>
|
||||||
|
<div class="absolute bottom-0 left-0 right-0 bg-white rounded-t-2xl shadow-2xl z-40 transform translate-y-full transition-transform duration-300 ease-in-out" id="reset-sheet">
|
||||||
|
<div class="px-5 pt-5 pb-8">
|
||||||
|
<!-- 标题 -->
|
||||||
|
<div class="flex items-center justify-center mb-6 relative">
|
||||||
|
<h3 class="text-base font-bold text-gray-900">重置状态</h3>
|
||||||
|
<button class="absolute right-0 w-8 h-8 rounded-full bg-gray-100 flex items-center justify-center" onclick="hideResetStatusSheet()">
|
||||||
|
<svg class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24">
|
||||||
|
<line x1="18" x2="6" y1="6" y2="18"></line>
|
||||||
|
<line x1="6" x2="18" y1="6" y2="18"></line>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- 状态下拉选择 -->
|
||||||
|
<div>
|
||||||
|
<label class="text-sm text-gray-500 font-medium mb-1.5 block">状态</label>
|
||||||
|
<select class="w-full bg-gray-50 border border-gray-200 rounded-xl h-10 px-3 text-[14px] text-gray-800 outline-none appearance-none bg-[url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%202000%2Fsvg%22%20width%3D%2212%22%20height%3D%2212%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22%239CA3AF%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpolyline%20points%3D%226%209%2012%2015%2018%209%22%3E%3C%2Fpolyline%3E%3C%2Fsvg%3E')] bg-[length:14px] bg-[right_12px_center] bg-no-repeat" id="reset-status-select">
|
||||||
|
<option disabled="" selected="" value="">请选择状态</option>
|
||||||
|
<option value="">空</option>
|
||||||
|
<option value="01">01</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<!-- 确认按钮 -->
|
||||||
|
<button class="w-full mt-6 py-3 text-sm font-medium text-white bg-[#2563EB] rounded-xl" onclick="confirmResetStatus()">
|
||||||
|
确定
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// 单选分单卡片
|
||||||
|
function toggleSuborderSelect(card) {
|
||||||
|
if (window.isLongPressing) return;
|
||||||
|
card.classList.toggle('selected');
|
||||||
|
const indicator = card.querySelector('.select-indicator');
|
||||||
|
if (card.classList.contains('selected')) {
|
||||||
|
indicator.classList.remove('border-gray-300', 'bg-white');
|
||||||
|
indicator.classList.add('bg-blue-500', 'border-blue-500');
|
||||||
|
indicator.innerHTML = `<svg class="w-3 h-3 text-white" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>`;
|
||||||
|
} else {
|
||||||
|
indicator.classList.remove('bg-blue-500', 'border-blue-500');
|
||||||
|
indicator.classList.add('border-gray-300', 'bg-white');
|
||||||
|
indicator.innerHTML = '';
|
||||||
|
}
|
||||||
|
updateSuborderCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全选/取消全选
|
||||||
|
function toggleSuborderSelectAll(btn) {
|
||||||
|
const allCards = document.querySelectorAll('.suborder-card');
|
||||||
|
const isAllSelected = Array.from(allCards).every(card => card.classList.contains('selected'));
|
||||||
|
if (isAllSelected) {
|
||||||
|
allCards.forEach(card => {
|
||||||
|
card.classList.remove('selected');
|
||||||
|
const ci = card.querySelector('.select-indicator');
|
||||||
|
ci.classList.remove('bg-blue-500', 'border-blue-500');
|
||||||
|
ci.classList.add('border-gray-300', 'bg-white');
|
||||||
|
ci.innerHTML = '';
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
allCards.forEach(card => {
|
||||||
|
card.classList.add('selected');
|
||||||
|
const ci = card.querySelector('.select-indicator');
|
||||||
|
ci.classList.remove('border-gray-300', 'bg-white');
|
||||||
|
ci.classList.add('bg-blue-500', 'border-blue-500');
|
||||||
|
ci.innerHTML = `<svg class="w-3 h-3 text-white" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
updateSuborderCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新底部选中数量
|
||||||
|
function updateSuborderCount() {
|
||||||
|
const selected = document.querySelectorAll('.suborder-card.selected').length;
|
||||||
|
const total = document.querySelectorAll('.suborder-card').length;
|
||||||
|
document.getElementById('suborder-count').innerText = `已选 ${selected} / ${total} 项`;
|
||||||
|
updateSelectAllState(selected, total);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同步全选按钮状态
|
||||||
|
function updateSelectAllState(selectedCount, totalCount) {
|
||||||
|
const allBtn = document.querySelector('.radio-select-all');
|
||||||
|
if (selectedCount === totalCount && totalCount > 0) {
|
||||||
|
allBtn.classList.remove('border-gray-300', 'bg-white');
|
||||||
|
allBtn.classList.add('bg-blue-500', 'border-blue-500');
|
||||||
|
allBtn.innerHTML = `<svg class="w-3 h-3 text-white" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>`;
|
||||||
|
} else {
|
||||||
|
allBtn.classList.remove('bg-blue-500', 'border-blue-500');
|
||||||
|
allBtn.classList.add('border-gray-300', 'bg-white');
|
||||||
|
allBtn.innerHTML = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选弹窗打开
|
||||||
|
function showFilterSheet() {
|
||||||
|
const overlay = document.getElementById('filter-sheet-overlay');
|
||||||
|
const sheet = document.getElementById('filter-sheet');
|
||||||
|
overlay.classList.remove('hidden');
|
||||||
|
setTimeout(() => {
|
||||||
|
sheet.classList.remove('translate-y-full');
|
||||||
|
sheet.classList.add('translate-y-0');
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选弹窗关闭
|
||||||
|
function hideFilterSheet() {
|
||||||
|
const overlay = document.getElementById('filter-sheet-overlay');
|
||||||
|
const sheet = document.getElementById('filter-sheet');
|
||||||
|
sheet.classList.add('translate-y-full');
|
||||||
|
sheet.classList.remove('translate-y-0');
|
||||||
|
setTimeout(() => {
|
||||||
|
overlay.classList.add('hidden');
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 卡片长按弹出操作菜单
|
||||||
|
window.isLongPressing = false;
|
||||||
|
document.querySelectorAll('.suborder-card').forEach(card => {
|
||||||
|
let timer;
|
||||||
|
// 鼠标按下
|
||||||
|
card.addEventListener('mousedown', e => {
|
||||||
|
if (e.target.closest('.select-indicator') || e.target.closest('button')) return;
|
||||||
|
window.isLongPressing = false;
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
window.isLongPressing = true;
|
||||||
|
showSuborderActionMenu(card);
|
||||||
|
}, 600);
|
||||||
|
});
|
||||||
|
card.addEventListener('mouseup', () => { clearTimeout(timer); setTimeout(()=>{window.isLongPressing=false},50) });
|
||||||
|
card.addEventListener('mouseleave', () => { clearTimeout(timer); window.isLongPressing=false });
|
||||||
|
// 触屏兼容
|
||||||
|
card.addEventListener('touchstart', e => {
|
||||||
|
if (e.target.closest('.select-indicator') || e.target.closest('button')) return;
|
||||||
|
window.isLongPressing = false;
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
window.isLongPressing = true;
|
||||||
|
showSuborderActionMenu(card);
|
||||||
|
}, 600);
|
||||||
|
});
|
||||||
|
card.addEventListener('touchend', () => { clearTimeout(timer); setTimeout(()=>{window.isLongPressing=false},50) });
|
||||||
|
card.addEventListener('touchmove', () => { clearTimeout(timer); window.isLongPressing=false });
|
||||||
|
});
|
||||||
|
|
||||||
|
function showSuborderActionMenu(card) {
|
||||||
|
document.querySelectorAll('.card-action-overlay').forEach(o => o.classList.add('hidden'));
|
||||||
|
const overlay = card.querySelector('.card-action-overlay');
|
||||||
|
if (overlay) overlay.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置状态弹窗
|
||||||
|
function showResetStatusSheet() {
|
||||||
|
document.getElementById('reset-sheet-overlay').classList.remove('hidden');
|
||||||
|
document.getElementById('reset-sheet').classList.remove('translate-y-full');
|
||||||
|
}
|
||||||
|
function hideResetStatusSheet() {
|
||||||
|
document.getElementById('reset-sheet-overlay').classList.add('hidden');
|
||||||
|
document.getElementById('reset-sheet').classList.add('translate-y-full');
|
||||||
|
}
|
||||||
|
function confirmResetStatus() {
|
||||||
|
const s = document.getElementById('reset-status-select');
|
||||||
|
if (!s.value && s.selectedIndex===0) { alert('请选择状态'); return; }
|
||||||
|
alert(s.value==='' ? '已选择状态: 置空' : '已选择状态: '+s.value);
|
||||||
|
hideResetStatusSheet();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
175
documents/5.5寸手持端设计文件/04_出港运抵/supplement.html
Normal file
175
documents/5.5寸手持端设计文件/04_出港运抵/supplement.html
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||||
|
<title>补充信息</title>
|
||||||
|
<!-- Tailwind CSS -->
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/tailwindcss.js"></script>
|
||||||
|
<!-- Iconify -->
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/iconify-icon.min.js"></script>
|
||||||
|
<style>
|
||||||
|
.no-scrollbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background-color: #f3f4f6;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="bg-gray-200">
|
||||||
|
<!-- Phone Shell -->
|
||||||
|
<div class="phone-shell w-[375px] h-[812px] bg-[#F5F5F7] overflow-hidden flex flex-col relative rounded-[48px] border-[10px] border-gray-900 shadow-2xl">
|
||||||
|
<!-- Status Bar & Nav Bar Container -->
|
||||||
|
<div class="bg-[#1A73E8] flex-none">
|
||||||
|
<!-- Status Bar -->
|
||||||
|
<div class="h-[44px] flex justify-between items-center px-8 text-white">
|
||||||
|
<span class="text-[15px] font-semibold">09:41</span>
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-lg" icon="mdi:signal-cellular-3"></iconify-icon>
|
||||||
|
<iconify-icon class="text-lg" icon="mdi:wifi"></iconify-icon>
|
||||||
|
<iconify-icon class="text-xl" icon="mdi:battery"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Navigation Bar -->
|
||||||
|
<div class="h-[44px] flex items-center px-4 relative">
|
||||||
|
<div class="flex items-center text-white cursor-pointer" onclick="window.location.href='main.html'">
|
||||||
|
<iconify-icon class="text-2xl" icon="mdi:chevron-left"></iconify-icon>
|
||||||
|
<span class="text-sm">返回</span>
|
||||||
|
</div>
|
||||||
|
<div class="absolute inset-0 flex items-center justify-center pointer-events-none">
|
||||||
|
<h1 class="text-white text-lg font-bold">补充信息</h1>
|
||||||
|
</div>
|
||||||
|
<div class="ml-auto w-10"></div> <!-- Placeholder for right side -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Content Area -->
|
||||||
|
<div class="flex-1 overflow-y-auto no-scrollbar p-4 space-y-4">
|
||||||
|
<!-- 收货人信息 -->
|
||||||
|
<div class="bg-white rounded-2xl p-5 shadow-sm border border-gray-100/50">
|
||||||
|
<div class="flex items-center gap-2 mb-4">
|
||||||
|
<div class="w-1.5 h-4 bg-[#1A73E8] rounded-full"></div>
|
||||||
|
<h3 class="text-sm font-bold text-gray-900">收货人信息</h3>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label class="text-[13px] text-gray-500 font-medium mb-1.5 block">收货人名称</label>
|
||||||
|
<div class="flex items-center bg-gray-50 border border-gray-200 rounded-xl h-10 px-3 focus-within:border-blue-500 focus-within:bg-white transition-all">
|
||||||
|
<input class="flex-1 bg-transparent text-[14px] text-gray-800 placeholder-gray-400 outline-none border-none" placeholder="请输入收货人名称" type="text"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="text-[13px] text-gray-500 font-medium mb-1.5 block">国家代码</label>
|
||||||
|
<div class="relative">
|
||||||
|
<select class="w-full bg-gray-50 border border-gray-200 rounded-xl h-10 px-3 text-[14px] text-gray-800 outline-none appearance-none focus:border-blue-500 focus:bg-white transition-all">
|
||||||
|
<option disabled="" value="">请选择</option>
|
||||||
|
<option selected="" value="US">US - 美国</option>
|
||||||
|
<option value="CN">CN - 中国</option>
|
||||||
|
<option value="JP">JP - 日本</option>
|
||||||
|
<option value="UK">UK - 英国</option>
|
||||||
|
<option value="DE">DE - 德国</option>
|
||||||
|
<option value="FR">FR - 法国</option>
|
||||||
|
</select>
|
||||||
|
<iconify-icon class="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 pointer-events-none text-xl" icon="mdi:chevron-down"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="text-[13px] text-gray-500 font-medium mb-1.5 block">通讯方式</label>
|
||||||
|
<div class="relative">
|
||||||
|
<select class="w-full bg-gray-50 border border-gray-200 rounded-xl h-10 px-3 text-[14px] text-gray-800 outline-none appearance-none focus:border-blue-500 focus:bg-white transition-all">
|
||||||
|
<option disabled="" selected="" value="">请选择</option>
|
||||||
|
<option value="phone">电话</option>
|
||||||
|
<option value="email">邮件</option>
|
||||||
|
<option value="fax">传真</option>
|
||||||
|
</select>
|
||||||
|
<iconify-icon class="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 pointer-events-none text-xl" icon="mdi:chevron-down"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="text-[13px] text-gray-500 font-medium mb-1.5 block">联系号码</label>
|
||||||
|
<div class="flex items-center bg-gray-50 border border-gray-200 rounded-xl h-10 px-3 focus-within:border-blue-500 focus-within:bg-white transition-all">
|
||||||
|
<input class="flex-1 bg-transparent text-[14px] text-gray-800 placeholder-gray-400 outline-none border-none" placeholder="请输入联系号码" type="text"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="text-[13px] text-gray-500 font-medium mb-1.5 block">地址</label>
|
||||||
|
<div class="flex items-center bg-gray-50 border border-gray-200 rounded-xl h-10 px-3 focus-within:border-blue-500 focus-within:bg-white transition-all">
|
||||||
|
<input class="flex-1 bg-transparent text-[14px] text-gray-800 placeholder-gray-400 outline-none border-none" placeholder="请输入地址" type="text"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 发货人信息 -->
|
||||||
|
<div class="bg-white rounded-2xl p-5 shadow-sm border border-gray-100/50">
|
||||||
|
<div class="flex items-center gap-2 mb-4">
|
||||||
|
<div class="w-1.5 h-4 bg-[#1A73E8] rounded-full"></div>
|
||||||
|
<h3 class="text-sm font-bold text-gray-900">发货人信息</h3>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label class="text-[13px] text-gray-500 font-medium mb-1.5 block">发货人名称</label>
|
||||||
|
<div class="flex items-center bg-gray-50 border border-gray-200 rounded-xl h-10 px-3 focus-within:border-blue-500 focus-within:bg-white transition-all">
|
||||||
|
<input class="flex-1 bg-transparent text-[14px] text-gray-800 placeholder-gray-400 outline-none border-none" placeholder="请输入发货人名称" type="text"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="text-[13px] text-gray-500 font-medium mb-1.5 block">国家代码</label>
|
||||||
|
<div class="relative">
|
||||||
|
<select class="w-full bg-gray-50 border border-gray-200 rounded-xl h-10 px-3 text-[14px] text-gray-800 outline-none appearance-none focus:border-blue-500 focus:bg-white transition-all">
|
||||||
|
<option disabled="" value="">请选择</option>
|
||||||
|
<option selected="" value="US">US - 美国</option>
|
||||||
|
<option value="CN">CN - 中国</option>
|
||||||
|
<option value="JP">JP - 日本</option>
|
||||||
|
<option value="UK">UK - 英国</option>
|
||||||
|
<option value="DE">DE - 德国</option>
|
||||||
|
<option value="FR">FR - 法国</option>
|
||||||
|
</select>
|
||||||
|
<iconify-icon class="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 pointer-events-none text-xl" icon="mdi:chevron-down"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="text-[13px] text-gray-500 font-medium mb-1.5 block">通讯方式</label>
|
||||||
|
<div class="relative">
|
||||||
|
<select class="w-full bg-gray-50 border border-gray-200 rounded-xl h-10 px-3 text-[14px] text-gray-800 outline-none appearance-none focus:border-blue-500 focus:bg-white transition-all">
|
||||||
|
<option disabled="" selected="" value="">请选择</option>
|
||||||
|
<option value="phone">电话</option>
|
||||||
|
<option value="email">邮件</option>
|
||||||
|
<option value="fax">传真</option>
|
||||||
|
</select>
|
||||||
|
<iconify-icon class="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 pointer-events-none text-xl" icon="mdi:chevron-down"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="text-[13px] text-gray-500 font-medium mb-1.5 block">联系号码</label>
|
||||||
|
<div class="flex items-center bg-gray-50 border border-gray-200 rounded-xl h-10 px-3 focus-within:border-blue-500 focus-within:bg-white transition-all">
|
||||||
|
<input class="flex-1 bg-transparent text-[14px] text-gray-800 placeholder-gray-400 outline-none border-none" placeholder="请输入联系号码" type="text"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="text-[13px] text-gray-500 font-medium mb-1.5 block">地址</label>
|
||||||
|
<div class="flex items-center bg-gray-50 border border-gray-200 rounded-xl h-10 px-3 focus-within:border-blue-500 focus-within:bg-white transition-all">
|
||||||
|
<input class="flex-1 bg-transparent text-[14px] text-gray-800 placeholder-gray-400 outline-none border-none" placeholder="请输入地址" type="text"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 底部确定按钮 -->
|
||||||
|
<div class="px-5 py-4 shrink-0">
|
||||||
|
<button class="w-full bg-[#2563EB] text-white text-[15px] font-bold py-3.5 rounded-xl shadow-lg shadow-blue-500/30 active:scale-[0.98] transition-all" onclick="alert('补充信息已提交'); window.location.href='main.html'">
|
||||||
|
确定
|
||||||
|
</button>
|
||||||
|
<!-- Home Indicator -->
|
||||||
|
<div class="mt-4 flex justify-center">
|
||||||
|
<div class="w-32 h-1.5 bg-gray-200 rounded-full"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
668
documents/5.5寸手持端设计文件/05_出港移库/出港移库.html
Normal file
668
documents/5.5寸手持端设计文件/05_出港移库/出港移库.html
Normal file
@@ -0,0 +1,668 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
|
||||||
|
<title>出港移库 - 移动端原型</title>
|
||||||
|
<!-- Tailwind CSS -->
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/tailwindcss.js"></script>
|
||||||
|
<!-- Iconify -->
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/iconify-icon.min.js"></script>
|
||||||
|
<style>
|
||||||
|
@font-face {
|
||||||
|
font-family: 'PingFang SC';
|
||||||
|
src: local('PingFang SC');
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: 'PingFang SC', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||||
|
/* 同步参考页面body背景色 */
|
||||||
|
background-color: #e2e8f0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
/* 模拟手机容器 - 同步参考底色 */
|
||||||
|
.phone-container {
|
||||||
|
width: 375px;
|
||||||
|
height: 812px;
|
||||||
|
background-color: #f5f6fa;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
||||||
|
border: 8px solid #1a1a1a;
|
||||||
|
border-radius: 40px;
|
||||||
|
}
|
||||||
|
/* 隐藏滚动条但保留滚动 */
|
||||||
|
.no-scrollbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.no-scrollbar {
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
/* 页面切换动画 */
|
||||||
|
.page {
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.page.active {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
/* 筛选面板弹出动画 */
|
||||||
|
#filter-panel {
|
||||||
|
transform: translateY(100%);
|
||||||
|
transition: transform 0.3s ease-out;
|
||||||
|
}
|
||||||
|
#filter-panel.show {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
.overlay {
|
||||||
|
background-color: rgba(0,0,0,0.5);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.overlay.show {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
/* 按钮按压效果 */
|
||||||
|
.btn-active:active {
|
||||||
|
opacity: 0.7;
|
||||||
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
|
/* 复选框样式 */
|
||||||
|
.custom-checkbox {
|
||||||
|
appearance: none;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border: 2px solid #cbd5e1;
|
||||||
|
border-radius: 4px;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.2s;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
.custom-checkbox:checked {
|
||||||
|
background-color: #2563EB;
|
||||||
|
border-color: #2563EB;
|
||||||
|
}
|
||||||
|
.custom-checkbox:checked::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 6px;
|
||||||
|
top: 2px;
|
||||||
|
width: 5px;
|
||||||
|
height: 10px;
|
||||||
|
border: solid white;
|
||||||
|
border-width: 0 2px 2px 0;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
.custom-checkbox-round {
|
||||||
|
appearance: none;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border: 2px solid #cbd5e1;
|
||||||
|
border-radius: 50%;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.2s;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
.custom-checkbox-round:checked {
|
||||||
|
background-color: #2563EB;
|
||||||
|
border-color: #2563EB;
|
||||||
|
}
|
||||||
|
.custom-checkbox-round:checked::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 6px;
|
||||||
|
top: 2px;
|
||||||
|
width: 5px;
|
||||||
|
height: 10px;
|
||||||
|
border: solid white;
|
||||||
|
border-width: 0 2px 2px 0;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="phone-container">
|
||||||
|
<!-- 状态栏 -->
|
||||||
|
<div class="h-10 w-full flex justify-between items-center px-8 flex-none bg-[#2563EB] text-white">
|
||||||
|
<span class="text-xs font-semibold">09:41</span>
|
||||||
|
<div class="flex gap-1 items-center">
|
||||||
|
<iconify-icon icon="mdi:signal" width="14"></iconify-icon>
|
||||||
|
<iconify-icon icon="mdi:wifi" width="14"></iconify-icon>
|
||||||
|
<iconify-icon icon="mdi:battery" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 列表首页 -->
|
||||||
|
<div class="page active" id="page-home">
|
||||||
|
<!-- 顶部导航栏 -->
|
||||||
|
<div class="bg-[#2563EB] text-white h-12 flex items-center justify-between px-4 flex-none">
|
||||||
|
<div class="flex items-center btn-active" onclick="alert('返回首页')">
|
||||||
|
<iconify-icon icon="mdi:chevron-left" width="28"></iconify-icon>
|
||||||
|
<span class="text-sm font-bold -ml-1">返回</span>
|
||||||
|
</div>
|
||||||
|
<h1 class="text-lg font-medium">出港移库</h1>
|
||||||
|
<div class="w-16"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 滚动内容区域 -->
|
||||||
|
<div class="flex-1 overflow-y-auto no-scrollbar pb-24">
|
||||||
|
<!-- 搜索栏 -->
|
||||||
|
<section class="px-4 pt-4 pb-3 bg-white">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 shadow-sm rounded-[12px] h-10 px-3 gap-2 flex-1">
|
||||||
|
<iconify-icon class="text-gray-400 text-lg flex-none" icon="mdi:magnify"></iconify-icon>
|
||||||
|
<input class="flex-1 bg-transparent text-[14px] text-gray-800 placeholder-gray-400 outline-none border-none rounded-lg px-2" placeholder="搜索运单号" type="text"/>
|
||||||
|
<button class="flex-none text-blue-500">
|
||||||
|
<iconify-icon class="text-lg" icon="mdi:qrcode-scan"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button class="bg-white p-2.5 rounded-full shadow-sm border border-gray-200 text-[#2563EB] flex items-center justify-center flex-none" onclick="toggleFilterDrawer(true)">
|
||||||
|
<iconify-icon class="text-xl" icon="mdi:filter-variant"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Tab切换 -->
|
||||||
|
<div class="flex bg-white border-b sticky top-0 z-20">
|
||||||
|
<button class="flex-1 py-3 text-sm font-bold text-[#1F2937] border-b-2 border-[#1F2937] transition-all" id="tab-pending" onclick="switchTab('pending')">
|
||||||
|
待移库 <span class="bg-[#DBEAF6] text-[#2563EB] text-[11px] font-medium px-1.5 py-0.5 rounded-md ml-1.5">3</span>
|
||||||
|
</button>
|
||||||
|
<button class="flex-1 py-3 text-sm font-bold text-gray-400 border-b-2 border-transparent transition-all" id="tab-shipped" onclick="switchTab('shipped')">
|
||||||
|
已移库 <span class="bg-[#DBEAF6] text-[#2563EB] text-[11px] font-medium px-1.5 py-0.5 rounded-md ml-1.5">3</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 待移库列表 -->
|
||||||
|
<div class="p-3 pt-4 space-y-3" id="list-pending">
|
||||||
|
<!-- 卡片1 -->
|
||||||
|
<div class="pending-card bg-white rounded-xl shadow-sm p-4 mb-3 overflow-hidden">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input class="item-checkbox custom-checkbox-round flex-none" onclick="handleCheckboxClick(this, event)" type="checkbox"/>
|
||||||
|
<div class="text-[#2563EB] text-[15px] font-bold">78133363573</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="bg-orange-100 text-orange-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">待移库</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon icon="mdi:airplane" class="text-gray-500 text-[14px]"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">航班信息:20260709/MU2311</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">特码</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">NOR</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">件数</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">100件</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">重量</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">200kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:map-marker"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">出运路径:HFE-NKG-LAX</span>
|
||||||
|
</div>
|
||||||
|
<div class="mt-4 flex justify-end border-t border-gray-100 pt-3">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer btn-active" onclick="showDetail({id: '78133363573', status: '待移库', agent: 'NOR', pieces: '100', weight: '200', goodsName: '电子元器件', carrier: 'MU', route: 'HFE-NKG-LAX', location: 'A区-03货位', code: 'NOR', counterPerson: '--', counterTime: '--', outboundPerson: '', outboundTime: ''})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片2 -->
|
||||||
|
<div class="pending-card bg-white rounded-xl shadow-sm p-4 mb-3 overflow-hidden">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input class="item-checkbox custom-checkbox-round flex-none" onclick="handleCheckboxClick(this, event)" type="checkbox"/>
|
||||||
|
<div class="text-[#2563EB] text-[15px] font-bold">78133363574</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="bg-orange-100 text-orange-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">待移库</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon icon="mdi:airplane" class="text-gray-500 text-[14px]"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">航班信息:20260709/MU2311</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">特码</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">CTA</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">件数</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">85件</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">重量</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">150kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:map-marker"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">出运路径:HFE-PEK-LAX</span>
|
||||||
|
</div>
|
||||||
|
<div class="mt-4 flex justify-end border-t border-gray-100 pt-3">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer btn-active" onclick="showDetail({id: '78133363574', status: '待移库', agent: 'CTA', pieces: '85', weight: '150', goodsName: '服装鞋帽', carrier: 'CA', route: 'HFE-PEK-LAX', location: 'B区-05货位', code: 'NOR', counterPerson: '--', counterTime: '--', outboundPerson: '', outboundTime: ''})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片3 -->
|
||||||
|
<div class="pending-card bg-white rounded-xl shadow-sm p-4 mb-3 overflow-hidden">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input class="item-checkbox custom-checkbox-round flex-none" onclick="handleCheckboxClick(this, event)" type="checkbox"/>
|
||||||
|
<div class="text-[#2563EB] text-[15px] font-bold">78133363575</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="bg-orange-100 text-orange-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">待移库</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon icon="mdi:airplane" class="text-gray-500 text-[14px]"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">航班信息:20260709/MU2311</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">特码</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">DHL</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">件数</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">200件</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">重量</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">450kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:map-marker"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">出运路径:HFE-NKG-LAX</span>
|
||||||
|
</div>
|
||||||
|
<div class="mt-4 flex justify-end border-t border-gray-100 pt-3">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer btn-active" onclick="showDetail({id: '78133363575', status: '待移库', agent: 'DHL', pieces: '200', weight: '450', goodsName: '精密模具', carrier: '3U', route: 'HFE-NKG-LAX', location: 'C区-01货位', code: 'NOR', counterPerson: '--', counterTime: '--', outboundPerson: '', outboundTime: ''})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 已移库列表 -->
|
||||||
|
<div class="p-3 pt-4 space-y-3 hidden" id="list-shipped">
|
||||||
|
<div class="bg-white rounded-xl shadow-sm p-4 mb-3">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="text-[#1F2937] text-[15px] font-bold">78133363001</div>
|
||||||
|
<div class="flex items-center gap-1 text-[#1F2937] text-[13px] font-medium">
|
||||||
|
<iconify-icon class="text-[#10B981]" icon="mdi:check-circle" width="16"></iconify-icon>
|
||||||
|
<span>已移库</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon icon="mdi:airplane" class="text-gray-500 text-[14px]"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">航班信息:20260709/MU2311</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">特码</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">NOR</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">件数</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">50件</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">重量</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">80kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:account-outline"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">出运路径:HFE-NKG-LAX</span>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2 flex justify-end border-t border-gray-50 pt-2">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer btn-active" onclick="showDetail({id: '78133363001', status: '已移库', agent: 'NOR', pieces: '50', weight: '80', pickupNo: 'TH20260701001', goodsName: '精密仪器', carrier: 'MU', route: 'HFE-NKG-LAX', location: 'B区-05货位', code: 'NOR', counterTime: '2026-07-05 10:30', counterPerson: '张三', outboundTime: '2026-07-05 11:45', outboundPerson: '张三'})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white rounded-xl shadow-sm p-4 mb-3">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="text-[#1F2937] text-[15px] font-bold">78133363002</div>
|
||||||
|
<div class="flex items-center gap-1 text-[#1F2937] text-[13px] font-medium">
|
||||||
|
<iconify-icon class="text-[#10B981]" icon="mdi:check-circle" width="16"></iconify-icon>
|
||||||
|
<span>已移库</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon icon="mdi:airplane" class="text-gray-500 text-[14px]"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">航班信息:20260709/MU2311</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">特码</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">CTA</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">件数</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">120件</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">重量</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">300kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:account-outline"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">出运路径:HFE-PEK-LAX</span>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2 flex justify-end border-t border-gray-50 pt-2">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer btn-active" onclick="showDetail({id: '78133363002', status: '已移库', agent: 'CTA', pieces: '120', weight: '300', pickupNo: 'TH20260702002', goodsName: '鲜花绿植', carrier: 'CA', route: 'HFE-PEK-LAX', location: 'A区-08货位', code: 'NOR', counterTime: '2026-07-06 09:15', counterPerson: '王五', outboundTime: '2026-07-06 10:30', outboundPerson: '赵六'})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white rounded-xl shadow-sm p-4 mb-3">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="text-[#1F2937] text-[15px] font-bold">78133363003</div>
|
||||||
|
<div class="flex items-center gap-1 text-[#1F2937] text-[13px] font-medium">
|
||||||
|
<iconify-icon class="text-[#10B981]" icon="mdi:check-circle" width="16"></iconify-icon>
|
||||||
|
<span>已移库</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon icon="mdi:airplane" class="text-gray-500 text-[14px]"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">航班信息:20260709/MU2311</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">特码</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">DHL</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">件数</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">75件</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">重量</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">160kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:account-outline"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">出运路径:HFE-NKG-LAX</span>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2 flex justify-end border-t border-gray-50 pt-2">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer btn-active" onclick="showDetail({id: '78133363003', status: '已移库', agent: 'DHL', pieces: '75', weight: '160', pickupNo: 'TH20260703003', goodsName: '生鲜食品', carrier: '3U', route: 'HFE-NKG-LAX', location: 'D区-02货位', code: 'NOR', counterTime: '2026-07-06 14:00', counterPerson: '钱七', outboundTime: '2026-07-06 15:20', outboundPerson: '孙八'})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 底部操作栏 -->
|
||||||
|
<div class="absolute bottom-0 w-full bg-white border-t border-gray-200 z-40 flex flex-col pt-4 pb-4" id="bottom-toolbar">
|
||||||
|
<div class="px-4 flex items-center w-full">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input class="custom-checkbox-round" id="select-all-cb" onclick="toggleSelectAll(this.checked)" type="checkbox"/>
|
||||||
|
<label class="text-[13px] text-[#1F2937] font-medium cursor-pointer" for="select-all-cb">全选</label>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1"></div>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<span class="text-[12px] text-[#9CA3AF]">已选 <span id="selected-count">0</span> 项</span>
|
||||||
|
<button class="bg-[#2563EB] text-white text-[15px] font-bold px-5 py-2 rounded-[10px] shadow-lg shadow-blue-500/25 btn-active" onclick="alert('移库操作')">
|
||||||
|
移库
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 运单详情页面 -->
|
||||||
|
<div class="page" id="page-detail">
|
||||||
|
<div class="bg-[#2563EB] text-white h-12 flex items-center justify-between px-4 flex-none">
|
||||||
|
<div class="flex items-center btn-active" onclick="switchPage('page-home')">
|
||||||
|
<iconify-icon icon="mdi:chevron-left" width="28"></iconify-icon>
|
||||||
|
<span class="text-sm font-bold -ml-1">返回</span>
|
||||||
|
</div>
|
||||||
|
<h1 class="text-lg font-medium">运单详情</h1>
|
||||||
|
<div class="w-16"></div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 overflow-y-auto no-scrollbar pb-8 p-4">
|
||||||
|
<div class="bg-white rounded-xl shadow-sm overflow-hidden border border-gray-100">
|
||||||
|
<div class="bg-[#2563EB] px-4 py-3 flex justify-between items-center text-white">
|
||||||
|
<span class="font-bold text-[17px] leading-tight" id="detail-awb">781-22222620</span>
|
||||||
|
<div class="flex items-center text-[13px] font-normal opacity-90">
|
||||||
|
<span class="w-2 h-2 bg-green-400 rounded-full mr-1.5"></span>
|
||||||
|
<span id="detail-time">2026-05-10 08:30</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-4">
|
||||||
|
<div class="flex items-center justify-between mb-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="bg-[#EF4444] text-white text-[11px] px-1.5 py-0.5 rounded leading-tight font-medium">国际进港</span>
|
||||||
|
<span class="text-[13px] font-normal text-[#666666] border-l border-gray-300 pl-2">普通货物运输</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-[22px] font-bold text-[#111827] mb-3" id="detail-goods-name">电子元器件</div>
|
||||||
|
<div class="grid grid-cols-2 gap-x-8 gap-y-3">
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">件数</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-count">55</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">重量</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-weight">622.00 kg</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">特码</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-code">NOR</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">代理</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-agent">NOR</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">出运路径</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-route">HFE-PEK-LAX</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">承运人</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-bold" id="detail-carrier">MU</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 移库信息卡片 -->
|
||||||
|
<div class="mt-4 bg-white rounded-xl shadow-sm overflow-hidden border border-gray-200 hidden" id="detail-outbound-card">
|
||||||
|
<div class="bg-[#10B981] px-4 py-2.5">
|
||||||
|
<span class="text-white font-semibold text-[15px]">移库信息</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white px-4 py-3 grid grid-cols-2 gap-y-3">
|
||||||
|
<div class="flex flex-col" id="detail-outbound-person-row">
|
||||||
|
<span class="text-[12px] text-[#9CA3AF] font-normal mb-[2px]">移库人</span>
|
||||||
|
<span class="text-[14px] text-[#1F2937] font-medium" id="detail-outbound-person">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col" id="detail-outbound-time-row">
|
||||||
|
<span class="text-[12px] text-[#9CA3AF] font-normal mb-[2px]">移库时间</span>
|
||||||
|
<span class="text-[14px] text-[#1F2937] font-medium" id="detail-outbound-time">-</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 底部筛选遮罩 -->
|
||||||
|
<div class="overlay absolute inset-0 z-30" id="filter-overlay" onclick="toggleFilterDrawer(false)"></div>
|
||||||
|
|
||||||
|
<!-- 筛选弹窗 -->
|
||||||
|
<div class="absolute bottom-0 w-full bg-white rounded-t-3xl z-50 p-6 shadow-2xl overflow-hidden" id="filter-panel">
|
||||||
|
<div class="relative flex items-center justify-center mb-6">
|
||||||
|
<h2 class="text-[18px] font-bold text-gray-900">筛选条件</h2>
|
||||||
|
<button class="absolute right-0 top-0 text-gray-400" onclick="toggleFilterDrawer(false)">
|
||||||
|
<iconify-icon class="text-2xl" icon="mdi:close"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">承运人</label>
|
||||||
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-3 flex items-center justify-between text-gray-800">
|
||||||
|
<span class="text-sm font-medium">MU</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">运单类型</label>
|
||||||
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-3 flex items-center justify-between text-gray-400">
|
||||||
|
<span class="text-sm">请选择运单类型</span>
|
||||||
|
<iconify-icon icon="mdi:chevron-down"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">特码</label>
|
||||||
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-3 flex items-center justify-between text-gray-400">
|
||||||
|
<span class="text-sm">请选择特码</span>
|
||||||
|
<iconify-icon icon="mdi:chevron-down"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-4 pt-2">
|
||||||
|
<button class="flex-1 bg-white border border-gray-300 text-gray-600 py-3.5 rounded-xl font-bold btn-active" onclick="alert('已重置')">
|
||||||
|
重置
|
||||||
|
</button>
|
||||||
|
<button class="flex-1 bg-[#2563EB] text-white py-3.5 rounded-xl font-bold shadow-lg shadow-blue-500/20 btn-active" onclick="toggleFilterDrawer(false)">
|
||||||
|
确认
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// 页面切换
|
||||||
|
function switchPage(pageId) {
|
||||||
|
document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
|
||||||
|
document.getElementById(pageId).classList.add('active');
|
||||||
|
if(pageId === 'page-detail'){
|
||||||
|
document.querySelector('#page-detail .no-scrollbar').scrollTop = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tab切换
|
||||||
|
function switchTab(type) {
|
||||||
|
const tabPending = document.getElementById('tab-pending');
|
||||||
|
const tabShipped = document.getElementById('tab-shipped');
|
||||||
|
const listPending = document.getElementById('list-pending');
|
||||||
|
const listShipped = document.getElementById('list-shipped');
|
||||||
|
const bottomToolbar = document.getElementById('bottom-toolbar');
|
||||||
|
|
||||||
|
if (type === 'pending') {
|
||||||
|
tabPending.classList.add('text-[#1F2937]', 'border-[#1F2937]');
|
||||||
|
tabPending.classList.remove('text-gray-400', 'border-transparent');
|
||||||
|
tabShipped.classList.add('text-gray-400', 'border-transparent');
|
||||||
|
tabShipped.classList.remove('text-[#1F2937]', 'border-[#1F2937]');
|
||||||
|
|
||||||
|
listPending.classList.remove('hidden');
|
||||||
|
listShipped.classList.add('hidden');
|
||||||
|
bottomToolbar.style.display = 'flex';
|
||||||
|
} else {
|
||||||
|
tabShipped.classList.add('text-[#1F2937]', 'border-[#1F2937]');
|
||||||
|
tabShipped.classList.remove('text-gray-400', 'border-transparent');
|
||||||
|
tabPending.classList.add('text-gray-400', 'border-transparent');
|
||||||
|
tabPending.classList.remove('text-[#1F2937]', 'border-[#1F2937]');
|
||||||
|
|
||||||
|
listShipped.classList.remove('hidden');
|
||||||
|
listPending.classList.add('hidden');
|
||||||
|
bottomToolbar.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全选
|
||||||
|
function toggleSelectAll(checked) {
|
||||||
|
const checkboxes = document.querySelectorAll('.item-checkbox');
|
||||||
|
checkboxes.forEach(cb => {
|
||||||
|
cb.checked = checked;
|
||||||
|
});
|
||||||
|
updateSelectionCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单选
|
||||||
|
function handleCheckboxClick(checkbox, event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
updateSelectionCount();
|
||||||
|
const allBox = document.getElementById('select-all-cb');
|
||||||
|
const all = Array.from(document.querySelectorAll('.item-checkbox')).every(i => i.checked);
|
||||||
|
allBox.checked = all;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新选中数量
|
||||||
|
function updateSelectionCount() {
|
||||||
|
const cnt = document.querySelectorAll('.item-checkbox:checked').length;
|
||||||
|
document.getElementById('selected-count').textContent = cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查看详情
|
||||||
|
function showDetail(data) {
|
||||||
|
if (!data) return;
|
||||||
|
const setText = (id, val) => {
|
||||||
|
const el = document.getElementById(id);
|
||||||
|
if(el) el.textContent = val || '-';
|
||||||
|
};
|
||||||
|
setText('detail-awb', data.id);
|
||||||
|
setText('detail-goods-name', data.goodsName);
|
||||||
|
setText('detail-count', data.pieces);
|
||||||
|
setText('detail-weight', data.weight + (String(data.weight).includes('kg') ? '' : ' kg'));
|
||||||
|
setText('detail-code', data.code);
|
||||||
|
setText('detail-agent', data.agent);
|
||||||
|
setText('detail-carrier', data.carrier);
|
||||||
|
setText('detail-route', data.route || 'HFE-PEK-LAX');
|
||||||
|
setText('detail-location', data.location);
|
||||||
|
|
||||||
|
const outboundCard = document.getElementById('detail-outbound-card');
|
||||||
|
if(data.status === '待移库'){
|
||||||
|
outboundCard.classList.add('hidden');
|
||||||
|
}else{
|
||||||
|
outboundCard.classList.remove('hidden');
|
||||||
|
setText('detail-outbound-person', data.outboundPerson);
|
||||||
|
setText('detail-outbound-time', data.outboundTime);
|
||||||
|
}
|
||||||
|
switchPage('page-detail');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选抽屉
|
||||||
|
function toggleFilterDrawer(show) {
|
||||||
|
const panel = document.getElementById('filter-panel');
|
||||||
|
const overlay = document.getElementById('filter-overlay');
|
||||||
|
if(show){
|
||||||
|
panel.classList.add('show');
|
||||||
|
overlay.classList.add('show');
|
||||||
|
}else{
|
||||||
|
panel.classList.remove('show');
|
||||||
|
overlay.classList.remove('show');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
963
documents/5.5寸手持端设计文件/06_出港查询/出港查询.html
Normal file
963
documents/5.5寸手持端设计文件/06_出港查询/出港查询.html
Normal file
@@ -0,0 +1,963 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||||
|
<title>出港查询</title>
|
||||||
|
<!-- Tailwind CSS (本地) -->
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/tailwindcss.js"></script>
|
||||||
|
<!-- Iconify 图标 -->
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/iconify-icon.min.js"></script>
|
||||||
|
<style>
|
||||||
|
@font-face {
|
||||||
|
font-family: 'PingFang SC';
|
||||||
|
src: local('PingFang SC');
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: 'PingFang SC', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||||
|
background-color: #e5e7eb;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
padding: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
/* 隐藏滚动条但保留功能 */
|
||||||
|
.hide-scrollbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.hide-scrollbar {
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-tag {
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.tag-occupied { background-color: #dcfce7; color: #22c55e; } /* 已离港 - 绿色 */
|
||||||
|
.tag-available { background-color: #dcfce7; color: #22c55e; } /* 已离港 - 绿色 */
|
||||||
|
.tag-repair { background-color: #fce7e7; color: #ef4444; } /* 离港 - 红色 */
|
||||||
|
|
||||||
|
/* 页面切换动画 */
|
||||||
|
.page {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
transition: transform 0.3s ease-in-out;
|
||||||
|
background-color: #f3f4f6;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-y: auto;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
.page::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.page-hidden-right { transform: translateX(100%); }
|
||||||
|
.page-hidden-left { transform: translateX(-100%); }
|
||||||
|
|
||||||
|
|
||||||
|
/* 统一的深蓝色调 */
|
||||||
|
.bg-header-blue { background-color: #2563EB; }
|
||||||
|
|
||||||
|
|
||||||
|
/* 标签页样式 */
|
||||||
|
.tab-item {
|
||||||
|
position: relative;
|
||||||
|
padding: 12px 0;
|
||||||
|
color: #999;
|
||||||
|
font-size: 14px;
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.tab-item.active {
|
||||||
|
color: #2563eb;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.tab-item::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 0;
|
||||||
|
height: 2px;
|
||||||
|
background-color: #2563eb;
|
||||||
|
transition: width 0.3s ease;
|
||||||
|
}
|
||||||
|
.tab-item.active::after {
|
||||||
|
width: 40%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 筛选弹窗样式 提升层级+动画稳定 ========== */
|
||||||
|
.filter-overlay {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background-color: rgba(0,0,0,0.4);
|
||||||
|
z-index: 9999;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
transition: opacity 0.25s ease, visibility 0.25s ease;
|
||||||
|
}
|
||||||
|
.filter-overlay.show {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-sheet {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: #fff;
|
||||||
|
border-top-left-radius: 20px;
|
||||||
|
border-top-right-radius: 20px;
|
||||||
|
padding: 20px;
|
||||||
|
z-index: 10000;
|
||||||
|
transform: translateY(100%);
|
||||||
|
transition: transform 0.25s ease-out;
|
||||||
|
max-height: 80vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.filter-sheet.show {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
/* 筛选输入框统一样式 */
|
||||||
|
.filter-input {
|
||||||
|
width: 100%;
|
||||||
|
height: 40px;
|
||||||
|
padding: 0 12px;
|
||||||
|
background: #f3f4f6;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
outline: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.filter-input:focus {
|
||||||
|
border-color: #2563EB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 下拉框箭头浅灰色 + 全浏览器兼容修复 */
|
||||||
|
select.filter-input {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%239ca3af' viewBox='0 0 16 16'%3E%3Cpath d='M8 11L3 6h10l-5 5z'/%3E%3C/svg%3E");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: right 12px center;
|
||||||
|
background-size: 16px;
|
||||||
|
padding-right: 36px;
|
||||||
|
}
|
||||||
|
/* 清除IE默认下拉箭头 */
|
||||||
|
select.filter-input::-ms-expand {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="w-[375px] h-[812px] bg-[#F3F4F6] overflow-hidden flex flex-col relative shadow-2xl rounded-[40px] border-[8px] border-gray-800">
|
||||||
|
<!-- 状态栏 -->
|
||||||
|
<div class="bg-header-blue flex-none z-50">
|
||||||
|
<div class="flex justify-between items-center px-6 pt-3 pb-1 text-[12px] font-medium text-white">
|
||||||
|
<span>09:41</span>
|
||||||
|
<div class="flex gap-1.5 items-center">
|
||||||
|
<iconify-icon icon="material-symbols:signal-cellular-4-bar-rounded"></iconify-icon>
|
||||||
|
<iconify-icon icon="material-symbols:wifi"></iconify-icon>
|
||||||
|
<iconify-icon icon="material-symbols:battery-full-rounded"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 筛选弹窗容器 移到最外层,层级提升 -->
|
||||||
|
<div class="filter-overlay" id="filterOverlay"></div>
|
||||||
|
<div class="filter-sheet" id="filterSheet">
|
||||||
|
<!-- 顶部标题栏 -->
|
||||||
|
<div class="relative flex items-center justify-center mb-6">
|
||||||
|
<button class="absolute right-0 top-0 text-gray-400" onclick="closeFilter()">
|
||||||
|
<iconify-icon class="text-2xl" icon="mdi:close"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
<h2 class="text-[18px] font-bold text-gray-900">筛选条件</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 筛选表单区域 -->
|
||||||
|
<div class="space-y-4 mb-7">
|
||||||
|
<!-- 1.航班日期 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">航班日期起</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择航班日期" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:calendar" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">航班日期止</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择航班日期" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:calendar" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 2.航班号 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">航班号</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请输入航班号" type="text" id="filterFlightNo">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 3.代理 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">代理</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择代理" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:chevron-down" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 4.特码 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">特码</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择特码" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:chevron-down" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 5.目的港 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">目的港</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请输入目的港" type="text" id="filterOrigin">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 6.运单类型 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">运单类型</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择运单类型" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:chevron-down" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 7.业务类型 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">业务类型</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择业务类型" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:chevron-down" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 8.品名(中) -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">品名(中)</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请输入中文品名" type="text" id="filterCnName">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 底部操作按钮 -->
|
||||||
|
<div class="flex gap-3">
|
||||||
|
<button class="flex-1 h-11 bg-gray-100 text-gray-600 rounded-lg text-sm font-medium" onclick="resetFilter()">重置</button>
|
||||||
|
<button class="flex-1 h-11 bg-[#2563EB] text-white rounded-lg text-sm font-medium" onclick="confirmFilter()">确定</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 页面主容器 -->
|
||||||
|
<div class="flex-1 relative overflow-hidden">
|
||||||
|
<!-- 列表页 -->
|
||||||
|
<div class="page z-10" id="listPage">
|
||||||
|
<!-- 头部 -->
|
||||||
|
<header class="bg-header-blue pt-2 pb-4 px-4 flex items-center relative flex-none">
|
||||||
|
<button class="flex items-center text-white text-sm absolute left-4">
|
||||||
|
<iconify-icon class="text-xl" icon="mdi:chevron-left"></iconify-icon>
|
||||||
|
<span>返回</span>
|
||||||
|
</button>
|
||||||
|
<h1 class="mx-auto text-white font-bold text-lg">出港查询</h1>
|
||||||
|
</header>
|
||||||
|
<!-- 搜索栏 筛选按钮已移除边框 -->
|
||||||
|
<div class="p-3 bg-transparent flex items-center gap-3 border-b border-gray-100 flex-none">
|
||||||
|
<div class="flex-1 bg-white rounded-xl flex items-center px-3 py-[10px] gap-2 border border-gray-50">
|
||||||
|
<iconify-icon class="text-[#9ca3af] text-lg" icon="mdi:magnify"></iconify-icon>
|
||||||
|
<input class="bg-transparent text-[14px] w-full outline-none text-gray-700 placeholder-[#9ca3af]" placeholder="搜索运单号" type="text"/>
|
||||||
|
<iconify-icon class="text-[#2563eb] text-lg" icon="mdi:qrcode-scan" onclick="alert('开启扫码功能')"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
<!-- 筛选按钮 无圆形实线边框 -->
|
||||||
|
<button id="filterBtn" class="w-10 h-10 flex items-center justify-center bg-white rounded-full relative z-[99999]">
|
||||||
|
<iconify-icon class="text-[#2563eb] text-xl" icon="mdi:filter-variant"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- 统计标签 -->
|
||||||
|
<div class="flex items-center gap-2 px-4 pb-3">
|
||||||
|
<div class="flex-1 bg-white rounded-lg px-3 py-2.5 shadow-sm border-l-[4px] border-l-[#2563EB]">
|
||||||
|
<div class="text-[11px] text-gray-500">总票数</div>
|
||||||
|
<div class="text-[22px] font-bold text-[#2563EB] leading-tight mt-0.5">4</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 bg-white rounded-lg px-3 py-2.5 shadow-sm border-l-[4px] border-l-orange-500">
|
||||||
|
<div class="text-[11px] text-gray-500">已入库</div>
|
||||||
|
<div class="text-[22px] font-bold text-orange-500 leading-tight mt-0.5">2</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 bg-white rounded-lg px-3 py-2.5 shadow-sm border-l-[4px] border-l-[#10B981]">
|
||||||
|
<div class="text-[11px] text-gray-500">已离港</div>
|
||||||
|
<div class="text-[22px] font-bold text-[#10B981] leading-tight mt-0.5">2</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- ULD 列表内容 -->
|
||||||
|
<div class="p-3 space-y-3 pb-24 overflow-y-auto hide-scrollbar">
|
||||||
|
<!-- 卡片 1 -->
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-sm active:bg-gray-50 transition-colors border border-gray-50 cursor-pointer" onclick="showDetail('78133363396')">
|
||||||
|
<div class="flex justify-between items-center mb-3">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-blue-500"></div>
|
||||||
|
<span class="font-bold text-[#1a1a1a]">78133363396</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="bg-green-100 text-green-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">已离港</span>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:chevron-right"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-y-2 text-[13px] text-gray-500">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:package-variant-closed"></iconify-icon>
|
||||||
|
<span>件数:444</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:weight-kilogram"></iconify-icon>
|
||||||
|
<span>重量:555</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:account-tie"></iconify-icon>
|
||||||
|
<span>代理人:中外运</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:tag-outline"></iconify-icon>
|
||||||
|
<span>特码:DGR</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片 2 -->
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-sm active:bg-gray-50 transition-colors border border-gray-50 cursor-pointer" onclick="showDetail('78133363397')">
|
||||||
|
<div class="flex justify-between items-center mb-3">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-blue-500"></div>
|
||||||
|
<span class="font-bold text-[#1a1a1a]">78133363397</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="bg-green-100 text-green-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">已离港</span>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:chevron-right"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-y-2 text-[13px] text-gray-500">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:package-variant-closed"></iconify-icon>
|
||||||
|
<span>件数:120</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:weight-kilogram"></iconify-icon>
|
||||||
|
<span>重量:320</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:account-tie"></iconify-icon>
|
||||||
|
<span>代理人:徽远</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:tag-outline"></iconify-icon>
|
||||||
|
<span>特码:PER</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片 3 -->
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-sm active:bg-gray-50 transition-colors border border-gray-50 cursor-pointer" onclick="showDetail('78133363398')">
|
||||||
|
<div class="flex justify-between items-center mb-3">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-blue-500"></div>
|
||||||
|
<span class="font-bold text-[#1a1a1a]">78133363398</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="bg-orange-100 text-orange-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">已入库</span>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:chevron-right"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-y-2 text-[13px] text-gray-500">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:package-variant-closed"></iconify-icon>
|
||||||
|
<span>件数:268</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:weight-kilogram"></iconify-icon>
|
||||||
|
<span>重量:780</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:account-tie"></iconify-icon>
|
||||||
|
<span>代理人:中外运</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:tag-outline"></iconify-icon>
|
||||||
|
<span>特码:NOR</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片 4 -->
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-sm active:bg-gray-50 transition-colors border border-gray-50 cursor-pointer" onclick="showDetail('78133363399')">
|
||||||
|
<div class="flex justify-between items-center mb-3">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-blue-500"></div>
|
||||||
|
<span class="font-bold text-[#1a1a1a]">78133363399</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="bg-green-100 text-green-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">已离港</span>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:chevron-right"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-y-2 text-[13px] text-gray-500">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:package-variant-closed"></iconify-icon>
|
||||||
|
<span>件数:85</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:weight-kilogram"></iconify-icon>
|
||||||
|
<span>重量:210</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:account-tie"></iconify-icon>
|
||||||
|
<span>代理人:徽远</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:tag-outline"></iconify-icon>
|
||||||
|
<span>特码:DGR</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片 5 -->
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-sm active:bg-gray-50 transition-colors border border-gray-50 cursor-pointer" onclick="showDetail('78133363400')">
|
||||||
|
<div class="flex justify-between items-center mb-3">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-blue-500"></div>
|
||||||
|
<span class="font-bold text-[#1a1a1a]">78133363400</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="bg-green-100 text-green-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">已离港</span>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:chevron-right"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-y-2 text-[13px] text-gray-500">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:package-variant-closed"></iconify-icon>
|
||||||
|
<span>件数:350</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:weight-kilogram"></iconify-icon>
|
||||||
|
<span>重量:430</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:account-tie"></iconify-icon>
|
||||||
|
<span>代理人:中外运</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:tag-outline"></iconify-icon>
|
||||||
|
<span>特码:PER</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 详情页 -->
|
||||||
|
<div class="page z-20 page-hidden-right !bg-[#f0f2f5]" id="detailPage">
|
||||||
|
<!-- 头部 -->
|
||||||
|
<header class="bg-header-blue pt-2 pb-4 px-4 flex items-center relative flex-none">
|
||||||
|
<button class="flex items-center text-white text-sm absolute left-4 active:opacity-70" onclick="goBack()">
|
||||||
|
<iconify-icon class="text-xl" icon="mdi:chevron-left"></iconify-icon>
|
||||||
|
<span>返回</span>
|
||||||
|
</button>
|
||||||
|
<h1 class="mx-auto text-white font-bold text-lg">出港详情</h1>
|
||||||
|
<div class="absolute right-4 flex items-center">
|
||||||
|
<iconify-icon class="text-red-500 text-2xl" icon="mdi:file-document-edit-outline"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<!-- 标签页 -->
|
||||||
|
<div class="bg-white px-4 border-b border-gray-200 flex-none">
|
||||||
|
<div class="flex justify-around">
|
||||||
|
<div class="tab-item active cursor-pointer" onclick="switchTab(0)">运单信息</div>
|
||||||
|
<div class="tab-item cursor-pointer" onclick="switchTab(1)">仓库信息</div>
|
||||||
|
<div class="tab-item cursor-pointer" onclick="switchTab(2)">库位信息</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 详情内容区 -->
|
||||||
|
<div class="flex-1 overflow-y-auto hide-scrollbar">
|
||||||
|
<!-- 运单信息标签页 -->
|
||||||
|
<div class="tab-pane p-3 space-y-3" id="tab-content-0">
|
||||||
|
<!-- 卡片1:基本信息 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
||||||
|
<div class="px-4 py-2.5 flex items-center border-b border-gray-100">
|
||||||
|
<div class="w-1 h-4 bg-blue-500 rounded-full inline-block mr-2"></div>
|
||||||
|
<span class="text-xs font-semibold text-gray-800" id="det-uldTitle">基本信息</span>
|
||||||
|
</div>
|
||||||
|
<div class="p-3 grid grid-cols-2 gap-2">
|
||||||
|
<!-- Row 1 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">运单号</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-billNo"></span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">代理人</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-agent"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 2 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">特码</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-code"></span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">承运人</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-carrier"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 3 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">始发站</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-route"></span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">中转站</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-outboundTime"></span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">目的站</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-dest"></span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">UN编号</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-unNo"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 5 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center" id="det-lockStatus-container">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5" id="det-lockStatus-label">锁定状态</span>
|
||||||
|
<div id="det-lockStatus-wrapper">
|
||||||
|
<span class="text-xs font-semibold" id="det-lockStatus"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">包装类型</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-packType"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 6 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">业务类型</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-type"></span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">入库时间</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-outboundTime"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 4 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">运单类型</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-billType"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 7 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center col-span-2">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">品名(中)</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-itemNameCn"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 8 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center col-span-2">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">品名(英)</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-itemNameEn"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 9 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center col-span-2">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">备注</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-remark"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片2:件重信息 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
||||||
|
<div class="px-4 py-2.5 flex items-center border-b border-gray-100">
|
||||||
|
<div class="w-1 h-4 bg-blue-500 rounded-full inline-block mr-2"></div>
|
||||||
|
<span class="text-xs font-semibold text-gray-800">件重信息</span>
|
||||||
|
</div>
|
||||||
|
<div class="p-3 grid grid-cols-3 gap-2">
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">运单件数</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-pieces"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">运单重量</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-weight"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">计费重量</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-calcWeight"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">入库件数</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-inPieces"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">入库重量</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-inWeight"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center opacity-0">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">—</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold">—</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片3:回执信息 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
||||||
|
<div class="px-4 py-2.5 flex items-center border-b border-gray-100">
|
||||||
|
<div class="w-1 h-4 bg-blue-500 rounded-full inline-block mr-2"></div>
|
||||||
|
<span class="text-xs font-semibold text-gray-800">回执信息</span>
|
||||||
|
</div>
|
||||||
|
<div class="p-3 grid grid-cols-3 gap-2">
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">预配舱单</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-originalManifest"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">运抵报告</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-tallyReport"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center" id="det-customsRelease-container">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">海关放行</div>
|
||||||
|
<div id="det-customsRelease-wrapper">
|
||||||
|
<div class="text-xs font-semibold" id="det-customsRelease"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">装载舱单</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-loadManifest"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">理货报告</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-cargoReport"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center opacity-0">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">—</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold">—</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 仓库信息标签页 -->
|
||||||
|
<div class="tab-pane p-3 space-y-3 hidden" id="tab-content-1"></div>
|
||||||
|
<!-- 库位信息标签页 -->
|
||||||
|
<div class="tab-pane p-3 space-y-3 hidden" id="tab-content-2"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const uldData = {
|
||||||
|
'78133363396': {
|
||||||
|
billNo: '78133363396', agent: '中外运', code: 'DGR',
|
||||||
|
pieces: '444', weight: '555.0', type: '普通货物运输',
|
||||||
|
inPieces: '444', inWeight: '555.0', calcWeight: '555.0',
|
||||||
|
carrier: 'CA', route: 'HFE', packType: '纸箱',
|
||||||
|
billType: '国际出港(国际直航)', unNo: '—', dest: 'LAX',
|
||||||
|
itemNameCn: '电子元器件', itemNameEn: 'Electronic Components',
|
||||||
|
lockStatus: '未锁定', outboundTime: '—', remark: '需冷藏存储',
|
||||||
|
originalManifest: '01', tallyReport: '01', customsRelease: '11',
|
||||||
|
warehouse: [
|
||||||
|
{ batch: '1', pieces: 200, weight: 300.0, flightDate: '2026-07-08', flightNo: 'CA1234',route: 'HFE',dest: 'LAX', time: '2026-07-08 14:30:00' },
|
||||||
|
{ batch: '2', pieces: 244, weight: 255.0, flightDate: '2026-07-09', flightNo: 'CA5678',route: 'HFE',dest: 'LAX', time: '2026-07-09 09:10:46' }
|
||||||
|
],
|
||||||
|
locations: [
|
||||||
|
{ id: 'A-01-001', inPerson: '张三', inTime: '2026-07-08 14:30', outPerson: '李四', outTime: '2026-07-09 10:00' },
|
||||||
|
{ id: 'B-02-005', inPerson: '王五', inTime: '2026-07-09 09:10', outPerson: '—', outTime: '—' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'78133363397': {
|
||||||
|
billNo: '78133363397', agent: '徽远', code: 'PER',
|
||||||
|
pieces: '120', weight: '320.0', type: '普通货物运输',
|
||||||
|
inPieces: '120', inWeight: '320.0', calcWeight: '320.0',
|
||||||
|
carrier: 'MU', route: 'PVG-NRT', packType: '托盘',
|
||||||
|
billType: '国际出港(国际直航)', unNo: '—', dest: 'PVG',
|
||||||
|
itemNameCn: '服装', itemNameEn: 'Garments',
|
||||||
|
lockStatus: '未锁定', outboundTime: '—', remark: '易碎品,轻拿轻放',
|
||||||
|
originalManifest: '01', tallyReport: '01', customsRelease: '11',
|
||||||
|
warehouse: [
|
||||||
|
{ batch: '3', pieces: 60, weight: 150.0, flightDate: '2026-07-07', flightNo: 'MU123',route: 'HFE',dest: 'LAX', time: '2026-07-07 16:20:00' },
|
||||||
|
{ batch: '4', pieces: 60, weight: 170.0, flightDate: '2026-07-08', flightNo: 'MU456',route: 'HFE',dest: 'LAX', time: '2026-07-08 11:00:00' }
|
||||||
|
],
|
||||||
|
locations: [
|
||||||
|
{ id: 'A-03-012', inPerson: '赵六', inTime: '2026-07-07 16:20', outPerson: '钱七', outTime: '2026-07-08 14:00' },
|
||||||
|
{ id: 'C-01-008', inPerson: '孙八', inTime: '2026-07-08 11:00', outPerson: '—', outTime: '—' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'78133363398': {
|
||||||
|
billNo: '78133363398', agent: '中外运', code: 'NOR',
|
||||||
|
pieces: '268', weight: '780.0', type: '普通货物运输',
|
||||||
|
inPieces: '268', inWeight: '780.0', calcWeight: '780.0',
|
||||||
|
carrier: 'CZ', route: 'CAN-AMS', packType: '托盘',
|
||||||
|
billType: '国际出港(国际直航)', unNo: '—', dest: 'CAN',
|
||||||
|
itemNameCn: '机械设备', itemNameEn: 'Machinery Equipment',
|
||||||
|
lockStatus: '锁定', outboundTime: '2026-07-09 08:00', remark: '需叉车装卸',
|
||||||
|
originalManifest: '01', tallyReport: '01', customsRelease: '11',
|
||||||
|
warehouse: [
|
||||||
|
{ batch: '5', pieces: 150, weight: 420.0, flightDate: '2026-07-08', flightNo: 'CZ789',route: 'HFE',dest: 'LAX', time: '2026-07-08 22:15:00' },
|
||||||
|
{ batch: '6', pieces: 118, weight: 360.0, flightDate: '2026-07-09', flightNo: 'CZ012',route: 'HFE',dest: 'LAX', time: '2026-07-09 06:30:00' },
|
||||||
|
{ batch: '7', pieces: 100, weight: 200.0, flightDate: '2026-07-09', flightNo: 'CZ345',route: 'HFE',dest: 'LAX', time: '2026-07-09 13:00:00' }
|
||||||
|
],
|
||||||
|
locations: [
|
||||||
|
{ id: 'B-01-003', inPerson: '张三', inTime: '2026-07-08 22:15', outPerson: '李四', outTime: '2026-07-09 06:00' },
|
||||||
|
{ id: 'A-02-010', inPerson: '王五', inTime: '2026-07-09 06:30', outPerson: '—', outTime: '—' },
|
||||||
|
{ id: 'C-03-007', inPerson: '赵六', inTime: '2026-07-09 13:00', outPerson: '—', outTime: '—' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'78133363399': {
|
||||||
|
billNo: '78133363399', agent: '徽远', code: 'DGR',
|
||||||
|
pieces: '85', weight: '210.0', type: '危险品运输',
|
||||||
|
inPieces: '85', inWeight: '210.0', calcWeight: '210.0',
|
||||||
|
carrier: '3U', route: 'CTU-SIN', packType: '铁箱',
|
||||||
|
billType: '国际出港(国际直航)', unNo: 'UN3480', dest: 'CTU',
|
||||||
|
itemNameCn: '锂电池', itemNameEn: 'Lithium Battery',
|
||||||
|
lockStatus: '锁定', outboundTime: '—', remark: '危险品,单独存放',
|
||||||
|
originalManifest: '01', tallyReport: '01', customsRelease: '11',
|
||||||
|
warehouse: [
|
||||||
|
{ batch: '8', pieces: 45, weight: 110.0, flightDate: '2026-07-08', flightNo: '3U678',route: 'HFE',dest: 'LAX', time: '2026-07-08 18:00:00' },
|
||||||
|
{ batch: '9', pieces: 40, weight: 100.0, flightDate: '2026-07-09', flightNo: '3U901',route: 'HFE',dest: 'LAX', time: '2026-07-09 07:45:00' }
|
||||||
|
],
|
||||||
|
locations: [
|
||||||
|
{ id: 'D-01-002', inPerson: '钱七', inTime: '2026-07-08 18:00', outPerson: '孙八', outTime: '2026-07-09 08:00' },
|
||||||
|
{ id: 'A-04-015', inPerson: '张三', inTime: '2026-07-09 07:45', outPerson: '—', outTime: '—' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'78133363400': {
|
||||||
|
billNo: '78133363400', agent: '中外运', code: 'PER',
|
||||||
|
pieces: '350', weight: '430.0', type: '普通货物运输',
|
||||||
|
inPieces: '350', inWeight: '430.0', calcWeight: '430.0',
|
||||||
|
carrier: 'HU', route: 'HKG-HFE', packType: '纸箱',
|
||||||
|
billType: '国际出港(国际直航)', unNo: '—', dest: 'HFE',
|
||||||
|
itemNameCn: '食品', itemNameEn: 'Food Products',
|
||||||
|
lockStatus: '未锁定', outboundTime: '2026-07-09 11:30', remark: '保质期至2026-12',
|
||||||
|
originalManifest: '01', tallyReport: '01', customsRelease: '11',
|
||||||
|
warehouse: [
|
||||||
|
{ batch: '10', pieces: 180, weight: 220.0, flightDate: '2026-07-07', flightNo: 'HU234',route: 'HFE',dest: 'LAX', time: '2026-07-07 20:00:00' },
|
||||||
|
{ batch: '11', pieces: 170, weight: 210.0, flightDate: '2026-07-09', flightNo: 'HU567',route: 'HFE',dest: 'LAX', time: '2026-07-09 10:30:00' }
|
||||||
|
],
|
||||||
|
locations: [
|
||||||
|
{ id: 'B-02-011', inPerson: '李四', inTime: '2026-07-07 20:00', outPerson: '王五', outTime: '2026-07-08 16:00' },
|
||||||
|
{ id: 'C-01-009', inPerson: '赵六', inTime: '2026-07-09 10:30', outPerson: '—', outTime: '—' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 核心修复:等待DOM全部渲染完成后再绑定点击事件,避免获取元素为null
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const filterOverlay = document.getElementById('filterOverlay');
|
||||||
|
const filterSheet = document.getElementById('filterSheet');
|
||||||
|
const filterBtn = document.getElementById('filterBtn');
|
||||||
|
|
||||||
|
// 点击遮罩空白关闭,添加self防止弹窗内部点击穿透关闭
|
||||||
|
filterOverlay.addEventListener('click', function(e) {
|
||||||
|
if (e.target === filterOverlay) {
|
||||||
|
closeFilter();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 筛选按钮点击打开弹窗
|
||||||
|
filterBtn.addEventListener('click', openFilter);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 打开筛选弹窗
|
||||||
|
function openFilter() {
|
||||||
|
const filterOverlay = document.getElementById('filterOverlay');
|
||||||
|
const filterSheet = document.getElementById('filterSheet');
|
||||||
|
filterOverlay.classList.add('show');
|
||||||
|
setTimeout(() => filterSheet.classList.add('show'), 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭筛选弹窗
|
||||||
|
function closeFilter() {
|
||||||
|
const filterOverlay = document.getElementById('filterOverlay');
|
||||||
|
const filterSheet = document.getElementById('filterSheet');
|
||||||
|
filterSheet.classList.remove('show');
|
||||||
|
setTimeout(() => filterOverlay.classList.remove('show'), 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置所有筛选输入框
|
||||||
|
function resetFilter() {
|
||||||
|
document.querySelectorAll('.filter-input').forEach(input => {
|
||||||
|
input.value = '';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确定筛选(模拟查询,可对接后端筛选逻辑)
|
||||||
|
function confirmFilter() {
|
||||||
|
const params = {
|
||||||
|
flightDate: document.getElementById('filterFlightDate').value,
|
||||||
|
flightNo: document.getElementById('filterFlightNo').value,
|
||||||
|
agent: document.getElementById('filterAgent').value,
|
||||||
|
code: document.getElementById('filterCode').value,
|
||||||
|
origin: document.getElementById('filterOrigin').value,
|
||||||
|
billType: document.getElementById('filterBillType').value,
|
||||||
|
bizType: document.getElementById('filterBizType').value,
|
||||||
|
cnName: document.getElementById('filterCnName').value
|
||||||
|
};
|
||||||
|
console.log('筛选参数:', params);
|
||||||
|
alert('筛选执行成功,控制台可查看筛选条件');
|
||||||
|
closeFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showDetail(id) {
|
||||||
|
const listPage = document.getElementById('listPage');
|
||||||
|
const detailPage = document.getElementById('detailPage');
|
||||||
|
|
||||||
|
const data = uldData[id];
|
||||||
|
if (data) {
|
||||||
|
document.getElementById('det-uldTitle').innerText = '基本信息';
|
||||||
|
document.getElementById('det-billNo').innerText = data.billNo;
|
||||||
|
document.getElementById('det-agent').innerText = data.agent;
|
||||||
|
document.getElementById('det-code').innerText = data.code;
|
||||||
|
document.getElementById('det-carrier').innerText = data.carrier;
|
||||||
|
document.getElementById('det-route').innerText = data.route;
|
||||||
|
document.getElementById('det-dest').innerText = data.dest;
|
||||||
|
document.getElementById('det-billType').innerText = data.billType;
|
||||||
|
document.getElementById('det-unNo').innerText = data.unNo;
|
||||||
|
|
||||||
|
// 锁定状态渲染
|
||||||
|
const lockStatusEl = document.getElementById('det-lockStatus');
|
||||||
|
if (data.lockStatus === '锁定') {
|
||||||
|
lockStatusEl.innerHTML = '<iconify-icon icon="mdi:lock" class="mr-1"></iconify-icon>锁定';
|
||||||
|
lockStatusEl.className = 'text-xs font-semibold px-2 py-0.5 rounded-md bg-red-50 text-red-600 inline-flex items-center';
|
||||||
|
} else {
|
||||||
|
lockStatusEl.innerHTML = '—';
|
||||||
|
lockStatusEl.className = 'text-xs font-semibold text-gray-800';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('det-packType').innerText = data.packType;
|
||||||
|
document.getElementById('det-type').innerText = data.type;
|
||||||
|
document.getElementById('det-outboundTime').innerText = data.outboundTime || '—';
|
||||||
|
document.getElementById('det-itemNameCn').innerText = data.itemNameCn || '—';
|
||||||
|
document.getElementById('det-itemNameEn').innerText = data.itemNameEn || '—';
|
||||||
|
document.getElementById('det-remark').innerText = data.remark || '—';
|
||||||
|
|
||||||
|
// 件重信息
|
||||||
|
document.getElementById('det-pieces').innerText = data.pieces;
|
||||||
|
document.getElementById('det-weight').innerText = data.weight;
|
||||||
|
document.getElementById('det-calcWeight').innerText = data.calcWeight;
|
||||||
|
document.getElementById('det-inPieces').innerText = data.inPieces;
|
||||||
|
document.getElementById('det-inWeight').innerText = data.inWeight;
|
||||||
|
|
||||||
|
// 海关放行标签
|
||||||
|
const customsReleaseEl = document.getElementById('det-customsRelease');
|
||||||
|
if (data.customsRelease === '11') {
|
||||||
|
customsReleaseEl.innerText = '11';
|
||||||
|
customsReleaseEl.className = 'text-xs font-semibold px-2 py-0.5 rounded-md bg-green-50 text-green-600 inline-block';
|
||||||
|
} else {
|
||||||
|
customsReleaseEl.innerText = data.customsRelease;
|
||||||
|
customsReleaseEl.className = 'text-xs font-semibold px-2 py-0.5 rounded-md bg-gray-100 text-gray-600 inline-block';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 渲染仓库批次列表
|
||||||
|
const warehouseContainer = document.getElementById('tab-content-1');
|
||||||
|
warehouseContainer.innerHTML = '';
|
||||||
|
data.warehouse.forEach(item => {
|
||||||
|
warehouseContainer.innerHTML += `
|
||||||
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
||||||
|
<div class="flex justify-between items-center pt-3 pb-1.5 px-3 mb-2 border-b border-gray-100">
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<span class="w-1.5 h-1.5 rounded-full bg-blue-500 inline-block"></span>
|
||||||
|
<span class="text-xs font-semibold text-gray-900">批次号: ${item.batch}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-1.5 px-3 pb-2">
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">件数</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${item.pieces}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">重量</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${parseFloat(item.weight).toFixed(1)} kg</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">航班日期</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${item.flightDate}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">航班号</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${item.flightNo}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">始发站</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${item.route}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">目的站</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${item.dest}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 渲染库位信息
|
||||||
|
const locationContainer = document.getElementById('tab-content-2');
|
||||||
|
locationContainer.innerHTML = '';
|
||||||
|
data.locations.forEach(loc => {
|
||||||
|
locationContainer.innerHTML += `
|
||||||
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
||||||
|
<div class="flex justify-between items-center pt-3 pb-1.5 px-3 mb-2 border-b border-gray-100">
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<span class="w-1.5 h-1.5 rounded-full bg-blue-500 inline-block"></span>
|
||||||
|
<span class="text-xs font-bold text-gray-900">${loc.id}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-1.5 px-3 pb-2">
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">入库人</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${loc.inPerson}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">入库时间</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${loc.inTime}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">出库人</div>
|
||||||
|
<div class="text-xs ${loc.outPerson === '—' ? 'text-gray-500 text-[14px]' : 'text-gray-800'} font-semibold">${loc.outPerson}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">出库时间</div>
|
||||||
|
<div class="text-xs ${loc.outTime === '—' ? 'text-gray-500 text-[14px]' : 'text-gray-800'} font-semibold">${loc.outTime}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
switchTab(0);
|
||||||
|
listPage.classList.add('page-hidden-left');
|
||||||
|
detailPage.classList.remove('page-hidden-right');
|
||||||
|
}
|
||||||
|
|
||||||
|
function goBack() {
|
||||||
|
const listPage = document.getElementById('listPage');
|
||||||
|
const detailPage = document.getElementById('detailPage');
|
||||||
|
listPage.classList.remove('page-hidden-left');
|
||||||
|
detailPage.classList.add('page-hidden-right');
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchTab(index) {
|
||||||
|
const tabs = document.querySelectorAll('.tab-item');
|
||||||
|
const contents = document.querySelectorAll('.tab-pane');
|
||||||
|
tabs.forEach((tab, i) => {
|
||||||
|
if (i === index) {
|
||||||
|
tab.classList.add('active');
|
||||||
|
contents[i].classList.remove('hidden');
|
||||||
|
} else {
|
||||||
|
tab.classList.remove('active');
|
||||||
|
contents[i].classList.add('hidden');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索框聚焦监听
|
||||||
|
document.querySelector('input[placeholder="搜索ULD编号"]').addEventListener('focus', () => {
|
||||||
|
console.log('搜索框已激活');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
139
documents/5.5寸手持端设计文件/06_出港查询/运单追踪.html
Normal file
139
documents/5.5寸手持端设计文件/06_出港查询/运单追踪.html
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
|
||||||
|
<title>国际进港查询 - 物流跟踪</title>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/tailwindcss.js"></script>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/iconify-icon.min.js"></script>
|
||||||
|
<style>
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
src: local('sans-serif');
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
|
.no-scrollbar::-webkit-scrollbar { display: none; }
|
||||||
|
.no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
|
||||||
|
|
||||||
|
/* 模拟手机容器阴影 */
|
||||||
|
.phone-shell {
|
||||||
|
box-shadow: 0 50px 100px -20px rgba(0,0,0,0.25), 0 30px 60px -30px rgba(0,0,0,0.3);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="bg-gray-200 flex justify-center items-center min-h-screen p-4">
|
||||||
|
<!-- 模拟手机屏幕容器 -->
|
||||||
|
<div class="phone-shell w-[375px] h-[812px] bg-[#F5F5F7] overflow-hidden flex flex-col relative rounded-[48px] border-[10px] border-gray-900">
|
||||||
|
<!-- 顶部蓝色区域 (包含状态栏和导航栏) -->
|
||||||
|
<div class="bg-[#1A73E8] flex-none">
|
||||||
|
<!-- 系统状态栏模拟 -->
|
||||||
|
<div class="h-11 w-full flex justify-between items-center px-8 text-white">
|
||||||
|
<span class="text-[15px] font-bold">09:41</span>
|
||||||
|
<div class="flex gap-1.5 items-center">
|
||||||
|
<iconify-icon class="text-sm" icon="mdi:signal-cellular-3"></iconify-icon>
|
||||||
|
<iconify-icon class="text-base" icon="mdi:wifi"></iconify-icon>
|
||||||
|
<iconify-icon class="text-xl" icon="mdi:battery"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 导航栏 -->
|
||||||
|
<div class="h-[44px] px-4 flex items-center justify-between">
|
||||||
|
<button class="flex items-center text-white space-x-0.5">
|
||||||
|
<iconify-icon class="text-2xl" icon="mdi:chevron-left"></iconify-icon>
|
||||||
|
<span class="text-base">返回</span>
|
||||||
|
</button>
|
||||||
|
<h1 class="text-lg font-bold text-white absolute left-1/2 -translate-x-1/2">运单追踪</h1>
|
||||||
|
<div class="w-10"></div> <!-- 占位保持平衡 -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 可滚动内容区 -->
|
||||||
|
<div class="flex-1 overflow-y-auto no-scrollbar px-5 pt-6 pb-12">
|
||||||
|
<!-- 流转状态卡片 -->
|
||||||
|
<div class="bg-white rounded-2xl p-5 shadow-sm border border-gray-100/50 mb-5">
|
||||||
|
<!-- 运单号 Header -->
|
||||||
|
<div class="flex items-center justify-between pt-2 pb-5 mb-8 border-b border-gray-100">
|
||||||
|
<div class="text-xl font-black text-gray-900 leading-none tracking-tight">
|
||||||
|
78133358743
|
||||||
|
</div>
|
||||||
|
<span class="text-[11px] font-medium text-blue-600 bg-blue-50 px-2.5 py-1 rounded-full border border-blue-100">国际进港</span>
|
||||||
|
</div>
|
||||||
|
<!-- 流转状态标题 -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<h2 class="text-base font-semibold text-gray-700 flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4 text-gray-700 inline-block" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewbox="0 0 24 24">
|
||||||
|
<circle cx="12" cy="12" r="10"></circle>
|
||||||
|
<polyline points="12 6 12 12 16 14"></polyline>
|
||||||
|
</svg>
|
||||||
|
流转状态
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div class="relative pl-7 pb-2">
|
||||||
|
<div class="absolute left-[9px] top-2 bottom-4 w-[2px] bg-gray-100"></div>
|
||||||
|
<!-- 状态 1: 当前 -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<div class="absolute -left-[27px] top-1 w-[20px] h-[20px] rounded-full bg-green-600 border-4 border-green-100 flex items-center justify-center ring-1 ring-green-600/20">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-white"></div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span class="text-sm font-medium text-green-700">原始舱单</span>
|
||||||
|
<span class="text-green-600 text-xs font-normal bg-green-50 px-2 py-0.5 rounded-full">放行状态:01</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-gray-400 text-xs font-normal flex items-center gap-1.5">
|
||||||
|
<span>2026-07-10 11:03:38</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 状态 2 -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<div class="absolute -left-[22px] top-1.5 w-[10px] h-[10px] rounded-full bg-gray-200 border-2 border-white"></div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm font-bold text-gray-400">分拣理货</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 状态 3 -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<div class="absolute -left-[22px] top-1.5 w-[10px] h-[10px] rounded-full bg-gray-200 border-2 border-white"></div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm font-bold text-gray-400">理货申报</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 状态 4 -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<div class="absolute -left-[22px] top-1.5 w-[10px] h-[10px] rounded-full bg-gray-200 border-2 border-white"></div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm font-bold text-gray-400">海关放行</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 状态 5 -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<div class="absolute -left-[22px] top-1.5 w-[10px] h-[10px] rounded-full bg-gray-200 border-2 border-white"></div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm font-bold text-gray-400">柜台办结</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 状态 6 -->
|
||||||
|
<div class="relative mb-2">
|
||||||
|
<div class="absolute -left-[22px] top-1.5 w-[10px] h-[10px] rounded-full bg-gray-200 border-2 border-white"></div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm font-bold text-gray-400">提取出库</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 模块 4: 操作详情卡片 -> 已删除 -->
|
||||||
|
<!-- 底部占位 -->
|
||||||
|
<div class="text-center py-6">
|
||||||
|
<p class="text-[10px] text-gray-300 uppercase tracking-[0.2em] font-bold">查询信息已触底</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 底部 Home Indicator 模拟 -->
|
||||||
|
<div class="h-8 w-full flex justify-center items-center flex-none bg-white/60 backdrop-blur-md">
|
||||||
|
<div class="w-32 h-1.5 bg-black rounded-full opacity-20"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>ml>
|
||||||
932
documents/5.5寸手持端设计文件/07_出港仓库/出港仓库.html
Normal file
932
documents/5.5寸手持端设计文件/07_出港仓库/出港仓库.html
Normal file
@@ -0,0 +1,932 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||||
|
<title>出港仓库</title>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/tailwindcss.js"></script>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/iconify-icon.min.js"></script>
|
||||||
|
<style>
|
||||||
|
@font-face {
|
||||||
|
font-family: 'PingFang SC';
|
||||||
|
src: local('PingFang SC');
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: 'PingFang SC', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||||
|
background-color: #e5e7eb;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
padding: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
/* 隐藏滚动条但保留功能 */
|
||||||
|
.hide-scrollbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.hide-scrollbar {
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-tag {
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.tag-occupied { background-color: #dcfce7; color: #22c55e; } /* 已离港 - 绿色 */
|
||||||
|
.tag-available { background-color: #dcfce7; color: #22c55e; } /* 已离港 - 绿色 */
|
||||||
|
.tag-repair { background-color: #fce7e7; color: #ef4444; } /* 离港 - 红色 */
|
||||||
|
|
||||||
|
/* 页面切换动画 */
|
||||||
|
.page {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
transition: transform 0.3s ease-in-out;
|
||||||
|
background-color: #f3f4f6;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-y: auto;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
.page::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.page-hidden-right { transform: translateX(100%); }
|
||||||
|
.page-hidden-left { transform: translateX(-100%); }
|
||||||
|
|
||||||
|
|
||||||
|
/* 统一的深蓝色调 */
|
||||||
|
.bg-header-blue { background-color: #2563EB; }
|
||||||
|
|
||||||
|
|
||||||
|
/* 标签页样式 */
|
||||||
|
.tab-item {
|
||||||
|
position: relative;
|
||||||
|
padding: 12px 0;
|
||||||
|
color: #999;
|
||||||
|
font-size: 14px;
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.tab-item.active {
|
||||||
|
color: #2563eb;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.tab-item::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 0;
|
||||||
|
height: 2px;
|
||||||
|
background-color: #2563eb;
|
||||||
|
transition: width 0.3s ease;
|
||||||
|
}
|
||||||
|
.tab-item.active::after {
|
||||||
|
width: 40%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 筛选弹窗样式 提升层级+动画稳定 ========== */
|
||||||
|
.filter-overlay {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background-color: rgba(0,0,0,0.4);
|
||||||
|
z-index: 9999;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
transition: opacity 0.25s ease, visibility 0.25s ease;
|
||||||
|
}
|
||||||
|
.filter-overlay.show {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-sheet {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: #fff;
|
||||||
|
border-top-left-radius: 20px;
|
||||||
|
border-top-right-radius: 20px;
|
||||||
|
padding: 20px;
|
||||||
|
z-index: 10000;
|
||||||
|
transform: translateY(100%);
|
||||||
|
transition: transform 0.25s ease-out;
|
||||||
|
max-height: 80vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.filter-sheet.show {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
/* 筛选输入框统一样式 */
|
||||||
|
.filter-input {
|
||||||
|
width: 100%;
|
||||||
|
height: 40px;
|
||||||
|
padding: 0 12px;
|
||||||
|
background: #f3f4f6;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
outline: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.filter-input:focus {
|
||||||
|
border-color: #2563EB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 下拉框箭头浅灰色 + 全浏览器兼容修复 */
|
||||||
|
select.filter-input {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%239ca3af' viewBox='0 0 16 16'%3E%3Cpath d='M8 11L3 6h10l-5 5z'/%3E%3C/svg%3E");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: right 12px center;
|
||||||
|
background-size: 16px;
|
||||||
|
padding-right: 36px;
|
||||||
|
}
|
||||||
|
/* 清除IE默认下拉箭头 */
|
||||||
|
select.filter-input::-ms-expand {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes scan {
|
||||||
|
0% { top: 0; }
|
||||||
|
100% { top: 100%; }
|
||||||
|
}
|
||||||
|
.scan-line {
|
||||||
|
animation: scan 2s linear infinite;
|
||||||
|
}
|
||||||
|
.custom-scrollbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.bottom-drawer {
|
||||||
|
transition: transform 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="w-[375px] h-[812px] bg-[#F3F4F6] overflow-hidden flex flex-col relative shadow-2xl rounded-[40px] border-[8px] border-gray-800">
|
||||||
|
<!-- 状态栏 -->
|
||||||
|
<div class="h-6 w-full bg-[#2563EB] flex justify-between items-center px-6 text-white text-xs pt-1">
|
||||||
|
<span>09:41</span>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<iconify-icon icon="material-symbols:signal-cellular-4-bar-rounded"></iconify-icon>
|
||||||
|
<iconify-icon icon="material-symbols:wifi"></iconify-icon>
|
||||||
|
<iconify-icon icon="material-symbols:battery-full-rounded"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 筛选弹窗容器 移到最外层,层级提升 -->
|
||||||
|
<div class="filter-overlay" id="filterOverlay"></div>
|
||||||
|
<div class="filter-sheet" id="filterSheet">
|
||||||
|
<!-- 顶部标题栏 -->
|
||||||
|
<div class="relative flex items-center justify-center mb-6">
|
||||||
|
<button class="absolute right-0 top-0 text-gray-400" onclick="closeFilter()">
|
||||||
|
<iconify-icon class="text-2xl" icon="mdi:close"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
<h2 class="text-[18px] font-bold text-gray-900">筛选条件</h2>
|
||||||
|
</div>
|
||||||
|
<!-- 筛选表单区域 -->
|
||||||
|
<div class="space-y-4 mb-7">
|
||||||
|
<!-- 1.航班日期 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">航班日期</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择航班日期" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:calendar" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 2.航班号 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">航班号</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请输入航班号" type="text" id="filterFlightNo">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 3.代理 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">代理</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择代理" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:chevron-down" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 4.特码 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">特码</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择特码" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:chevron-down" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 5.目的站 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">目的站</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请输入目的站" type="text" id="filterOrigin">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 6.运单类型 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">运单类型</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择运单类型" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:chevron-down" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 7.业务类型 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">业务类型</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择业务类型" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:chevron-down" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 8.品名(中) -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">品名(中)</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请输入中文品名" type="text" id="filterCnName">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 底部操作按钮 -->
|
||||||
|
<div class="flex gap-3">
|
||||||
|
<button class="flex-1 h-11 bg-gray-100 text-gray-600 rounded-lg text-sm font-medium" onclick="resetFilter()">重置</button>
|
||||||
|
<button class="flex-1 h-11 bg-[#2563EB] text-white rounded-lg text-sm font-medium" onclick="confirmFilter()">确定</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 页面主容器 -->
|
||||||
|
<div class="flex-1 relative overflow-hidden">
|
||||||
|
<!-- 列表首页:出港仓库卡片页面 -->
|
||||||
|
<div class="page z-10" id="listPage">
|
||||||
|
<!-- 顶部导航栏 -->
|
||||||
|
<header class="bg-[#2563EB] h-14 flex items-center justify-between px-4 flex-none">
|
||||||
|
<button class="flex items-center text-white text-sm" onclick="showToast('返回上一级')">
|
||||||
|
<iconify-icon class="text-2xl" icon="mdi:chevron-left"></iconify-icon>
|
||||||
|
<span>返回</span>
|
||||||
|
</button>
|
||||||
|
<h1 class="text-white font-bold text-lg">出港仓库</h1>
|
||||||
|
<div class="w-12"></div>
|
||||||
|
</header>
|
||||||
|
<!-- 搜索区 -->
|
||||||
|
<section class="bg-[#F3F4F6] p-3 flex-none">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="flex-1 relative">
|
||||||
|
<iconify-icon class="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 text-lg" icon="mdi:magnify"></iconify-icon>
|
||||||
|
<input class="w-full bg-white rounded-full pl-10 pr-10 py-2.5 text-sm shadow-sm border border-gray-200 outline-none" onkeypress="if(event.keyCode==13) showToast('执行搜索')" placeholder="搜索运单号" type="text"/>
|
||||||
|
<button class="absolute right-2 top-1/2 -translate-y-1/2 p-1 text-[#2563EB]" onclick="toggleScanOverlay(true)">
|
||||||
|
<iconify-icon class="text-lg" icon="mdi:qrcode-scan"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button id="filterBtn" class="bg-white p-2.5 rounded-full shadow-sm border border-gray-200 text-[#2563EB] flex items-center justify-center flex-none" onclick="openFilter()">
|
||||||
|
<iconify-icon class="text-xl" icon="mdi:filter-variant"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- 统计栏 -->
|
||||||
|
<section class="px-3 pb-3 flex justify-between gap-2 flex-none">
|
||||||
|
<div class="flex-1 bg-white rounded-lg px-3 py-2.5 shadow-sm border-l-[4px] border-l-[#2563EB]">
|
||||||
|
<div class="text-[11px] text-gray-500">总票数</div>
|
||||||
|
<div class="text-lg font-bold text-[#2563EB]">8</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 bg-white rounded-lg px-3 py-2.5 shadow-sm border-l-[4px] border-l-orange-500">
|
||||||
|
<div class="text-[11px] text-gray-500">未清仓</div>
|
||||||
|
<div class="text-lg font-bold text-orange-500">4</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 bg-white rounded-lg px-3 py-2.5 shadow-sm border-l-[4px] border-l-[#10B981]">
|
||||||
|
<div class="text-[11px] text-gray-500">已清仓</div>
|
||||||
|
<div class="text-lg font-bold text-[#10B981]">4</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- 卡片列表容器 -->
|
||||||
|
<main class="flex-1 overflow-y-auto px-3 pb-4 custom-scrollbar" id="cardListContainer">
|
||||||
|
</main>
|
||||||
|
<!-- 扫码层 -->
|
||||||
|
<div class="absolute inset-0 z-50 bg-black hidden flex flex-col" id="scanOverlay">
|
||||||
|
<div class="p-6 flex justify-between items-center text-white">
|
||||||
|
<button onclick="toggleScanOverlay(false)">
|
||||||
|
<iconify-icon class="text-2xl" icon="mdi:close"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
<span class="text-sm font-medium">扫描运单条码</span>
|
||||||
|
<button><iconify-icon class="text-2xl" icon="mdi:flashlight"></iconify-icon></button>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 flex flex-col items-center justify-center p-12">
|
||||||
|
<div class="w-64 h-64 border-2 border-[#2563EB] relative overflow-hidden rounded-lg">
|
||||||
|
<div class="absolute top-0 left-0 w-full h-0.5 bg-[#2563EB] shadow-[0_0_10px_#2563EB] scan-line"></div>
|
||||||
|
<div class="absolute top-0 left-0 w-6 h-6 border-t-4 border-l-4 border-[#2563EB]"></div>
|
||||||
|
<div class="absolute top-0 right-0 w-6 h-6 border-t-4 border-r-4 border-[#2563EB]"></div>
|
||||||
|
<div class="absolute bottom-0 left-0 w-6 h-6 border-b-4 border-l-4 border-[#2563EB]"></div>
|
||||||
|
<div class="absolute bottom-0 right-0 w-6 h-6 border-b-4 border-r-4 border-[#2563EB]"></div>
|
||||||
|
</div>
|
||||||
|
<p class="text-white text-xs mt-6 opacity-60 text-center px-4">将条码/二维码放入框内,即可自动扫描</p>
|
||||||
|
</div>
|
||||||
|
<div class="h-32 bg-black flex justify-center items-center gap-12 text-white">
|
||||||
|
<div class="flex flex-col items-center opacity-60">
|
||||||
|
<iconify-icon class="text-3xl" icon="mdi:image-outline"></iconify-icon>
|
||||||
|
<span class="text-[10px] mt-1">相册</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<iconify-icon class="text-3xl" icon="mdi:keyboard-outline"></iconify-icon>
|
||||||
|
<span class="text-[10px] mt-1">手动输入</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Toast -->
|
||||||
|
<div class="absolute bottom-20 left-1/2 -translate-x-1/2 bg-black bg-opacity-80 text-white text-xs px-4 py-2 rounded-full hidden z-[60] whitespace-nowrap" id="toast">提示内容</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 出港货物页面(右滑弹出) -->
|
||||||
|
<div class="page z-20 page-hidden-right !bg-[#f0f2f5]" id="detailPage">
|
||||||
|
<!-- 头部 -->
|
||||||
|
<header class="bg-header-blue pt-2 pb-4 px-4 flex items-center relative flex-none">
|
||||||
|
<button class="flex items-center text-white text-sm absolute left-4 active:opacity-70" onclick="goBack()">
|
||||||
|
<iconify-icon class="text-xl" icon="mdi:chevron-left"></iconify-icon>
|
||||||
|
<span>返回</span>
|
||||||
|
</button>
|
||||||
|
<h1 class="mx-auto text-white font-bold text-lg">出港货物</h1>
|
||||||
|
<div class="absolute right-4 flex items-center">
|
||||||
|
<iconify-icon class="text-red-500 text-2xl" icon="mdi:file-document-edit-outline"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<!-- 标签页 -->
|
||||||
|
<div class="bg-white px-4 border-b border-gray-200 flex-none">
|
||||||
|
<div class="flex justify-around">
|
||||||
|
<div class="tab-item active cursor-pointer" onclick="switchTab(0)">运单信息</div>
|
||||||
|
<div class="tab-item cursor-pointer" onclick="switchTab(1)">仓库信息</div>
|
||||||
|
<div class="tab-item cursor-pointer" onclick="switchTab(2)">库位信息</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 详情内容区 -->
|
||||||
|
<div class="flex-1 overflow-y-auto hide-scrollbar">
|
||||||
|
<!-- 运单信息标签页 -->
|
||||||
|
<div class="tab-pane p-3 space-y-3" id="tab-content-0">
|
||||||
|
<!-- 卡片1:基本信息 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
||||||
|
<div class="px-4 py-2.5 flex items-center border-b border-gray-100">
|
||||||
|
<div class="w-1 h-4 bg-blue-500 rounded-full inline-block mr-2"></div>
|
||||||
|
<span class="text-xs font-semibold text-gray-800" id="det-uldTitle">基本信息</span>
|
||||||
|
</div>
|
||||||
|
<div class="p-3 grid grid-cols-2 gap-2">
|
||||||
|
<!-- Row 1 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">运单号</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-billNo"></span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">代理人</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-agent"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 2 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">特码</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-code"></span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">承运人</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-carrier"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 3 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">始发站</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-route"></span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">中转站</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-outboundTime"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 4 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">目的站</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-dest"></span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">UN编号</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-unNo"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 5 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center" id="det-lockStatus-container">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5" id="det-lockStatus-label">锁定状态</span>
|
||||||
|
<div id="det-lockStatus-wrapper">
|
||||||
|
<span class="text-xs font-semibold" id="det-lockStatus"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">包装类型</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-packType"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 6 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">业务类型</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-type"></span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">入库时间</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-ciTime"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 7 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center col-span-2">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">运单类型</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-billType"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 8 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center col-span-2">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">品名(中)</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-itemNameCn"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 9 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center col-span-2">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">品名(英)</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-itemNameEn"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 10 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center col-span-2">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">备注</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-remark"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片2:件重信息 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
||||||
|
<div class="px-4 py-2.5 flex items-center border-b border-gray-100">
|
||||||
|
<div class="w-1 h-4 bg-blue-500 rounded-full inline-block mr-2"></div>
|
||||||
|
<span class="text-xs font-semibold text-gray-800">件重信息</span>
|
||||||
|
</div>
|
||||||
|
<div class="p-3 grid grid-cols-3 gap-2">
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">运单件数</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-pieces"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">运单重量</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-weight"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">计费重量</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-calcWeight"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">入库件数</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-inPieces"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">入库重量</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-inWeight"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center opacity-0">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">—</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold">—</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片3:回执信息 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
||||||
|
<div class="px-4 py-2.5 flex items-center border-b border-gray-100">
|
||||||
|
<div class="w-1 h-4 bg-blue-500 rounded-full inline-block mr-2"></div>
|
||||||
|
<span class="text-xs font-semibold text-gray-800">回执信息</span>
|
||||||
|
</div>
|
||||||
|
<div class="p-3 grid grid-cols-3 gap-2">
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">预配舱单</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-originalManifest"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">运抵报告</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-arriReport"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center" id="det-customsRelease-container">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">海关放行</div>
|
||||||
|
<div id="det-customsRelease-wrapper">
|
||||||
|
<div class="text-xs font-semibold" id="det-customsRelease"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">装载舱单</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-mftReport"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">理货报告</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-tallyReport"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 仓库信息标签页 -->
|
||||||
|
<div class="tab-pane p-3 space-y-3 hidden" id="tab-content-1"></div>
|
||||||
|
<!-- 库位信息标签页 -->
|
||||||
|
<div class="tab-pane p-3 space-y-3 hidden" id="tab-content-2"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// 运单详情数据源(用于出港货物渲染)
|
||||||
|
const uldData = {
|
||||||
|
'78133363396': {
|
||||||
|
billNo: '78133363396', agent: '中外运', code: 'DGR',
|
||||||
|
pieces: '444', weight: '555.0', type: '普通货物运输',
|
||||||
|
inPieces: '444', inWeight: '555.0', calcWeight: '555.0',
|
||||||
|
carrier: 'CA', route: 'HFE', packType: '纸箱',
|
||||||
|
billType: '国际进港(国际直航)', unNo: '—', dest: 'LAX',
|
||||||
|
itemNameCn: '电子元器件', itemNameEn: 'Electronic Components',
|
||||||
|
lockStatus: '未锁定', outboundTime: '—', remark: '需冷藏存储',
|
||||||
|
originalManifest: '01', tallyReport: '01', customsRelease: '11',ciTime: '2026-07-08 14:30:00',arriReport: '01',mftReport: '01',
|
||||||
|
warehouse: [
|
||||||
|
{ batch: '1', pieces: 200, weight: 300.0, flightDate: '2026-07-08', flightNo: 'CA1234',route: 'HFE',dest: 'LAX', time: '2026-07-08 14:30:00' },
|
||||||
|
{ batch: '2', pieces: 244, weight: 255.0, flightDate: '2026-07-09', flightNo: 'CA5678',route: 'HFE',dest: 'LAX', time: '2026-07-09 09:10:46' }
|
||||||
|
],
|
||||||
|
locations: [
|
||||||
|
{ id: 'A-01-001', inPerson: '张三', inTime: '2026-07-08 14:30', outPerson: '李四', outTime: '2026-07-09 10:00' },
|
||||||
|
{ id: 'B-02-005', inPerson: '王五', inTime: '2026-07-09 09:10', outPerson: '—', outTime: '—' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'78133363397': {
|
||||||
|
billNo: '78133363397', agent: '徽远', code: 'PER',
|
||||||
|
pieces: '120', weight: '320.0', type: '普通货物运输',
|
||||||
|
inPieces: '120', inWeight: '320.0', calcWeight: '320.0',
|
||||||
|
carrier: 'MU', route: 'PVG-NRT', packType: '托盘',
|
||||||
|
billType: '国际进港(国际直航)', unNo: '—', dest: 'PVG',
|
||||||
|
itemNameCn: '服装', itemNameEn: 'Garments',
|
||||||
|
lockStatus: '未锁定', outboundTime: '—', remark: '易碎品,轻拿轻放',
|
||||||
|
originalManifest: '01', tallyReport: '01', customsRelease: '11',ciTime: '2026-07-08 14:30:00',arriReport: '01',mftReport: '01',
|
||||||
|
warehouse: [
|
||||||
|
{ batch: '3', pieces: 60, weight: 150.0, flightDate: '2026-07-07', flightNo: 'MU123', time: '2026-07-07 16:20:00' },
|
||||||
|
{ batch: '4', pieces: 60, weight: 170.0, flightDate: '2026-07-08', flightNo: 'MU456', time: '2026-07-08 11:00:00' }
|
||||||
|
],
|
||||||
|
locations: [
|
||||||
|
{ id: 'A-03-012', inPerson: '赵六', inTime: '2026-07-07 16:20', outPerson: '钱七', outTime: '2026-07-08 14:00' },
|
||||||
|
{ id: 'C-01-008', inPerson: '孙八', inTime: '2026-07-08 11:00', outPerson: '—', outTime: '—' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'78133363398': {
|
||||||
|
billNo: '78133363398', agent: '中外运', code: 'NOR',
|
||||||
|
pieces: '268', weight: '780.0', type: '普通货物运输',
|
||||||
|
inPieces: '268', inWeight: '780.0', calcWeight: '780.0',
|
||||||
|
carrier: 'CZ', route: 'CAN-AMS', packType: '托盘',
|
||||||
|
billType: '国际进港(国际直航)', unNo: '—', dest: 'CAN',
|
||||||
|
itemNameCn: '机械设备', itemNameEn: 'Machinery Equipment',
|
||||||
|
lockStatus: '锁定', outboundTime: '2026-07-09 08:00', remark: '需叉车装卸',
|
||||||
|
originalManifest: '01', tallyReport: '01', customsRelease: '11',ciTime: '2026-07-08 14:30:00',arriReport: '01',mftReport: '01',
|
||||||
|
warehouse: [
|
||||||
|
{ batch: '5', pieces: 150, weight: 420.0, flightDate: '2026-07-08', flightNo: 'CZ789', time: '2026-07-08 22:15:00' },
|
||||||
|
{ batch: '6', pieces: 118, weight: 360.0, flightDate: '2026-07-09', flightNo: 'CZ012', time: '2026-07-09 06:30:00' },
|
||||||
|
{ batch: '7', pieces: 100, weight: 200.0, flightDate: '2026-07-09', flightNo: 'CZ345', time: '2026-07-09 13:00:00' }
|
||||||
|
],
|
||||||
|
locations: [
|
||||||
|
{ id: 'B-01-003', inPerson: '张三', inTime: '2026-07-08 22:15', outPerson: '李四', outTime: '2026-07-09 06:00' },
|
||||||
|
{ id: 'A-02-010', inPerson: '王五', inTime: '2026-07-09 06:30', outPerson: '—', outTime: '—' },
|
||||||
|
{ id: 'C-03-007', inPerson: '赵六', inTime: '2026-07-09 13:00', outPerson: '—', outTime: '—' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'78133363399': {
|
||||||
|
billNo: '78133363399', agent: '徽远', code: 'DGR',
|
||||||
|
pieces: '85', weight: '210.0', type: '危险品运输',
|
||||||
|
inPieces: '85', inWeight: '210.0', calcWeight: '210.0',
|
||||||
|
carrier: '3U', route: 'CTU-SIN', packType: '铁箱',
|
||||||
|
billType: '国际进港(国际直航)', unNo: 'UN3480', dest: 'CTU',
|
||||||
|
itemNameCn: '锂电池', itemNameEn: 'Lithium Battery',
|
||||||
|
lockStatus: '锁定', outboundTime: '—', remark: '危险品,单独存放',
|
||||||
|
originalManifest: '01', tallyReport: '01', customsRelease: '11',ciTime: '2026-07-08 14:30:00',arriReport: '01',mftReport: '01',
|
||||||
|
warehouse: [
|
||||||
|
{ batch: '8', pieces: 45, weight: 110.0, flightDate: '2026-07-08', flightNo: '3U678', time: '2026-07-08 18:00:00' },
|
||||||
|
{ batch: '9', pieces: 40, weight: 100.0, flightDate: '2026-07-09', flightNo: '3U901', time: '2026-07-09 07:45:00' }
|
||||||
|
],
|
||||||
|
locations: [
|
||||||
|
{ id: 'D-01-002', inPerson: '钱七', inTime: '2026-07-08 18:00', outPerson: '孙八', outTime: '2026-07-09 08:00' },
|
||||||
|
{ id: 'A-04-015', inPerson: '张三', inTime: '2026-07-09 07:45', outPerson: '—', outTime: '—' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'78133363400': {
|
||||||
|
billNo: '78133363400', agent: '中外运', code: 'PER',
|
||||||
|
pieces: '350', weight: '430.0', type: '普通货物运输',
|
||||||
|
inPieces: '350', inWeight: '430.0', calcWeight: '430.0',
|
||||||
|
carrier: 'HU', route: 'HKG-LAX', packType: '纸箱',
|
||||||
|
billType: '国际进港(国际直航)', unNo: '—', dest: 'LAX',
|
||||||
|
itemNameCn: '食品', itemNameEn: 'Food Products',
|
||||||
|
lockStatus: '未锁定', outboundTime: '2026-07-09 11:30', remark: '保质期至2026-12',
|
||||||
|
originalManifest: '01', tallyReport: '01', customsRelease: '11',ciTime: '2026-07-08 14:30:00',arriReport: '01',mftReport: '01',
|
||||||
|
warehouse: [
|
||||||
|
{ batch: '10', pieces: 180, weight: 220.0, flightDate: '2026-07-07', flightNo: 'HU234', time: '2026-07-07 20:00:00' },
|
||||||
|
{ batch: '11', pieces: 170, weight: 210.0, flightDate: '2026-07-09', flightNo: 'HU567', time: '2026-07-09 10:30:00' }
|
||||||
|
],
|
||||||
|
locations: [
|
||||||
|
{ id: 'B-02-011', inPerson: '李四', inTime: '2026-07-07 20:00', outPerson: '王五', outTime: '2026-07-08 16:00' },
|
||||||
|
{ id: 'C-01-009', inPerson: '赵六', inTime: '2026-07-09 10:30', outPerson: '—', outTime: '—' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 出港仓库卡片列表数据源
|
||||||
|
const data = [
|
||||||
|
{ id: "78133363396", status: "已清仓", flight: "20260702/MU1111", route: "HFE-LAX", pcs: 111, weight: 2300 },
|
||||||
|
{ id: "78133363397", status: "未清仓", flight: "20260702/MU2222", route: "NRT-LAX", pcs: 85, weight: 1560 },
|
||||||
|
{ id: "78133363398", status: "已清仓", flight: "20260702/MU3333", route: "FRA-LAX", pcs: 200, weight: 4200 },
|
||||||
|
{ id: "78133363399", status: "未清仓", flight: "20260702/MU4444", route: "HFE-PVG", pcs: 50, weight: 980 },
|
||||||
|
{ id: "78133363400", status: "未清仓", flight: "20260702/MU5555", route: "CDG-LAX", pcs: 168, weight: 3150 },
|
||||||
|
{ id: "78133363401", status: "已清仓", flight: "20260702/MU6666", route: "SIN-LAX", pcs: 92, weight: 1800 },
|
||||||
|
{ id: "78133363402", status: "未清仓", flight: "20260702/MU7777", route: "HFE-HFE", pcs: 145, weight: 2800 },
|
||||||
|
{ id: "78133363403", status: "已清仓", flight: "20260702/MU8888", route: "HND-LAX", pcs: 73, weight: 1420 }
|
||||||
|
];
|
||||||
|
|
||||||
|
// 渲染仓库卡片列表
|
||||||
|
function renderList() {
|
||||||
|
const container = document.getElementById('cardListContainer');
|
||||||
|
container.innerHTML = data.map((item) => {
|
||||||
|
const isCleared = item.status === '已清仓';
|
||||||
|
const departure = item.route.split('-')[0];
|
||||||
|
const flightNo = item.flight.split('/')[1];
|
||||||
|
return `
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-sm active:bg-gray-50 transition-colors border border-gray-50 cursor-pointer mb-3" onclick="showDetail('${item.id}')">
|
||||||
|
<div class="flex justify-between items-center mb-3">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-blue-500"></div>
|
||||||
|
<span class="font-bold text-[#1a1a1a]">${item.id}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
${getStatusTag(item.status)}
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:chevron-right"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 gap-y-2 text-[13px] text-gray-500">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:package-variant-closed"></iconify-icon>
|
||||||
|
<span>件数:${item.pcs}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:weight-kilogram"></iconify-icon>
|
||||||
|
<span>重量:${item.weight}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:airplane"></iconify-icon>
|
||||||
|
<span>航班号:${flightNo}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:map-marker"></iconify-icon>
|
||||||
|
<span>目的站:${departure}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-4 gap-2 mt-3">
|
||||||
|
<button onclick="event.stopPropagation(); showToast('执行清仓操作:运单号 ${item.id}')"
|
||||||
|
class="text-xs py-1.5 px-2 rounded-[6px] font-medium h-8 ${isCleared ? 'bg-gray-100 text-gray-400 cursor-not-allowed' : 'bg-[#EFF6FF] text-[#2563EB]'}" ${isCleared ? 'disabled' : ''}>
|
||||||
|
清仓
|
||||||
|
</button>
|
||||||
|
<button onclick="event.stopPropagation(); showToast('修改库位:运单号 ${item.id}')"
|
||||||
|
class="bg-[#EFF6FF] text-[#2563EB] text-xs py-1.5 px-2 rounded-[6px] font-medium h-8">
|
||||||
|
修改库位
|
||||||
|
</button>
|
||||||
|
<button onclick="event.stopPropagation(); showToast('执行出库:运单号 ${item.id}')"
|
||||||
|
class="bg-[#EFF6FF] text-[#2563EB] text-xs py-1.5 px-2 rounded-[6px] font-medium h-8">
|
||||||
|
出库
|
||||||
|
</button>
|
||||||
|
<button onclick="event.stopPropagation(); showToast('执行入库:运单号 ${item.id}')"
|
||||||
|
class="bg-[#EFF6FF] text-[#2563EB] text-xs py-1.5 px-2 rounded-[6px] font-medium h-8">
|
||||||
|
入库
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 状态标签渲染
|
||||||
|
function getStatusTag(status) {
|
||||||
|
let color = '';
|
||||||
|
switch(status) {
|
||||||
|
case '已清仓': color = 'bg-green-100 text-green-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium'; break;
|
||||||
|
case '未清仓': color = 'bg-orange-100 text-orange-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium'; break;
|
||||||
|
}
|
||||||
|
return `<span class="${color}">${status}</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 跳转至出港货物页面,填充数据
|
||||||
|
function showDetail(id) {
|
||||||
|
const listPage = document.getElementById('listPage');
|
||||||
|
const detailPage = document.getElementById('detailPage');
|
||||||
|
|
||||||
|
const data = uldData[id];
|
||||||
|
if (!data) {
|
||||||
|
showToast("暂无该运单详情数据");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 填充基础信息
|
||||||
|
document.getElementById('det-billNo').innerText = data.billNo;
|
||||||
|
document.getElementById('det-agent').innerText = data.agent;
|
||||||
|
document.getElementById('det-code').innerText = data.code;
|
||||||
|
document.getElementById('det-carrier').innerText = data.carrier;
|
||||||
|
document.getElementById('det-route').innerText = data.route;
|
||||||
|
document.getElementById('det-dest').innerText = data.dest;
|
||||||
|
document.getElementById('det-billType').innerText = data.billType;
|
||||||
|
document.getElementById('det-unNo').innerText = data.unNo;
|
||||||
|
document.getElementById('det-ciTime').innerText = data.ciTime;
|
||||||
|
// 锁定状态样式
|
||||||
|
const lockStatusEl = document.getElementById('det-lockStatus');
|
||||||
|
if (data.lockStatus === '锁定') {
|
||||||
|
lockStatusEl.innerHTML = '<iconify-icon icon="mdi:lock" class="mr-1"></iconify-icon>锁定';
|
||||||
|
lockStatusEl.className = 'text-xs font-semibold px-2 py-0.5 rounded-md bg-red-50 text-red-600 inline-flex items-center';
|
||||||
|
} else {
|
||||||
|
lockStatusEl.innerText = '—';
|
||||||
|
lockStatusEl.className = 'text-xs font-semibold text-gray-800';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('det-packType').innerText = data.packType;
|
||||||
|
document.getElementById('det-type').innerText = data.type;
|
||||||
|
document.getElementById('det-outboundTime').innerText = data.outboundTime || '—';
|
||||||
|
document.getElementById('det-itemNameCn').innerText = data.itemNameCn || '—';
|
||||||
|
document.getElementById('det-itemNameEn').innerText = data.itemNameEn || '—';
|
||||||
|
document.getElementById('det-remark').innerText = data.remark || '—';
|
||||||
|
|
||||||
|
// 件重信息
|
||||||
|
document.getElementById('det-pieces').innerText = data.pieces;
|
||||||
|
document.getElementById('det-weight').innerText = data.weight;
|
||||||
|
document.getElementById('det-calcWeight').innerText = data.calcWeight;
|
||||||
|
document.getElementById('det-inPieces').innerText = data.inPieces;
|
||||||
|
document.getElementById('det-inWeight').innerText = data.inWeight;
|
||||||
|
|
||||||
|
// 海关放行标签
|
||||||
|
const customsReleaseEl = document.getElementById('det-customsRelease');
|
||||||
|
if (data.customsRelease === '11') {
|
||||||
|
customsReleaseEl.innerText = '11';
|
||||||
|
customsReleaseEl.className = 'text-xs font-semibold px-2 py-0.5 rounded-md bg-green-50 text-green-600 inline-block';
|
||||||
|
} else {
|
||||||
|
customsReleaseEl.innerText = data.customsRelease;
|
||||||
|
customsReleaseEl.className = 'text-xs font-semibold px-2 py-0.5 rounded-md bg-gray-100 text-gray-600 inline-block';
|
||||||
|
}
|
||||||
|
document.getElementById('det-originalManifest').innerText = data.originalManifest;
|
||||||
|
document.getElementById('det-arriReport').innerText = data.arriReport;
|
||||||
|
document.getElementById('det-mftReport').innerText = data.mftReport;
|
||||||
|
document.getElementById('det-tallyReport').innerText = data.tallyReport;
|
||||||
|
// 渲染仓库批次
|
||||||
|
const warehouseContainer = document.getElementById('tab-content-1');
|
||||||
|
warehouseContainer.innerHTML = '';
|
||||||
|
data.warehouse.forEach(item => {
|
||||||
|
warehouseContainer.innerHTML += `
|
||||||
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
||||||
|
<div class="flex justify-between items-center pt-3 pb-1.5 px-3 mb-2 border-b border-gray-100">
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<span class="w-1.5 h-1.5 rounded-full bg-blue-500 inline-block"></span>
|
||||||
|
<span class="text-xs font-semibold text-gray-900">批次号: ${item.batch}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-1.5 px-3 pb-2">
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">件数</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${item.pieces}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">重量</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${parseFloat(item.weight).toFixed(1)} kg</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">航班日期</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${item.flightDate}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">航班号</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${item.flightNo}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">始发站</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${item.route}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">目的站</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${item.dest}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 渲染库位信息
|
||||||
|
const locationContainer = document.getElementById('tab-content-2');
|
||||||
|
locationContainer.innerHTML = '';
|
||||||
|
data.locations.forEach(loc => {
|
||||||
|
locationContainer.innerHTML += `
|
||||||
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
||||||
|
<div class="flex justify-between items-center pt-3 pb-1.5 px-3 mb-2 border-b border-gray-100">
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<span class="w-1.5 h-1.5 rounded-full bg-blue-500 inline-block"></span>
|
||||||
|
<span class="text-xs font-bold text-gray-900">${loc.id}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-1.5 px-3 pb-2">
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">入库人</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${loc.inPerson}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">入库时间</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${loc.inTime}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">出库人</div>
|
||||||
|
<div class="text-xs ${loc.outPerson === '—' ? 'text-gray-500' : 'text-gray-800'} font-semibold">${loc.outPerson}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">出库时间</div>
|
||||||
|
<div class="text-xs ${loc.outTime === '—' ? 'text-gray-500' : 'text-gray-800'} font-semibold">${loc.outTime}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 默认激活运单信息标签
|
||||||
|
switchTab(0);
|
||||||
|
// 页面切换动画:列表左滑隐藏,详情滑入
|
||||||
|
listPage.classList.add('page-hidden-left');
|
||||||
|
detailPage.classList.remove('page-hidden-right');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回列表页
|
||||||
|
function goBack() {
|
||||||
|
const listPage = document.getElementById('listPage');
|
||||||
|
const detailPage = document.getElementById('detailPage');
|
||||||
|
listPage.classList.remove('page-hidden-left');
|
||||||
|
detailPage.classList.add('page-hidden-right');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换详情标签页
|
||||||
|
function switchTab(index) {
|
||||||
|
const tabs = document.querySelectorAll('.tab-item');
|
||||||
|
const contents = document.querySelectorAll('.tab-pane');
|
||||||
|
tabs.forEach((tab, i) => {
|
||||||
|
if (i === index) {
|
||||||
|
tab.classList.add('active');
|
||||||
|
contents[i].classList.remove('hidden');
|
||||||
|
} else {
|
||||||
|
tab.classList.remove('active');
|
||||||
|
contents[i].classList.add('hidden');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toast提示
|
||||||
|
function showToast(msg) {
|
||||||
|
const toast = document.getElementById('toast');
|
||||||
|
toast.innerText = msg;
|
||||||
|
toast.classList.remove('hidden');
|
||||||
|
setTimeout(() => toast.classList.add('hidden'), 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选弹窗方法
|
||||||
|
function openFilter() {
|
||||||
|
const filterOverlay = document.getElementById('filterOverlay');
|
||||||
|
const filterSheet = document.getElementById('filterSheet');
|
||||||
|
filterOverlay.classList.add('show');
|
||||||
|
setTimeout(() => filterSheet.classList.add('show'), 10);
|
||||||
|
}
|
||||||
|
function closeFilter() {
|
||||||
|
const filterOverlay = document.getElementById('filterOverlay');
|
||||||
|
const filterSheet = document.getElementById('filterSheet');
|
||||||
|
filterSheet.classList.remove('show');
|
||||||
|
setTimeout(() => filterOverlay.classList.remove('show'), 250);
|
||||||
|
}
|
||||||
|
function resetFilter() {
|
||||||
|
document.querySelectorAll('.filter-input').forEach(input => {
|
||||||
|
input.value = '';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function confirmFilter() {
|
||||||
|
const params = {
|
||||||
|
flightDate: document.getElementById('filterFlightDate')?.value || '',
|
||||||
|
flightNo: document.getElementById('filterFlightNo')?.value || '',
|
||||||
|
agent: '',
|
||||||
|
code: '',
|
||||||
|
origin: document.getElementById('filterOrigin')?.value || '',
|
||||||
|
billType: '',
|
||||||
|
bizType: '',
|
||||||
|
cnName: document.getElementById('filterCnName')?.value || ''
|
||||||
|
};
|
||||||
|
console.log('筛选参数:', params);
|
||||||
|
alert('筛选执行成功,控制台可查看筛选条件');
|
||||||
|
closeFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 扫码弹窗
|
||||||
|
function toggleScanOverlay(show) {
|
||||||
|
const overlay = document.getElementById('scanOverlay');
|
||||||
|
if (show) overlay.classList.remove('hidden');
|
||||||
|
else overlay.classList.add('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面加载完成初始化
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
renderList();
|
||||||
|
// 筛选遮罩点击关闭
|
||||||
|
const filterOverlay = document.getElementById('filterOverlay');
|
||||||
|
filterOverlay.addEventListener('click', function(e) {
|
||||||
|
if (e.target === filterOverlay) closeFilter();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
139
documents/5.5寸手持端设计文件/07_出港仓库/运单追踪.html
Normal file
139
documents/5.5寸手持端设计文件/07_出港仓库/运单追踪.html
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
|
||||||
|
<title>国际进港查询 - 物流跟踪</title>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/tailwindcss.js"></script>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/iconify-icon.min.js"></script>
|
||||||
|
<style>
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
src: local('sans-serif');
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
|
.no-scrollbar::-webkit-scrollbar { display: none; }
|
||||||
|
.no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
|
||||||
|
|
||||||
|
/* 模拟手机容器阴影 */
|
||||||
|
.phone-shell {
|
||||||
|
box-shadow: 0 50px 100px -20px rgba(0,0,0,0.25), 0 30px 60px -30px rgba(0,0,0,0.3);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="bg-gray-200 flex justify-center items-center min-h-screen p-4">
|
||||||
|
<!-- 模拟手机屏幕容器 -->
|
||||||
|
<div class="phone-shell w-[375px] h-[812px] bg-[#F5F5F7] overflow-hidden flex flex-col relative rounded-[48px] border-[10px] border-gray-900">
|
||||||
|
<!-- 顶部蓝色区域 (包含状态栏和导航栏) -->
|
||||||
|
<div class="bg-[#1A73E8] flex-none">
|
||||||
|
<!-- 系统状态栏模拟 -->
|
||||||
|
<div class="h-11 w-full flex justify-between items-center px-8 text-white">
|
||||||
|
<span class="text-[15px] font-bold">09:41</span>
|
||||||
|
<div class="flex gap-1.5 items-center">
|
||||||
|
<iconify-icon class="text-sm" icon="mdi:signal-cellular-3"></iconify-icon>
|
||||||
|
<iconify-icon class="text-base" icon="mdi:wifi"></iconify-icon>
|
||||||
|
<iconify-icon class="text-xl" icon="mdi:battery"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 导航栏 -->
|
||||||
|
<div class="h-[44px] px-4 flex items-center justify-between">
|
||||||
|
<button class="flex items-center text-white space-x-0.5">
|
||||||
|
<iconify-icon class="text-2xl" icon="mdi:chevron-left"></iconify-icon>
|
||||||
|
<span class="text-base">返回</span>
|
||||||
|
</button>
|
||||||
|
<h1 class="text-lg font-bold text-white absolute left-1/2 -translate-x-1/2">运单追踪</h1>
|
||||||
|
<div class="w-10"></div> <!-- 占位保持平衡 -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 可滚动内容区 -->
|
||||||
|
<div class="flex-1 overflow-y-auto no-scrollbar px-5 pt-6 pb-12">
|
||||||
|
<!-- 流转状态卡片 -->
|
||||||
|
<div class="bg-white rounded-2xl p-5 shadow-sm border border-gray-100/50 mb-5">
|
||||||
|
<!-- 运单号 Header -->
|
||||||
|
<div class="flex items-center justify-between pt-2 pb-5 mb-8 border-b border-gray-100">
|
||||||
|
<div class="text-xl font-black text-gray-900 leading-none tracking-tight">
|
||||||
|
78133358743
|
||||||
|
</div>
|
||||||
|
<span class="text-[11px] font-medium text-blue-600 bg-blue-50 px-2.5 py-1 rounded-full border border-blue-100">国际进港</span>
|
||||||
|
</div>
|
||||||
|
<!-- 流转状态标题 -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<h2 class="text-base font-semibold text-gray-700 flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4 text-gray-700 inline-block" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewbox="0 0 24 24">
|
||||||
|
<circle cx="12" cy="12" r="10"></circle>
|
||||||
|
<polyline points="12 6 12 12 16 14"></polyline>
|
||||||
|
</svg>
|
||||||
|
流转状态
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div class="relative pl-7 pb-2">
|
||||||
|
<div class="absolute left-[9px] top-2 bottom-4 w-[2px] bg-gray-100"></div>
|
||||||
|
<!-- 状态 1: 当前 -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<div class="absolute -left-[27px] top-1 w-[20px] h-[20px] rounded-full bg-green-600 border-4 border-green-100 flex items-center justify-center ring-1 ring-green-600/20">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-white"></div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span class="text-sm font-medium text-green-700">原始舱单</span>
|
||||||
|
<span class="text-green-600 text-xs font-normal bg-green-50 px-2 py-0.5 rounded-full">放行状态:01</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-gray-400 text-xs font-normal flex items-center gap-1.5">
|
||||||
|
<span>2026-07-10 11:03:38</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 状态 2 -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<div class="absolute -left-[22px] top-1.5 w-[10px] h-[10px] rounded-full bg-gray-200 border-2 border-white"></div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm font-bold text-gray-400">分拣理货</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 状态 3 -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<div class="absolute -left-[22px] top-1.5 w-[10px] h-[10px] rounded-full bg-gray-200 border-2 border-white"></div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm font-bold text-gray-400">理货申报</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 状态 4 -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<div class="absolute -left-[22px] top-1.5 w-[10px] h-[10px] rounded-full bg-gray-200 border-2 border-white"></div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm font-bold text-gray-400">海关放行</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 状态 5 -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<div class="absolute -left-[22px] top-1.5 w-[10px] h-[10px] rounded-full bg-gray-200 border-2 border-white"></div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm font-bold text-gray-400">柜台办结</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 状态 6 -->
|
||||||
|
<div class="relative mb-2">
|
||||||
|
<div class="absolute -left-[22px] top-1.5 w-[10px] h-[10px] rounded-full bg-gray-200 border-2 border-white"></div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm font-bold text-gray-400">提取出库</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 模块 4: 操作详情卡片 -> 已删除 -->
|
||||||
|
<!-- 底部占位 -->
|
||||||
|
<div class="text-center py-6">
|
||||||
|
<p class="text-[10px] text-gray-300 uppercase tracking-[0.2em] font-bold">查询信息已触底</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 底部 Home Indicator 模拟 -->
|
||||||
|
<div class="h-8 w-full flex justify-center items-center flex-none bg-white/60 backdrop-blur-md">
|
||||||
|
<div class="w-32 h-1.5 bg-black rounded-full opacity-20"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>ml>
|
||||||
139
documents/5.5寸手持端设计文件/08_进港仓库/运单追踪.html
Normal file
139
documents/5.5寸手持端设计文件/08_进港仓库/运单追踪.html
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
|
||||||
|
<title>国际进港查询 - 物流跟踪</title>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/tailwindcss.js"></script>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/iconify-icon.min.js"></script>
|
||||||
|
<style>
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
src: local('sans-serif');
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
|
.no-scrollbar::-webkit-scrollbar { display: none; }
|
||||||
|
.no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
|
||||||
|
|
||||||
|
/* 模拟手机容器阴影 */
|
||||||
|
.phone-shell {
|
||||||
|
box-shadow: 0 50px 100px -20px rgba(0,0,0,0.25), 0 30px 60px -30px rgba(0,0,0,0.3);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="bg-gray-200 flex justify-center items-center min-h-screen p-4">
|
||||||
|
<!-- 模拟手机屏幕容器 -->
|
||||||
|
<div class="phone-shell w-[375px] h-[812px] bg-[#F5F5F7] overflow-hidden flex flex-col relative rounded-[48px] border-[10px] border-gray-900">
|
||||||
|
<!-- 顶部蓝色区域 (包含状态栏和导航栏) -->
|
||||||
|
<div class="bg-[#1A73E8] flex-none">
|
||||||
|
<!-- 系统状态栏模拟 -->
|
||||||
|
<div class="h-11 w-full flex justify-between items-center px-8 text-white">
|
||||||
|
<span class="text-[15px] font-bold">09:41</span>
|
||||||
|
<div class="flex gap-1.5 items-center">
|
||||||
|
<iconify-icon class="text-sm" icon="mdi:signal-cellular-3"></iconify-icon>
|
||||||
|
<iconify-icon class="text-base" icon="mdi:wifi"></iconify-icon>
|
||||||
|
<iconify-icon class="text-xl" icon="mdi:battery"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 导航栏 -->
|
||||||
|
<div class="h-[44px] px-4 flex items-center justify-between">
|
||||||
|
<button class="flex items-center text-white space-x-0.5">
|
||||||
|
<iconify-icon class="text-2xl" icon="mdi:chevron-left"></iconify-icon>
|
||||||
|
<span class="text-base">返回</span>
|
||||||
|
</button>
|
||||||
|
<h1 class="text-lg font-bold text-white absolute left-1/2 -translate-x-1/2">运单追踪</h1>
|
||||||
|
<div class="w-10"></div> <!-- 占位保持平衡 -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 可滚动内容区 -->
|
||||||
|
<div class="flex-1 overflow-y-auto no-scrollbar px-5 pt-6 pb-12">
|
||||||
|
<!-- 流转状态卡片 -->
|
||||||
|
<div class="bg-white rounded-2xl p-5 shadow-sm border border-gray-100/50 mb-5">
|
||||||
|
<!-- 运单号 Header -->
|
||||||
|
<div class="flex items-center justify-between pt-2 pb-5 mb-8 border-b border-gray-100">
|
||||||
|
<div class="text-xl font-black text-gray-900 leading-none tracking-tight">
|
||||||
|
78133358743
|
||||||
|
</div>
|
||||||
|
<span class="text-[11px] font-medium text-blue-600 bg-blue-50 px-2.5 py-1 rounded-full border border-blue-100">国际进港</span>
|
||||||
|
</div>
|
||||||
|
<!-- 流转状态标题 -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<h2 class="text-base font-semibold text-gray-700 flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4 text-gray-700 inline-block" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewbox="0 0 24 24">
|
||||||
|
<circle cx="12" cy="12" r="10"></circle>
|
||||||
|
<polyline points="12 6 12 12 16 14"></polyline>
|
||||||
|
</svg>
|
||||||
|
流转状态
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div class="relative pl-7 pb-2">
|
||||||
|
<div class="absolute left-[9px] top-2 bottom-4 w-[2px] bg-gray-100"></div>
|
||||||
|
<!-- 状态 1: 当前 -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<div class="absolute -left-[27px] top-1 w-[20px] h-[20px] rounded-full bg-green-600 border-4 border-green-100 flex items-center justify-center ring-1 ring-green-600/20">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-white"></div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span class="text-sm font-medium text-green-700">原始舱单</span>
|
||||||
|
<span class="text-green-600 text-xs font-normal bg-green-50 px-2 py-0.5 rounded-full">放行状态:01</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-gray-400 text-xs font-normal flex items-center gap-1.5">
|
||||||
|
<span>2026-07-10 11:03:38</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 状态 2 -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<div class="absolute -left-[22px] top-1.5 w-[10px] h-[10px] rounded-full bg-gray-200 border-2 border-white"></div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm font-bold text-gray-400">分拣理货</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 状态 3 -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<div class="absolute -left-[22px] top-1.5 w-[10px] h-[10px] rounded-full bg-gray-200 border-2 border-white"></div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm font-bold text-gray-400">理货申报</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 状态 4 -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<div class="absolute -left-[22px] top-1.5 w-[10px] h-[10px] rounded-full bg-gray-200 border-2 border-white"></div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm font-bold text-gray-400">海关放行</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 状态 5 -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<div class="absolute -left-[22px] top-1.5 w-[10px] h-[10px] rounded-full bg-gray-200 border-2 border-white"></div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm font-bold text-gray-400">柜台办结</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 状态 6 -->
|
||||||
|
<div class="relative mb-2">
|
||||||
|
<div class="absolute -left-[22px] top-1.5 w-[10px] h-[10px] rounded-full bg-gray-200 border-2 border-white"></div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm font-bold text-gray-400">提取出库</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 模块 4: 操作详情卡片 -> 已删除 -->
|
||||||
|
<!-- 底部占位 -->
|
||||||
|
<div class="text-center py-6">
|
||||||
|
<p class="text-[10px] text-gray-300 uppercase tracking-[0.2em] font-bold">查询信息已触底</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 底部 Home Indicator 模拟 -->
|
||||||
|
<div class="h-8 w-full flex justify-center items-center flex-none bg-white/60 backdrop-blur-md">
|
||||||
|
<div class="w-32 h-1.5 bg-black rounded-full opacity-20"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>ml>
|
||||||
924
documents/5.5寸手持端设计文件/08_进港仓库/进港仓库.html
Normal file
924
documents/5.5寸手持端设计文件/08_进港仓库/进港仓库.html
Normal file
@@ -0,0 +1,924 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||||
|
<title>进港仓库</title>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/tailwindcss.js"></script>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/iconify-icon.min.js"></script>
|
||||||
|
<style>
|
||||||
|
@font-face {
|
||||||
|
font-family: 'PingFang SC';
|
||||||
|
src: local('PingFang SC');
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: 'PingFang SC', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||||
|
background-color: #e5e7eb;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
padding: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
/* 隐藏滚动条但保留功能 */
|
||||||
|
.hide-scrollbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.hide-scrollbar {
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-tag {
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.tag-occupied { background-color: #dcfce7; color: #22c55e; } /* 已离港 - 绿色 */
|
||||||
|
.tag-available { background-color: #dcfce7; color: #22c55e; } /* 已离港 - 绿色 */
|
||||||
|
.tag-repair { background-color: #fce7e7; color: #ef4444; } /* 离港 - 红色 */
|
||||||
|
|
||||||
|
/* 页面切换动画 */
|
||||||
|
.page {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
transition: transform 0.3s ease-in-out;
|
||||||
|
background-color: #f3f4f6;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-y: auto;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
.page::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.page-hidden-right { transform: translateX(100%); }
|
||||||
|
.page-hidden-left { transform: translateX(-100%); }
|
||||||
|
|
||||||
|
|
||||||
|
/* 统一的深蓝色调 */
|
||||||
|
.bg-header-blue { background-color: #2563EB; }
|
||||||
|
|
||||||
|
|
||||||
|
/* 标签页样式 */
|
||||||
|
.tab-item {
|
||||||
|
position: relative;
|
||||||
|
padding: 12px 0;
|
||||||
|
color: #999;
|
||||||
|
font-size: 14px;
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.tab-item.active {
|
||||||
|
color: #2563eb;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.tab-item::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 0;
|
||||||
|
height: 2px;
|
||||||
|
background-color: #2563eb;
|
||||||
|
transition: width 0.3s ease;
|
||||||
|
}
|
||||||
|
.tab-item.active::after {
|
||||||
|
width: 40%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 筛选弹窗样式 提升层级+动画稳定 ========== */
|
||||||
|
.filter-overlay {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background-color: rgba(0,0,0,0.4);
|
||||||
|
z-index: 9999;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
transition: opacity 0.25s ease, visibility 0.25s ease;
|
||||||
|
}
|
||||||
|
.filter-overlay.show {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-sheet {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: #fff;
|
||||||
|
border-top-left-radius: 20px;
|
||||||
|
border-top-right-radius: 20px;
|
||||||
|
padding: 20px;
|
||||||
|
z-index: 10000;
|
||||||
|
transform: translateY(100%);
|
||||||
|
transition: transform 0.25s ease-out;
|
||||||
|
max-height: 80vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.filter-sheet.show {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
/* 筛选输入框统一样式 */
|
||||||
|
.filter-input {
|
||||||
|
width: 100%;
|
||||||
|
height: 40px;
|
||||||
|
padding: 0 12px;
|
||||||
|
background: #f3f4f6;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
outline: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.filter-input:focus {
|
||||||
|
border-color: #2563EB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 下拉框箭头浅灰色 + 全浏览器兼容修复 */
|
||||||
|
select.filter-input {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%239ca3af' viewBox='0 0 16 16'%3E%3Cpath d='M8 11L3 6h10l-5 5z'/%3E%3C/svg%3E");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: right 12px center;
|
||||||
|
background-size: 16px;
|
||||||
|
padding-right: 36px;
|
||||||
|
}
|
||||||
|
/* 清除IE默认下拉箭头 */
|
||||||
|
select.filter-input::-ms-expand {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes scan {
|
||||||
|
0% { top: 0; }
|
||||||
|
100% { top: 100%; }
|
||||||
|
}
|
||||||
|
.scan-line {
|
||||||
|
animation: scan 2s linear infinite;
|
||||||
|
}
|
||||||
|
.custom-scrollbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.bottom-drawer {
|
||||||
|
transition: transform 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="w-[375px] h-[812px] bg-[#F3F4F6] overflow-hidden flex flex-col relative shadow-2xl rounded-[40px] border-[8px] border-gray-800">
|
||||||
|
<!-- 状态栏 -->
|
||||||
|
<div class="h-6 w-full bg-[#2563EB] flex justify-between items-center px-6 text-white text-xs pt-1">
|
||||||
|
<span>09:41</span>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<iconify-icon icon="material-symbols:signal-cellular-4-bar-rounded"></iconify-icon>
|
||||||
|
<iconify-icon icon="material-symbols:wifi"></iconify-icon>
|
||||||
|
<iconify-icon icon="material-symbols:battery-full-rounded"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 筛选弹窗容器 移到最外层,层级提升 -->
|
||||||
|
<div class="filter-overlay" id="filterOverlay"></div>
|
||||||
|
<div class="filter-sheet" id="filterSheet">
|
||||||
|
<!-- 顶部标题栏 -->
|
||||||
|
<div class="relative flex items-center justify-center mb-6">
|
||||||
|
<button class="absolute right-0 top-0 text-gray-400" onclick="closeFilter()">
|
||||||
|
<iconify-icon class="text-2xl" icon="mdi:close"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
<h2 class="text-[18px] font-bold text-gray-900">筛选条件</h2>
|
||||||
|
</div>
|
||||||
|
<!-- 筛选表单区域 -->
|
||||||
|
<div class="space-y-4 mb-7">
|
||||||
|
<!-- 1.航班日期 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">航班日期</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择航班日期" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:calendar" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 2.航班号 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">航班号</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请输入航班号" type="text" id="filterFlightNo">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 3.代理 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">代理</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择代理" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:chevron-down" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 4.特码 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">特码</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择特码" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:chevron-down" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 5.始发站 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">始发站</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请输入始发站" type="text" id="filterOrigin">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 6.运单类型 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">运单类型</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择运单类型" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:chevron-down" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 7.业务类型 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">业务类型</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择业务类型" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:chevron-down" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 8.品名(中) -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">品名(中)</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请输入中文品名" type="text" id="filterCnName">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 底部操作按钮 -->
|
||||||
|
<div class="flex gap-3">
|
||||||
|
<button class="flex-1 h-11 bg-gray-100 text-gray-600 rounded-lg text-sm font-medium" onclick="resetFilter()">重置</button>
|
||||||
|
<button class="flex-1 h-11 bg-[#2563EB] text-white rounded-lg text-sm font-medium" onclick="confirmFilter()">确定</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 页面主容器 -->
|
||||||
|
<div class="flex-1 relative overflow-hidden">
|
||||||
|
<!-- 列表首页:进港仓库卡片页面 -->
|
||||||
|
<div class="page z-10" id="listPage">
|
||||||
|
<!-- 顶部导航栏 -->
|
||||||
|
<header class="bg-[#2563EB] h-14 flex items-center justify-between px-4 flex-none">
|
||||||
|
<button class="flex items-center text-white text-sm" onclick="showToast('返回上一级')">
|
||||||
|
<iconify-icon class="text-2xl" icon="mdi:chevron-left"></iconify-icon>
|
||||||
|
<span>返回</span>
|
||||||
|
</button>
|
||||||
|
<h1 class="text-white font-bold text-lg">进港仓库</h1>
|
||||||
|
<div class="w-12"></div>
|
||||||
|
</header>
|
||||||
|
<!-- 搜索区 -->
|
||||||
|
<section class="bg-[#F3F4F6] p-3 flex-none">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="flex-1 relative">
|
||||||
|
<iconify-icon class="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 text-lg" icon="mdi:magnify"></iconify-icon>
|
||||||
|
<input class="w-full bg-white rounded-full pl-10 pr-10 py-2.5 text-sm shadow-sm border border-gray-200 outline-none" onkeypress="if(event.keyCode==13) showToast('执行搜索')" placeholder="搜索运单号/航班号..." type="text"/>
|
||||||
|
<button class="absolute right-2 top-1/2 -translate-y-1/2 p-1 text-[#2563EB]" onclick="toggleScanOverlay(true)">
|
||||||
|
<iconify-icon class="text-lg" icon="mdi:qrcode-scan"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button id="filterBtn" class="bg-white p-2.5 rounded-full shadow-sm border border-gray-200 text-[#2563EB] flex items-center justify-center flex-none" onclick="openFilter()">
|
||||||
|
<iconify-icon class="text-xl" icon="mdi:filter-variant"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- 统计栏 -->
|
||||||
|
<section class="px-3 pb-3 flex justify-between gap-2 flex-none">
|
||||||
|
<div class="flex-1 bg-white rounded-lg px-3 py-2.5 shadow-sm border-l-[4px] border-l-[#2563EB]">
|
||||||
|
<div class="text-[11px] text-gray-500">总票数</div>
|
||||||
|
<div class="text-lg font-bold text-[#2563EB]">8</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 bg-white rounded-lg px-3 py-2.5 shadow-sm border-l-[4px] border-l-orange-500">
|
||||||
|
<div class="text-[11px] text-gray-500">未清仓</div>
|
||||||
|
<div class="text-lg font-bold text-orange-500">4</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 bg-white rounded-lg px-3 py-2.5 shadow-sm border-l-[4px] border-l-[#10B981]">
|
||||||
|
<div class="text-[11px] text-gray-500">已清仓</div>
|
||||||
|
<div class="text-lg font-bold text-[#10B981]">4</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- 卡片列表容器 -->
|
||||||
|
<main class="flex-1 overflow-y-auto px-3 pb-4 custom-scrollbar" id="cardListContainer">
|
||||||
|
</main>
|
||||||
|
<!-- 扫码层 -->
|
||||||
|
<div class="absolute inset-0 z-50 bg-black hidden flex flex-col" id="scanOverlay">
|
||||||
|
<div class="p-6 flex justify-between items-center text-white">
|
||||||
|
<button onclick="toggleScanOverlay(false)">
|
||||||
|
<iconify-icon class="text-2xl" icon="mdi:close"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
<span class="text-sm font-medium">扫描运单条码</span>
|
||||||
|
<button><iconify-icon class="text-2xl" icon="mdi:flashlight"></iconify-icon></button>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 flex flex-col items-center justify-center p-12">
|
||||||
|
<div class="w-64 h-64 border-2 border-[#2563EB] relative overflow-hidden rounded-lg">
|
||||||
|
<div class="absolute top-0 left-0 w-full h-0.5 bg-[#2563EB] shadow-[0_0_10px_#2563EB] scan-line"></div>
|
||||||
|
<div class="absolute top-0 left-0 w-6 h-6 border-t-4 border-l-4 border-[#2563EB]"></div>
|
||||||
|
<div class="absolute top-0 right-0 w-6 h-6 border-t-4 border-r-4 border-[#2563EB]"></div>
|
||||||
|
<div class="absolute bottom-0 left-0 w-6 h-6 border-b-4 border-l-4 border-[#2563EB]"></div>
|
||||||
|
<div class="absolute bottom-0 right-0 w-6 h-6 border-b-4 border-r-4 border-[#2563EB]"></div>
|
||||||
|
</div>
|
||||||
|
<p class="text-white text-xs mt-6 opacity-60 text-center px-4">将条码/二维码放入框内,即可自动扫描</p>
|
||||||
|
</div>
|
||||||
|
<div class="h-32 bg-black flex justify-center items-center gap-12 text-white">
|
||||||
|
<div class="flex flex-col items-center opacity-60">
|
||||||
|
<iconify-icon class="text-3xl" icon="mdi:image-outline"></iconify-icon>
|
||||||
|
<span class="text-[10px] mt-1">相册</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<iconify-icon class="text-3xl" icon="mdi:keyboard-outline"></iconify-icon>
|
||||||
|
<span class="text-[10px] mt-1">手动输入</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Toast -->
|
||||||
|
<div class="absolute bottom-20 left-1/2 -translate-x-1/2 bg-black bg-opacity-80 text-white text-xs px-4 py-2 rounded-full hidden z-[60] whitespace-nowrap" id="toast">提示内容</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 进港货物页面(右滑弹出) -->
|
||||||
|
<div class="page z-20 page-hidden-right !bg-[#f0f2f5]" id="detailPage">
|
||||||
|
<!-- 头部 -->
|
||||||
|
<header class="bg-header-blue pt-2 pb-4 px-4 flex items-center relative flex-none">
|
||||||
|
<button class="flex items-center text-white text-sm absolute left-4 active:opacity-70" onclick="goBack()">
|
||||||
|
<iconify-icon class="text-xl" icon="mdi:chevron-left"></iconify-icon>
|
||||||
|
<span>返回</span>
|
||||||
|
</button>
|
||||||
|
<h1 class="mx-auto text-white font-bold text-lg">进港货物</h1>
|
||||||
|
<div class="absolute right-4 flex items-center">
|
||||||
|
<iconify-icon class="text-red-500 text-2xl" icon="mdi:file-document-edit-outline"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<!-- 标签页 -->
|
||||||
|
<div class="bg-white px-4 border-b border-gray-200 flex-none">
|
||||||
|
<div class="flex justify-around">
|
||||||
|
<div class="tab-item active cursor-pointer" onclick="switchTab(0)">运单信息</div>
|
||||||
|
<div class="tab-item cursor-pointer" onclick="switchTab(1)">仓库信息</div>
|
||||||
|
<div class="tab-item cursor-pointer" onclick="switchTab(2)">库位信息</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 详情内容区 -->
|
||||||
|
<div class="flex-1 overflow-y-auto hide-scrollbar">
|
||||||
|
<!-- 运单信息标签页 -->
|
||||||
|
<div class="tab-pane p-3 space-y-3" id="tab-content-0">
|
||||||
|
<!-- 卡片1:基本信息 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
||||||
|
<div class="px-4 py-2.5 flex items-center border-b border-gray-100">
|
||||||
|
<div class="w-1 h-4 bg-blue-500 rounded-full inline-block mr-2"></div>
|
||||||
|
<span class="text-xs font-semibold text-gray-800" id="det-uldTitle">基本信息</span>
|
||||||
|
</div>
|
||||||
|
<div class="p-3 grid grid-cols-2 gap-2">
|
||||||
|
<!-- Row 1 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">运单号</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-billNo"></span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">代理人</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-agent"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 2 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">特码</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-code"></span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">承运人</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-carrier"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 3 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">始发站</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-route"></span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">中转站</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-outboundTime"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 4 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">目的站</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-dest"></span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">UN编号</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-unNo"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 5 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center" id="det-lockStatus-container">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5" id="det-lockStatus-label">锁定状态</span>
|
||||||
|
<div id="det-lockStatus-wrapper">
|
||||||
|
<span class="text-xs font-semibold" id="det-lockStatus"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">包装类型</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-packType"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 6 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">业务类型</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-type"></span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">入库时间</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-ciTime"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 7 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center col-span-2">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">运单类型</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-billType"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 8 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center col-span-2">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">品名(中)</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-itemNameCn"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 9 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center col-span-2">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">品名(英)</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-itemNameEn"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 10 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center col-span-2">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">备注</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-remark"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片2:件重信息 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
||||||
|
<div class="px-4 py-2.5 flex items-center border-b border-gray-100">
|
||||||
|
<div class="w-1 h-4 bg-blue-500 rounded-full inline-block mr-2"></div>
|
||||||
|
<span class="text-xs font-semibold text-gray-800">件重信息</span>
|
||||||
|
</div>
|
||||||
|
<div class="p-3 grid grid-cols-3 gap-2">
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">运单件数</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-pieces"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">运单重量</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-weight"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">计费重量</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-calcWeight"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">入库件数</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-inPieces"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">入库重量</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-inWeight"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center opacity-0">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">—</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold">—</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片3:回执信息 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
||||||
|
<div class="px-4 py-2.5 flex items-center border-b border-gray-100">
|
||||||
|
<div class="w-1 h-4 bg-blue-500 rounded-full inline-block mr-2"></div>
|
||||||
|
<span class="text-xs font-semibold text-gray-800">回执信息</span>
|
||||||
|
</div>
|
||||||
|
<div class="p-3 grid grid-cols-3 gap-2">
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">原始舱单</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-originalManifest"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">理货报告</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-tallyReport"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center" id="det-customsRelease-container">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">海关放行</div>
|
||||||
|
<div id="det-customsRelease-wrapper">
|
||||||
|
<div class="text-xs font-semibold" id="det-customsRelease"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 仓库信息标签页 -->
|
||||||
|
<div class="tab-pane p-3 space-y-3 hidden" id="tab-content-1"></div>
|
||||||
|
<!-- 库位信息标签页 -->
|
||||||
|
<div class="tab-pane p-3 space-y-3 hidden" id="tab-content-2"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// 运单详情数据源(用于进港货物渲染)
|
||||||
|
const uldData = {
|
||||||
|
'78133363396': {
|
||||||
|
billNo: '78133363396', agent: '中外运', code: 'DGR',
|
||||||
|
pieces: '444', weight: '555.0', type: '普通货物运输',
|
||||||
|
inPieces: '444', inWeight: '555.0', calcWeight: '555.0',
|
||||||
|
carrier: 'CA', route: 'LAX', packType: '纸箱',
|
||||||
|
billType: '国际进港(国际直航)', unNo: '—', dest: 'HFE',
|
||||||
|
itemNameCn: '电子元器件', itemNameEn: 'Electronic Components',
|
||||||
|
lockStatus: '未锁定', outboundTime: '—', remark: '需冷藏存储',
|
||||||
|
originalManifest: '01', tallyReport: '01', customsRelease: '11',ciTime: '2026-07-08 14:30:00',
|
||||||
|
warehouse: [
|
||||||
|
{ batch: '1', pieces: 200, weight: 300.0, flightDate: '2026-07-08', flightNo: 'CA1234',route: 'LAX',dest: 'HFE', time: '2026-07-08 14:30:00' },
|
||||||
|
{ batch: '2', pieces: 244, weight: 255.0, flightDate: '2026-07-09', flightNo: 'CA5678',route: 'LAX',dest: 'HFE', time: '2026-07-09 09:10:46' }
|
||||||
|
],
|
||||||
|
locations: [
|
||||||
|
{ id: 'A-01-001', inPerson: '张三', inTime: '2026-07-08 14:30', outPerson: '李四', outTime: '2026-07-09 10:00' },
|
||||||
|
{ id: 'B-02-005', inPerson: '王五', inTime: '2026-07-09 09:10', outPerson: '—', outTime: '—' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'78133363397': {
|
||||||
|
billNo: '78133363397', agent: '徽远', code: 'PER',
|
||||||
|
pieces: '120', weight: '320.0', type: '普通货物运输',
|
||||||
|
inPieces: '120', inWeight: '320.0', calcWeight: '320.0',
|
||||||
|
carrier: 'MU', route: 'PVG-NRT', packType: '托盘',
|
||||||
|
billType: '国际进港(国际直航)', unNo: '—', dest: 'PVG',
|
||||||
|
itemNameCn: '服装', itemNameEn: 'Garments',
|
||||||
|
lockStatus: '未锁定', outboundTime: '—', remark: '易碎品,轻拿轻放',
|
||||||
|
originalManifest: '01', tallyReport: '01', customsRelease: '11',ciTime: '2026-07-08 14:30:00',
|
||||||
|
warehouse: [
|
||||||
|
{ batch: '3', pieces: 60, weight: 150.0, flightDate: '2026-07-07', flightNo: 'MU123', time: '2026-07-07 16:20:00' },
|
||||||
|
{ batch: '4', pieces: 60, weight: 170.0, flightDate: '2026-07-08', flightNo: 'MU456', time: '2026-07-08 11:00:00' }
|
||||||
|
],
|
||||||
|
locations: [
|
||||||
|
{ id: 'A-03-012', inPerson: '赵六', inTime: '2026-07-07 16:20', outPerson: '钱七', outTime: '2026-07-08 14:00' },
|
||||||
|
{ id: 'C-01-008', inPerson: '孙八', inTime: '2026-07-08 11:00', outPerson: '—', outTime: '—' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'78133363398': {
|
||||||
|
billNo: '78133363398', agent: '中外运', code: 'NOR',
|
||||||
|
pieces: '268', weight: '780.0', type: '普通货物运输',
|
||||||
|
inPieces: '268', inWeight: '780.0', calcWeight: '780.0',
|
||||||
|
carrier: 'CZ', route: 'CAN-AMS', packType: '托盘',
|
||||||
|
billType: '国际进港(国际直航)', unNo: '—', dest: 'CAN',
|
||||||
|
itemNameCn: '机械设备', itemNameEn: 'Machinery Equipment',
|
||||||
|
lockStatus: '锁定', outboundTime: '2026-07-09 08:00', remark: '需叉车装卸',
|
||||||
|
originalManifest: '01', tallyReport: '01', customsRelease: '11',ciTime: '2026-07-08 14:30:00',
|
||||||
|
warehouse: [
|
||||||
|
{ batch: '5', pieces: 150, weight: 420.0, flightDate: '2026-07-08', flightNo: 'CZ789', time: '2026-07-08 22:15:00' },
|
||||||
|
{ batch: '6', pieces: 118, weight: 360.0, flightDate: '2026-07-09', flightNo: 'CZ012', time: '2026-07-09 06:30:00' },
|
||||||
|
{ batch: '7', pieces: 100, weight: 200.0, flightDate: '2026-07-09', flightNo: 'CZ345', time: '2026-07-09 13:00:00' }
|
||||||
|
],
|
||||||
|
locations: [
|
||||||
|
{ id: 'B-01-003', inPerson: '张三', inTime: '2026-07-08 22:15', outPerson: '李四', outTime: '2026-07-09 06:00' },
|
||||||
|
{ id: 'A-02-010', inPerson: '王五', inTime: '2026-07-09 06:30', outPerson: '—', outTime: '—' },
|
||||||
|
{ id: 'C-03-007', inPerson: '赵六', inTime: '2026-07-09 13:00', outPerson: '—', outTime: '—' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'78133363399': {
|
||||||
|
billNo: '78133363399', agent: '徽远', code: 'DGR',
|
||||||
|
pieces: '85', weight: '210.0', type: '危险品运输',
|
||||||
|
inPieces: '85', inWeight: '210.0', calcWeight: '210.0',
|
||||||
|
carrier: '3U', route: 'CTU-SIN', packType: '铁箱',
|
||||||
|
billType: '国际进港(国际直航)', unNo: 'UN3480', dest: 'CTU',
|
||||||
|
itemNameCn: '锂电池', itemNameEn: 'Lithium Battery',
|
||||||
|
lockStatus: '锁定', outboundTime: '—', remark: '危险品,单独存放',
|
||||||
|
originalManifest: '01', tallyReport: '01', customsRelease: '11',ciTime: '2026-07-08 14:30:00',
|
||||||
|
warehouse: [
|
||||||
|
{ batch: '8', pieces: 45, weight: 110.0, flightDate: '2026-07-08', flightNo: '3U678', time: '2026-07-08 18:00:00' },
|
||||||
|
{ batch: '9', pieces: 40, weight: 100.0, flightDate: '2026-07-09', flightNo: '3U901', time: '2026-07-09 07:45:00' }
|
||||||
|
],
|
||||||
|
locations: [
|
||||||
|
{ id: 'D-01-002', inPerson: '钱七', inTime: '2026-07-08 18:00', outPerson: '孙八', outTime: '2026-07-09 08:00' },
|
||||||
|
{ id: 'A-04-015', inPerson: '张三', inTime: '2026-07-09 07:45', outPerson: '—', outTime: '—' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'78133363400': {
|
||||||
|
billNo: '78133363400', agent: '中外运', code: 'PER',
|
||||||
|
pieces: '350', weight: '430.0', type: '普通货物运输',
|
||||||
|
inPieces: '350', inWeight: '430.0', calcWeight: '430.0',
|
||||||
|
carrier: 'HU', route: 'HKG-HFE', packType: '纸箱',
|
||||||
|
billType: '国际进港(国际直航)', unNo: '—', dest: 'HFE',
|
||||||
|
itemNameCn: '食品', itemNameEn: 'Food Products',
|
||||||
|
lockStatus: '未锁定', outboundTime: '2026-07-09 11:30', remark: '保质期至2026-12',
|
||||||
|
originalManifest: '01', tallyReport: '01', customsRelease: '11',ciTime: '2026-07-08 14:30:00',
|
||||||
|
warehouse: [
|
||||||
|
{ batch: '10', pieces: 180, weight: 220.0, flightDate: '2026-07-07', flightNo: 'HU234', time: '2026-07-07 20:00:00' },
|
||||||
|
{ batch: '11', pieces: 170, weight: 210.0, flightDate: '2026-07-09', flightNo: 'HU567', time: '2026-07-09 10:30:00' }
|
||||||
|
],
|
||||||
|
locations: [
|
||||||
|
{ id: 'B-02-011', inPerson: '李四', inTime: '2026-07-07 20:00', outPerson: '王五', outTime: '2026-07-08 16:00' },
|
||||||
|
{ id: 'C-01-009', inPerson: '赵六', inTime: '2026-07-09 10:30', outPerson: '—', outTime: '—' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 进港仓库卡片列表数据源
|
||||||
|
const data = [
|
||||||
|
{ id: "78133363396", status: "已清仓", flight: "20260702/MU1111", route: "LAX-HFE", pcs: 111, weight: 2300 },
|
||||||
|
{ id: "78133363397", status: "未清仓", flight: "20260702/MU2222", route: "NRT-HFE", pcs: 85, weight: 1560 },
|
||||||
|
{ id: "78133363398", status: "已清仓", flight: "20260702/MU3333", route: "FRA-HFE", pcs: 200, weight: 4200 },
|
||||||
|
{ id: "78133363399", status: "未清仓", flight: "20260702/MU4444", route: "LAX-PVG", pcs: 50, weight: 980 },
|
||||||
|
{ id: "78133363400", status: "未清仓", flight: "20260702/MU5555", route: "CDG-HFE", pcs: 168, weight: 3150 },
|
||||||
|
{ id: "78133363401", status: "已清仓", flight: "20260702/MU6666", route: "SIN-HFE", pcs: 92, weight: 1800 },
|
||||||
|
{ id: "78133363402", status: "未清仓", flight: "20260702/MU7777", route: "LAX-NKG", pcs: 145, weight: 2800 },
|
||||||
|
{ id: "78133363403", status: "已清仓", flight: "20260702/MU8888", route: "HND-HFE", pcs: 73, weight: 1420 }
|
||||||
|
];
|
||||||
|
|
||||||
|
// 渲染仓库卡片列表
|
||||||
|
function renderList() {
|
||||||
|
const container = document.getElementById('cardListContainer');
|
||||||
|
container.innerHTML = data.map((item) => {
|
||||||
|
const isCleared = item.status === '已清仓';
|
||||||
|
const departure = item.route.split('-')[0];
|
||||||
|
const flightNo = item.flight.split('/')[1];
|
||||||
|
return `
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-sm active:bg-gray-50 transition-colors border border-gray-50 cursor-pointer mb-3" onclick="showDetail('${item.id}')">
|
||||||
|
<div class="flex justify-between items-center mb-3">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-blue-500"></div>
|
||||||
|
<span class="font-bold text-[#1a1a1a]">${item.id}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
${getStatusTag(item.status)}
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:chevron-right"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 gap-y-2 text-[13px] text-gray-500">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:package-variant-closed"></iconify-icon>
|
||||||
|
<span>件数:${item.pcs}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:weight-kilogram"></iconify-icon>
|
||||||
|
<span>重量:${item.weight}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:airplane"></iconify-icon>
|
||||||
|
<span>航班号:${flightNo}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:map-marker"></iconify-icon>
|
||||||
|
<span>始发站:${departure}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-4 gap-2 mt-3">
|
||||||
|
<button onclick="event.stopPropagation(); showToast('执行清仓操作:运单号 ${item.id}')"
|
||||||
|
class="text-xs py-1.5 px-2 rounded-[6px] font-medium h-8 ${isCleared ? 'bg-gray-100 text-gray-400 cursor-not-allowed' : 'bg-[#EFF6FF] text-[#2563EB]'}" ${isCleared ? 'disabled' : ''}>
|
||||||
|
清仓
|
||||||
|
</button>
|
||||||
|
<button onclick="event.stopPropagation(); showToast('修改库位:运单号 ${item.id}')"
|
||||||
|
class="bg-[#EFF6FF] text-[#2563EB] text-xs py-1.5 px-2 rounded-[6px] font-medium h-8">
|
||||||
|
修改库位
|
||||||
|
</button>
|
||||||
|
<button onclick="event.stopPropagation(); showToast('执行出库:运单号 ${item.id}')"
|
||||||
|
class="bg-[#EFF6FF] text-[#2563EB] text-xs py-1.5 px-2 rounded-[6px] font-medium h-8">
|
||||||
|
出库
|
||||||
|
</button>
|
||||||
|
<button onclick="event.stopPropagation(); showToast('执行入库:运单号 ${item.id}')"
|
||||||
|
class="bg-[#EFF6FF] text-[#2563EB] text-xs py-1.5 px-2 rounded-[6px] font-medium h-8">
|
||||||
|
入库
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 状态标签渲染
|
||||||
|
function getStatusTag(status) {
|
||||||
|
let color = '';
|
||||||
|
switch(status) {
|
||||||
|
case '已清仓': color = 'bg-green-100 text-green-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium'; break;
|
||||||
|
case '未清仓': color = 'bg-orange-100 text-orange-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium'; break;
|
||||||
|
}
|
||||||
|
return `<span class="${color}">${status}</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 跳转至进港货物页面,填充数据
|
||||||
|
function showDetail(id) {
|
||||||
|
const listPage = document.getElementById('listPage');
|
||||||
|
const detailPage = document.getElementById('detailPage');
|
||||||
|
|
||||||
|
const data = uldData[id];
|
||||||
|
if (!data) {
|
||||||
|
showToast("暂无该运单详情数据");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 填充基础信息
|
||||||
|
document.getElementById('det-billNo').innerText = data.billNo;
|
||||||
|
document.getElementById('det-agent').innerText = data.agent;
|
||||||
|
document.getElementById('det-code').innerText = data.code;
|
||||||
|
document.getElementById('det-carrier').innerText = data.carrier;
|
||||||
|
document.getElementById('det-route').innerText = data.route;
|
||||||
|
document.getElementById('det-dest').innerText = data.dest;
|
||||||
|
document.getElementById('det-billType').innerText = data.billType;
|
||||||
|
document.getElementById('det-unNo').innerText = data.unNo;
|
||||||
|
document.getElementById('det-ciTime').innerText = data.ciTime;
|
||||||
|
// 锁定状态样式
|
||||||
|
const lockStatusEl = document.getElementById('det-lockStatus');
|
||||||
|
if (data.lockStatus === '锁定') {
|
||||||
|
lockStatusEl.innerHTML = '<iconify-icon icon="mdi:lock" class="mr-1"></iconify-icon>锁定';
|
||||||
|
lockStatusEl.className = 'text-xs font-semibold px-2 py-0.5 rounded-md bg-red-50 text-red-600 inline-flex items-center';
|
||||||
|
} else {
|
||||||
|
lockStatusEl.innerText = '—';
|
||||||
|
lockStatusEl.className = 'text-xs font-semibold text-gray-800';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('det-packType').innerText = data.packType;
|
||||||
|
document.getElementById('det-type').innerText = data.type;
|
||||||
|
document.getElementById('det-outboundTime').innerText = data.outboundTime || '—';
|
||||||
|
document.getElementById('det-itemNameCn').innerText = data.itemNameCn || '—';
|
||||||
|
document.getElementById('det-itemNameEn').innerText = data.itemNameEn || '—';
|
||||||
|
document.getElementById('det-remark').innerText = data.remark || '—';
|
||||||
|
|
||||||
|
// 件重信息
|
||||||
|
document.getElementById('det-pieces').innerText = data.pieces;
|
||||||
|
document.getElementById('det-weight').innerText = data.weight;
|
||||||
|
document.getElementById('det-calcWeight').innerText = data.calcWeight;
|
||||||
|
document.getElementById('det-inPieces').innerText = data.inPieces;
|
||||||
|
document.getElementById('det-inWeight').innerText = data.inWeight;
|
||||||
|
|
||||||
|
// 海关放行标签
|
||||||
|
const customsReleaseEl = document.getElementById('det-customsRelease');
|
||||||
|
if (data.customsRelease === '11') {
|
||||||
|
customsReleaseEl.innerText = '11';
|
||||||
|
customsReleaseEl.className = 'text-xs font-semibold px-2 py-0.5 rounded-md bg-green-50 text-green-600 inline-block';
|
||||||
|
} else {
|
||||||
|
customsReleaseEl.innerText = data.customsRelease;
|
||||||
|
customsReleaseEl.className = 'text-xs font-semibold px-2 py-0.5 rounded-md bg-gray-100 text-gray-600 inline-block';
|
||||||
|
}
|
||||||
|
document.getElementById('det-originalManifest').innerText = data.originalManifest;
|
||||||
|
document.getElementById('det-tallyReport').innerText = data.tallyReport;
|
||||||
|
|
||||||
|
// 渲染仓库批次
|
||||||
|
const warehouseContainer = document.getElementById('tab-content-1');
|
||||||
|
warehouseContainer.innerHTML = '';
|
||||||
|
data.warehouse.forEach(item => {
|
||||||
|
warehouseContainer.innerHTML += `
|
||||||
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
||||||
|
<div class="flex justify-between items-center pt-3 pb-1.5 px-3 mb-2 border-b border-gray-100">
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<span class="w-1.5 h-1.5 rounded-full bg-blue-500 inline-block"></span>
|
||||||
|
<span class="text-xs font-semibold text-gray-900">批次号: ${item.batch}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-1.5 px-3 pb-2">
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">件数</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${item.pieces}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">重量</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${parseFloat(item.weight).toFixed(1)} kg</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">航班日期</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${item.flightDate}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">航班号</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${item.flightNo}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">始发站</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${item.route}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">目的站</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${item.dest}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 渲染库位信息
|
||||||
|
const locationContainer = document.getElementById('tab-content-2');
|
||||||
|
locationContainer.innerHTML = '';
|
||||||
|
data.locations.forEach(loc => {
|
||||||
|
locationContainer.innerHTML += `
|
||||||
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
||||||
|
<div class="flex justify-between items-center pt-3 pb-1.5 px-3 mb-2 border-b border-gray-100">
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<span class="w-1.5 h-1.5 rounded-full bg-blue-500 inline-block"></span>
|
||||||
|
<span class="text-xs font-bold text-gray-900">${loc.id}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-1.5 px-3 pb-2">
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">入库人</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${loc.inPerson}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">入库时间</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${loc.inTime}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">出库人</div>
|
||||||
|
<div class="text-xs ${loc.outPerson === '—' ? 'text-gray-500' : 'text-gray-800'} font-semibold">${loc.outPerson}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">出库时间</div>
|
||||||
|
<div class="text-xs ${loc.outTime === '—' ? 'text-gray-500' : 'text-gray-800'} font-semibold">${loc.outTime}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 默认激活运单信息标签
|
||||||
|
switchTab(0);
|
||||||
|
// 页面切换动画:列表左滑隐藏,详情滑入
|
||||||
|
listPage.classList.add('page-hidden-left');
|
||||||
|
detailPage.classList.remove('page-hidden-right');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回列表页
|
||||||
|
function goBack() {
|
||||||
|
const listPage = document.getElementById('listPage');
|
||||||
|
const detailPage = document.getElementById('detailPage');
|
||||||
|
listPage.classList.remove('page-hidden-left');
|
||||||
|
detailPage.classList.add('page-hidden-right');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换详情标签页
|
||||||
|
function switchTab(index) {
|
||||||
|
const tabs = document.querySelectorAll('.tab-item');
|
||||||
|
const contents = document.querySelectorAll('.tab-pane');
|
||||||
|
tabs.forEach((tab, i) => {
|
||||||
|
if (i === index) {
|
||||||
|
tab.classList.add('active');
|
||||||
|
contents[i].classList.remove('hidden');
|
||||||
|
} else {
|
||||||
|
tab.classList.remove('active');
|
||||||
|
contents[i].classList.add('hidden');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toast提示
|
||||||
|
function showToast(msg) {
|
||||||
|
const toast = document.getElementById('toast');
|
||||||
|
toast.innerText = msg;
|
||||||
|
toast.classList.remove('hidden');
|
||||||
|
setTimeout(() => toast.classList.add('hidden'), 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选弹窗方法
|
||||||
|
function openFilter() {
|
||||||
|
const filterOverlay = document.getElementById('filterOverlay');
|
||||||
|
const filterSheet = document.getElementById('filterSheet');
|
||||||
|
filterOverlay.classList.add('show');
|
||||||
|
setTimeout(() => filterSheet.classList.add('show'), 10);
|
||||||
|
}
|
||||||
|
function closeFilter() {
|
||||||
|
const filterOverlay = document.getElementById('filterOverlay');
|
||||||
|
const filterSheet = document.getElementById('filterSheet');
|
||||||
|
filterSheet.classList.remove('show');
|
||||||
|
setTimeout(() => filterOverlay.classList.remove('show'), 250);
|
||||||
|
}
|
||||||
|
function resetFilter() {
|
||||||
|
document.querySelectorAll('.filter-input').forEach(input => {
|
||||||
|
input.value = '';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function confirmFilter() {
|
||||||
|
const params = {
|
||||||
|
flightDate: document.getElementById('filterFlightDate')?.value || '',
|
||||||
|
flightNo: document.getElementById('filterFlightNo')?.value || '',
|
||||||
|
agent: '',
|
||||||
|
code: '',
|
||||||
|
origin: document.getElementById('filterOrigin')?.value || '',
|
||||||
|
billType: '',
|
||||||
|
bizType: '',
|
||||||
|
cnName: document.getElementById('filterCnName')?.value || ''
|
||||||
|
};
|
||||||
|
console.log('筛选参数:', params);
|
||||||
|
alert('筛选执行成功,控制台可查看筛选条件');
|
||||||
|
closeFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 扫码弹窗
|
||||||
|
function toggleScanOverlay(show) {
|
||||||
|
const overlay = document.getElementById('scanOverlay');
|
||||||
|
if (show) overlay.classList.remove('hidden');
|
||||||
|
else overlay.classList.add('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面加载完成初始化
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
renderList();
|
||||||
|
// 筛选遮罩点击关闭
|
||||||
|
const filterOverlay = document.getElementById('filterOverlay');
|
||||||
|
filterOverlay.addEventListener('click', function(e) {
|
||||||
|
if (e.target === filterOverlay) closeFilter();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
773
documents/5.5寸手持端设计文件/09_提取出库/提取出库.html
Normal file
773
documents/5.5寸手持端设计文件/09_提取出库/提取出库.html
Normal file
@@ -0,0 +1,773 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
|
||||||
|
<title>提取出库 - 移动端原型</title>
|
||||||
|
<!-- Tailwind CSS -->
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/tailwindcss.js"></script>
|
||||||
|
<!-- Iconify -->
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/iconify-icon.min.js"></script>
|
||||||
|
<style>
|
||||||
|
@font-face {
|
||||||
|
font-family: 'PingFang SC';
|
||||||
|
src: local('PingFang SC');
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: 'PingFang SC', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||||
|
background-color: #e2e8f0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
/* 模拟手机容器 */
|
||||||
|
.phone-container {
|
||||||
|
width: 375px;
|
||||||
|
height: 812px;
|
||||||
|
background-color: #f5f6fa;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
||||||
|
border: 8px solid #1a1a1a;
|
||||||
|
border-radius: 40px;
|
||||||
|
}
|
||||||
|
/* 隐藏滚动条但保留功能 */
|
||||||
|
.no-scrollbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.no-scrollbar {
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
/* 页面切换动画 */
|
||||||
|
.page {
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.page.active {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
/* 筛选面板动画 */
|
||||||
|
#filter-panel {
|
||||||
|
transform: translateY(100%);
|
||||||
|
transition: transform 0.3s ease-out;
|
||||||
|
}
|
||||||
|
#filter-panel.show {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
.overlay {
|
||||||
|
background-color: rgba(0,0,0,0.5);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.overlay.show {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
/* 按钮点击态 */
|
||||||
|
.btn-active:active {
|
||||||
|
opacity: 0.7;
|
||||||
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
|
/* 复选框样式 */
|
||||||
|
.custom-checkbox {
|
||||||
|
appearance: none;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border: 2px solid #cbd5e1;
|
||||||
|
border-radius: 4px;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.2s;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
.custom-checkbox:checked {
|
||||||
|
background-color: #2563EB;
|
||||||
|
border-color: #2563EB;
|
||||||
|
}
|
||||||
|
.custom-checkbox:checked::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 6px;
|
||||||
|
top: 2px;
|
||||||
|
width: 5px;
|
||||||
|
height: 10px;
|
||||||
|
border: solid white;
|
||||||
|
border-width: 0 2px 2px 0;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
.custom-checkbox-round {
|
||||||
|
appearance: none;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border: 2px solid #cbd5e1;
|
||||||
|
border-radius: 50%;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.2s;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
.custom-checkbox-round:checked {
|
||||||
|
background-color: #2563EB;
|
||||||
|
border-color: #2563EB;
|
||||||
|
}
|
||||||
|
.custom-checkbox-round:checked::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 6px;
|
||||||
|
top: 2px;
|
||||||
|
width: 5px;
|
||||||
|
height: 10px;
|
||||||
|
border: solid white;
|
||||||
|
border-width: 0 2px 2px 0;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
/* 卡片选中样式已移除 */
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="phone-container">
|
||||||
|
<!-- 状态栏模拟 -->
|
||||||
|
<div class="h-10 w-full flex justify-between items-center px-8 flex-none bg-[#2563EB] text-white">
|
||||||
|
<span class="text-xs font-semibold">09:41</span>
|
||||||
|
<div class="flex space-x-1 items-center">
|
||||||
|
<iconify-icon icon="mdi:signal" width="14"></iconify-icon>
|
||||||
|
<iconify-icon icon="mdi:wifi" width="14"></iconify-icon>
|
||||||
|
<iconify-icon icon="mdi:battery" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 页面1: 货运列表首页 -->
|
||||||
|
<div class="page active" id="page-home">
|
||||||
|
<!-- 顶部导航 -->
|
||||||
|
<div class="bg-[#2563EB] text-white h-12 flex items-center justify-between px-4 flex-none">
|
||||||
|
<div class="flex items-center btn-active" onclick="alert('返回首页')">
|
||||||
|
<iconify-icon icon="mdi:chevron-left" width="28"></iconify-icon>
|
||||||
|
<span class="text-sm font-bold -ml-1">返回</span>
|
||||||
|
</div>
|
||||||
|
<h1 class="text-lg font-medium">提取出库</h1>
|
||||||
|
<div class="w-16"></div>
|
||||||
|
</div>
|
||||||
|
<!-- 内容滚动区 -->
|
||||||
|
<div class="flex-1 overflow-y-auto no-scrollbar pb-24">
|
||||||
|
<!-- 搜索栏 -->
|
||||||
|
<section class="px-4 pt-4 pb-3 bg-white">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 shadow-sm rounded-[12px] h-10 px-3 gap-2 flex-1">
|
||||||
|
<iconify-icon class="text-gray-400 text-lg flex-none" icon="mdi:magnify"></iconify-icon>
|
||||||
|
<input class="flex-1 bg-transparent text-[14px] text-gray-800 placeholder-gray-400 outline-none border-none rounded-lg px-2" placeholder="搜索运单号" type="text"/>
|
||||||
|
<button class="flex-none text-blue-500">
|
||||||
|
<iconify-icon class="text-lg" icon="mdi:qrcode-scan"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button class="bg-white p-2.5 rounded-full shadow-sm border border-gray-200 text-[#2563EB] flex items-center justify-center flex-none" onclick="toggleFilterDrawer(true)">
|
||||||
|
<iconify-icon class="text-xl" icon="mdi:filter-variant"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- 子Tab切换栏 -->
|
||||||
|
<div class="flex bg-white border-b sticky top-0 z-20">
|
||||||
|
<button class="flex-1 py-3 text-sm font-bold text-[#1F2937] border-b-2 border-[#1F2937] transition-all" id="tab-pending" onclick="switchTab('pending')">
|
||||||
|
待出库 <span class="bg-[#DBEAF6] text-[#2563EB] text-[11px] font-medium px-1.5 py-0.5 rounded-md ml-1.5">3</span>
|
||||||
|
</button>
|
||||||
|
<button class="flex-1 py-3 text-sm font-bold text-gray-400 border-b-2 border-transparent transition-all" id="tab-shipped" onclick="switchTab('shipped')">
|
||||||
|
已出库 <span class="bg-[#DBEAF6] text-[#2563EB] text-[11px] font-medium px-1.5 py-0.5 rounded-md ml-1.5">3</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- 列表内容 -->
|
||||||
|
<div class="p-3 pt-4 space-y-3" id="list-pending">
|
||||||
|
<!-- 卡片 1 -->
|
||||||
|
<div class="pending-card bg-white rounded-xl shadow-sm p-4 mb-3 overflow-hidden">
|
||||||
|
<!-- 顶部行 -->
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input class="item-checkbox custom-checkbox-round flex-none" onclick="handleCheckboxClick(this, event)" type="checkbox"/>
|
||||||
|
<div class="text-[#2563EB] text-[15px] font-bold">78133363573</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="bg-orange-100 text-orange-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">待出库</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 提货车辆行 -->
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:airplane"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">提货车辆:皖A88909</span>
|
||||||
|
</div>
|
||||||
|
<!-- 统计框 -->
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">代理人</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">ATR</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">件数</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">100件</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">重量</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">200kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 库位信息行 -->
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:map-marker"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">库位:A区-03货位</span>
|
||||||
|
</div>
|
||||||
|
<!-- 查看详情链接 -->
|
||||||
|
<div class="mt-4 flex justify-end border-t border-gray-100 pt-3">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer btn-active" onclick="showDetail({id: '78133363573', status: '待出库', agent: 'ATR', flightDate: '20260706', flightNo: 'MU1111', pieces: '100', weight: '200', goodsName: '电子元器件', carrier: 'MU', origin: 'LAX', location: 'A区-03货位', code: 'NOR', counterPerson: '--', counterTime: '--', outboundPerson: '', outboundTime: ''})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片 2 -->
|
||||||
|
<div class="pending-card bg-white rounded-xl shadow-sm p-4 mb-3 overflow-hidden">
|
||||||
|
<!-- 顶部行 -->
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input class="item-checkbox custom-checkbox-round flex-none" onclick="handleCheckboxClick(this, event)" type="checkbox"/>
|
||||||
|
<div class="text-[#2563EB] text-[15px] font-bold">78133363574</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="bg-orange-100 text-orange-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">待出库</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 提货车辆行 -->
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:airplane"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">提货车辆:皖A78223</span>
|
||||||
|
</div>
|
||||||
|
<!-- 统计框 -->
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">代理人</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">CTA</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">件数</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">85件</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">重量</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">150kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 库位信息行 -->
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:map-marker"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">库位:B区-05货位</span>
|
||||||
|
</div>
|
||||||
|
<!-- 查看详情链接 -->
|
||||||
|
<div class="mt-4 flex justify-end border-t border-gray-100 pt-3">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer btn-active" onclick="showDetail({id: '78133363574', status: '待出库', agent: 'CTA', flightDate: '20260706', flightNo: 'CA2222', pieces: '85', weight: '150', goodsName: '服装鞋帽', carrier: 'CA', origin: 'PEK', location: 'B区-05货位', code: 'ATR', counterPerson: '--', counterTime: '--', outboundPerson: '', outboundTime: ''})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片 3 -->
|
||||||
|
<div class="pending-card bg-white rounded-xl shadow-sm p-4 mb-3 overflow-hidden">
|
||||||
|
<!-- 顶部行 -->
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input class="item-checkbox custom-checkbox-round flex-none" onclick="handleCheckboxClick(this, event)" type="checkbox"/>
|
||||||
|
<div class="text-[#2563EB] text-[15px] font-bold">78133363575</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="bg-orange-100 text-orange-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">待出库</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 提货车辆行 -->
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:airplane"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">提货车辆:皖A67651</span>
|
||||||
|
</div>
|
||||||
|
<!-- 统计框 -->
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">代理人</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">DHL</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">件数</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">200件</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">重量</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">450kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 库位信息行 -->
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:map-marker"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">库位:C区-01货位</span>
|
||||||
|
</div>
|
||||||
|
<!-- 查看详情链接 -->
|
||||||
|
<div class="mt-4 flex justify-end border-t border-gray-100 pt-3">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer btn-active" onclick="showDetail({id: '78133363575', status: '待出库', agent: 'DHL', flightDate: '20260707', flightNo: '3U3333', pieces: '200', weight: '450', goodsName: '精密模具', carrier: '3U', origin: 'CTU', location: 'C区-01货位', code: 'ATR', counterPerson: '--', counterTime: '--', outboundPerson: '', outboundTime: ''})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 已出库列表内容 -->
|
||||||
|
<div class="p-3 pt-4 space-y-3 hidden" id="list-shipped">
|
||||||
|
<!-- 卡片 1 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm p-4 mb-3">
|
||||||
|
<!-- 顶部行 -->
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="text-[#1F2937] text-[15px] font-bold">78133363001</div>
|
||||||
|
<div class="flex items-center gap-1 text-[#1F2937] text-[13px] font-medium">
|
||||||
|
<iconify-icon class="text-[#10B981]" icon="mdi:check-circle" width="16"></iconify-icon>
|
||||||
|
<span>已出库</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 操作信息行 -->
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:airplane"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">提货车辆:皖A23422</span>
|
||||||
|
</div>
|
||||||
|
<!-- 统计框 -->
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">代理人</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">ATR</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">件数</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">50件</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">重量</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">80kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 操作人信息 -->
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:account-outline"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">出库人:张三 · 出库时间:2026-07-05 11:45</span>
|
||||||
|
</div>
|
||||||
|
<!-- 查看详情链接 -->
|
||||||
|
<div class="mt-2 flex justify-end border-t border-gray-50 pt-2">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer" onclick="showDetail({id: '78133363001', status: '已出库', agent: 'ATR', flightDate: '20260704', flightNo: 'MU1111', pieces: '50', weight: '80', pickupNo: 'TH20260701001', goodsName: '精密仪器', carrier: 'MU', origin: 'LAX', location: 'B区-05货位', code: 'ATR', counterTime: '2026-07-05 10:30', counterPerson: '张三', outboundTime: '2026-07-05 11:45', outboundPerson: '张三'})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片 2 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm p-4 mb-3">
|
||||||
|
<!-- 顶部行 -->
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="text-[#1F2937] text-[15px] font-bold">78133363002</div>
|
||||||
|
<div class="flex items-center gap-1 text-[#1F2937] text-[13px] font-medium">
|
||||||
|
<iconify-icon class="text-[#10B981]" icon="mdi:check-circle" width="16"></iconify-icon>
|
||||||
|
<span>已出库</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 操作信息行 -->
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:airplane"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">提货车辆:皖A79909</span>
|
||||||
|
</div>
|
||||||
|
<!-- 统计框 -->
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">代理人</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">CTA</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">件数</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">120件</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">重量</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">300kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 操作人信息 -->
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:account-outline"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">出库人:赵六 · 出库时间:2026-07-06 10:30</span>
|
||||||
|
</div>
|
||||||
|
<!-- 查看详情链接 -->
|
||||||
|
<div class="mt-2 flex justify-end border-t border-gray-50 pt-2">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer" onclick="showDetail({id: '78133363002', status: '已出库', agent: 'CTA', flightDate: '20260705', flightNo: 'CA2222', pieces: '120', weight: '300', pickupNo: 'TH20260702002', goodsName: '鲜花绿植', carrier: 'CA', origin: 'SFO', location: 'A区-08货位', code: 'ATR', counterTime: '2026-07-06 09:15', counterPerson: '王五', outboundTime: '2026-07-06 10:30', outboundPerson: '赵六'})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片 3 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm p-4 mb-3">
|
||||||
|
<!-- 顶部行 -->
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="text-[#1F2937] text-[15px] font-bold">78133363003</div>
|
||||||
|
<div class="flex items-center gap-1 text-[#1F2937] text-[13px] font-medium">
|
||||||
|
<iconify-icon class="text-[#10B981]" icon="mdi:check-circle" width="16"></iconify-icon>
|
||||||
|
<span>已出库</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 操作信息行 -->
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:airplane"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">提货车辆:皖A66712</span>
|
||||||
|
</div>
|
||||||
|
<!-- 统计框 -->
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">代理人</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">DHL</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">件数</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">75件</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">重量</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">160kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 操作人信息 -->
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:account-outline"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">出库人:孙八 · 出库时间:2026-07-06 15:20</span>
|
||||||
|
</div>
|
||||||
|
<!-- 查看详情链接 -->
|
||||||
|
<div class="mt-2 flex justify-end border-t border-gray-50 pt-2">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer" onclick="showDetail({id: '78133363003', status: '已出库', agent: 'DHL', flightDate: '20260705', flightNo: '3U3333', pieces: '75', weight: '160', pickupNo: 'TH20260703003', goodsName: '生鲜食品', carrier: '3U', origin: 'CDG', location: 'D区-02货位', code: 'NOR', counterTime: '2026-07-06 14:00', counterPerson: '钱七', outboundTime: '2026-07-06 15:20', outboundPerson: '孙八'})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 底部工具栏 -->
|
||||||
|
<div class="absolute bottom-0 w-full bg-white border-t border-gray-200 z-40 flex flex-col pt-4 pb-4" id="bottom-toolbar">
|
||||||
|
<!-- 操作区域 -->
|
||||||
|
<div class="px-4 flex items-center w-full">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input class="custom-checkbox-round" id="select-all-cb" onclick="toggleSelectAll(this.checked)" type="checkbox"/>
|
||||||
|
<label class="text-[13px] text-[#1F2937] font-medium cursor-pointer" for="select-all-cb">全选</label>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1"></div>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<span class="text-[12px] text-[#9CA3AF]">已选 <span id="selected-count">0</span> 项</span>
|
||||||
|
<button class="bg-[#2563EB] text-white text-[15px] font-bold px-5 py-2 rounded-[10px] shadow-lg shadow-blue-500/25 btn-active" onclick="alert('出库操作')">
|
||||||
|
出库
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 页面2: 详情页 -->
|
||||||
|
<div class="page" id="page-detail">
|
||||||
|
<!-- 顶部导航 -->
|
||||||
|
<div class="bg-[#2563EB] text-white h-12 flex items-center justify-between px-4 flex-none">
|
||||||
|
<div class="flex items-center btn-active" onclick="switchPage('home')">
|
||||||
|
<iconify-icon icon="mdi:chevron-left" width="28"></iconify-icon>
|
||||||
|
<span class="text-sm font-bold -ml-1">返回</span>
|
||||||
|
</div>
|
||||||
|
<h1 class="text-lg font-medium">运单详情</h1>
|
||||||
|
<div class="w-16"></div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 overflow-y-auto no-scrollbar pb-8 p-4">
|
||||||
|
<!-- 货运单据样式卡片 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm overflow-hidden border border-gray-100">
|
||||||
|
<!-- 1. 顶部蓝色条带 -->
|
||||||
|
<div class="bg-[#2563EB] px-4 py-3 flex justify-between items-center text-white">
|
||||||
|
<span class="font-bold text-[17px] leading-tight" id="detail-awb">781-22222620</span>
|
||||||
|
<div class="flex items-center text-[13px] font-normal opacity-90">
|
||||||
|
<span class="w-2 h-2 bg-green-400 rounded-full mr-1.5"></span>
|
||||||
|
<span id="detail-time">2026-05-10 08:30</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-4">
|
||||||
|
<!-- 2. 标签区 -->
|
||||||
|
<div class="flex items-center justify-between mb-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="bg-[#EF4444] text-white text-[11px] px-1.5 py-0.5 rounded leading-tight font-medium">国际进港</span>
|
||||||
|
<span class="text-[13px] font-normal text-[#666666] border-l border-gray-300 pl-2">普通货物运输</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 3. 货物名称 -->
|
||||||
|
<div class="text-[22px] font-bold text-[#111827] mb-3" id="detail-goods-name">电子元器件</div>
|
||||||
|
<!-- 4. 两列信息表格 -->
|
||||||
|
<div class="grid grid-cols-2 gap-x-8 gap-y-3">
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">件数</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-count">55</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">重量</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-weight">622.00 kg</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">特码</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-code">NOR</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">代理</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-agent">ATR</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">始发港</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-origin">LAX</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">目的港</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-carrier">MU</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">航班日期</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-flight-date">20260706</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">航班号</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-flight-no">MU1111</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">库位</div>
|
||||||
|
<div class="flex">
|
||||||
|
<span class="bg-orange-50 text-orange-600 px-1 rounded text-[15px] font-bold" id="detail-location">1111111</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">提货单号</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-delivery-no">TH20260706001</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 提货信息卡片 -->
|
||||||
|
<div class="mt-4 bg-white rounded-xl shadow-sm overflow-hidden border border-gray-200 hidden" id="detail-outbound-card">
|
||||||
|
<div class="bg-[#10B981] px-4 py-2.5">
|
||||||
|
<span class="text-white font-semibold text-[15px]">提货信息</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white px-4 py-3 grid grid-cols-2 gap-y-3">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[12px] text-[#9CA3AF] font-normal mb-[2px]">柜台办理人</span>
|
||||||
|
<span class="text-[14px] text-[#1F2937] font-medium" id="detail-counter-person">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[12px] text-[#9CA3AF] font-normal mb-[2px]">柜台办理时间</span>
|
||||||
|
<span class="text-[14px] text-[#1F2937] font-medium" id="detail-counter-time">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col" id="detail-outbound-person-row">
|
||||||
|
<span class="text-[12px] text-[#9CA3AF] font-normal mb-[2px]">出库人</span>
|
||||||
|
<span class="text-[14px] text-[#1F2937] font-medium" id="detail-outbound-person">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col" id="detail-outbound-time-row">
|
||||||
|
<span class="text-[12px] text-[#9CA3AF] font-normal mb-[2px]">出库时间</span>
|
||||||
|
<span class="text-[14px] text-[#1F2937] font-medium" id="detail-outbound-time">-</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 底部筛选面板蒙层 -->
|
||||||
|
<div class="overlay absolute inset-0 z-40" id="filter-overlay" onclick="toggleFilterDrawer(false)"></div>
|
||||||
|
<!-- 筛选面板 -->
|
||||||
|
<div class="absolute bottom-0 w-full bg-white rounded-t-3xl z-50 p-6 shadow-2xl overflow-hidden" id="filter-panel">
|
||||||
|
<!-- 标题 + 关闭按钮 -->
|
||||||
|
<div class="relative flex items-center justify-center mb-6">
|
||||||
|
<h2 class="text-[18px] font-bold text-gray-900">筛选条件</h2>
|
||||||
|
<button class="absolute right-0 top-0 text-gray-400" onclick="toggleFilterDrawer(false)">
|
||||||
|
<iconify-icon class="text-2xl" icon="mdi:close"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-4">
|
||||||
|
<!-- 航班日期 -->
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">航班日期</label>
|
||||||
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-3 flex items-center justify-between text-gray-400">
|
||||||
|
<span class="text-sm">请选择航班日期</span>
|
||||||
|
<iconify-icon class="text-gray-400" icon="mdi:calendar-month-outline"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 航班号 -->
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">航班号</label>
|
||||||
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-3 flex items-center justify-between">
|
||||||
|
<input class="bg-transparent outline-none text-sm w-full text-gray-800" placeholder="请输入航班号" type="text"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 代理人 -->
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">代理人</label>
|
||||||
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-3 flex items-center justify-between text-gray-400">
|
||||||
|
<span class="text-sm">请选择代理人</span>
|
||||||
|
<iconify-icon icon="mdi:chevron-down"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 特码 -->
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">特码</label>
|
||||||
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-3 flex items-center justify-between text-gray-400">
|
||||||
|
<span class="text-sm">请选择特码</span>
|
||||||
|
<iconify-icon icon="mdi:chevron-down"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-4 pt-2">
|
||||||
|
<button class="flex-1 bg-white border border-gray-300 text-gray-600 py-3.5 rounded-xl font-bold btn-active" onclick="alert('已重置')">
|
||||||
|
重置
|
||||||
|
</button>
|
||||||
|
<button class="flex-1 bg-[#2563EB] text-white py-3.5 rounded-xl font-bold shadow-lg shadow-blue-500/20 btn-active" onclick="toggleFilterDrawer(false)">
|
||||||
|
确认
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
// 页面切换逻辑
|
||||||
|
function switchPage(pageId) {
|
||||||
|
document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
|
||||||
|
document.getElementById('page-' + pageId).classList.add('active');
|
||||||
|
|
||||||
|
// 如果进入详情页,可以重置滚动
|
||||||
|
if(pageId === 'detail') {
|
||||||
|
document.querySelector('#page-detail .overflow-y-auto').scrollTop = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 子Tab切换逻辑
|
||||||
|
function switchTab(type) {
|
||||||
|
const tabPending = document.getElementById('tab-pending');
|
||||||
|
const tabShipped = document.getElementById('tab-shipped');
|
||||||
|
const listPending = document.getElementById('list-pending');
|
||||||
|
const listShipped = document.getElementById('list-shipped');
|
||||||
|
const bottomToolbar = document.getElementById('bottom-toolbar');
|
||||||
|
|
||||||
|
if (type === 'pending') {
|
||||||
|
tabPending.classList.add('text-[#1F2937]', 'border-[#1F2937]');
|
||||||
|
tabPending.classList.remove('text-gray-400', 'border-transparent');
|
||||||
|
tabShipped.classList.add('text-gray-400', 'border-transparent');
|
||||||
|
tabShipped.classList.remove('text-[#1F2937]', 'border-[#1F2937]');
|
||||||
|
|
||||||
|
listPending.classList.remove('hidden');
|
||||||
|
listShipped.classList.add('hidden');
|
||||||
|
bottomToolbar.style.display = 'flex';
|
||||||
|
} else {
|
||||||
|
tabShipped.classList.add('text-[#1F2937]', 'border-[#1F2937]');
|
||||||
|
tabShipped.classList.remove('text-gray-400', 'border-transparent');
|
||||||
|
tabPending.classList.add('text-gray-400', 'border-transparent');
|
||||||
|
tabPending.classList.remove('text-[#1F2937]', 'border-[#1F2937]');
|
||||||
|
|
||||||
|
listShipped.classList.remove('hidden');
|
||||||
|
listPending.classList.add('hidden');
|
||||||
|
bottomToolbar.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全选/取消全选
|
||||||
|
function toggleSelectAll(checked) {
|
||||||
|
const checkboxes = document.querySelectorAll('.item-checkbox');
|
||||||
|
checkboxes.forEach(cb => {
|
||||||
|
cb.checked = checked;
|
||||||
|
updateCardStyle(cb);
|
||||||
|
});
|
||||||
|
updateSelectionCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理卡片复选框点击
|
||||||
|
function handleCheckboxClick(checkbox, event) {
|
||||||
|
event.stopPropagation(); // 阻止触发卡片详情点击
|
||||||
|
updateCardStyle(checkbox);
|
||||||
|
updateSelectionCount();
|
||||||
|
|
||||||
|
// 更新全选状态
|
||||||
|
const checkboxes = document.querySelectorAll('.item-checkbox');
|
||||||
|
const selectAllCb = document.getElementById('select-all-cb');
|
||||||
|
const allChecked = Array.from(checkboxes).every(cb => cb.checked);
|
||||||
|
selectAllCb.checked = allChecked;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新卡片选中样式 (已根据需求移除背景和边框变化,仅保留复选框状态)
|
||||||
|
function updateCardStyle(checkbox) {
|
||||||
|
// 卡片不再随选中状态改变背景和边框颜色
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新选中计数
|
||||||
|
function updateSelectionCount() {
|
||||||
|
const checkedCount = document.querySelectorAll('.item-checkbox:checked').length;
|
||||||
|
document.getElementById('selected-count').textContent = checkedCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示详情页并填充数据
|
||||||
|
function showDetail(data) {
|
||||||
|
if (!data) return;
|
||||||
|
|
||||||
|
const setText = (id, text) => {
|
||||||
|
const el = document.getElementById(id);
|
||||||
|
if (el) el.textContent = text || '-';
|
||||||
|
};
|
||||||
|
|
||||||
|
setText('detail-awb', data.id);
|
||||||
|
setText('detail-time', new Date().toISOString().replace('T', ' ').substring(0, 16));
|
||||||
|
setText('detail-goods-name', data.goodsName);
|
||||||
|
setText('detail-count', data.pieces);
|
||||||
|
setText('detail-weight', data.weight + (data.weight && data.weight.toString().includes('kg') ? '' : ' kg'));
|
||||||
|
setText('detail-code', data.code);
|
||||||
|
setText('detail-agent', data.agent);
|
||||||
|
setText('detail-carrier', data.carrier);
|
||||||
|
setText('detail-origin', data.origin);
|
||||||
|
setText('detail-flight-date', data.flightDate);
|
||||||
|
setText('detail-flight-no', data.flightNo);
|
||||||
|
setText('detail-location', data.location);
|
||||||
|
setText('detail-delivery-no', data.pickupNo);
|
||||||
|
|
||||||
|
const outboundCard = document.getElementById('detail-outbound-card');
|
||||||
|
if (outboundCard) {
|
||||||
|
// 始终显示提货信息卡片
|
||||||
|
outboundCard.classList.remove('hidden');
|
||||||
|
|
||||||
|
setText('detail-counter-person', data.counterPerson);
|
||||||
|
setText('detail-counter-time', data.counterTime);
|
||||||
|
setText('detail-outbound-person', data.outboundPerson);
|
||||||
|
setText('detail-outbound-time', data.outboundTime);
|
||||||
|
|
||||||
|
const outboundPersonRow = document.getElementById('detail-outbound-person-row');
|
||||||
|
const outboundTimeRow = document.getElementById('detail-outbound-time-row');
|
||||||
|
|
||||||
|
if (data.status === '已出库') {
|
||||||
|
// 已出库显示全部
|
||||||
|
if (outboundPersonRow) outboundPersonRow.classList.remove('hidden');
|
||||||
|
if (outboundTimeRow) outboundTimeRow.classList.remove('hidden');
|
||||||
|
} else {
|
||||||
|
// 待出库隐藏出库人信息
|
||||||
|
if (outboundPersonRow) outboundPersonRow.classList.add('hidden');
|
||||||
|
if (outboundTimeRow) outboundTimeRow.classList.add('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switchPage('detail');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选面板显示隐藏
|
||||||
|
function toggleFilterDrawer(show) {
|
||||||
|
const panel = document.getElementById('filter-panel');
|
||||||
|
const overlay = document.getElementById('filter-overlay');
|
||||||
|
if (show) {
|
||||||
|
panel.classList.add('show');
|
||||||
|
overlay.classList.add('show');
|
||||||
|
} else {
|
||||||
|
panel.classList.remove('show');
|
||||||
|
overlay.classList.remove('show');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化显示日期
|
||||||
|
const today = new Date().toISOString().split('T')[0];
|
||||||
|
console.log("System date initialized:", today);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
147
documents/5.5寸手持端设计文件/10_进港查询/运单追踪.html
Normal file
147
documents/5.5寸手持端设计文件/10_进港查询/运单追踪.html
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
|
||||||
|
<title>国际进港查询 - 物流跟踪</title>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/tailwindcss.js"></script>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/iconify-icon.min.js"></script>
|
||||||
|
<style>
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
src: local('sans-serif');
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
|
.no-scrollbar::-webkit-scrollbar { display: none; }
|
||||||
|
.no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
|
||||||
|
|
||||||
|
/* 模拟手机容器阴影 */
|
||||||
|
.phone-shell {
|
||||||
|
box-shadow: 0 50px 100px -20px rgba(0,0,0,0.25), 0 30px 60px -30px rgba(0,0,0,0.3);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="bg-gray-200 flex justify-center items-center min-h-screen p-4">
|
||||||
|
<!-- 模拟手机屏幕容器 -->
|
||||||
|
<div class="phone-shell w-[375px] h-[812px] bg-[#F5F5F7] overflow-hidden flex flex-col relative rounded-[48px] border-[10px] border-gray-900">
|
||||||
|
<!-- 顶部蓝色区域 (包含状态栏和导航栏) -->
|
||||||
|
<div class="bg-[#1A73E8] flex-none">
|
||||||
|
<!-- 系统状态栏模拟 -->
|
||||||
|
<div class="h-11 w-full flex justify-between items-center px-8 text-white">
|
||||||
|
<span class="text-[15px] font-bold">09:41</span>
|
||||||
|
<div class="flex gap-1.5 items-center">
|
||||||
|
<iconify-icon class="text-sm" icon="mdi:signal-cellular-3"></iconify-icon>
|
||||||
|
<iconify-icon class="text-base" icon="mdi:wifi"></iconify-icon>
|
||||||
|
<iconify-icon class="text-xl" icon="mdi:battery"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 导航栏 -->
|
||||||
|
<div class="h-[44px] px-4 flex items-center justify-between">
|
||||||
|
<button class="flex items-center text-white space-x-0.5">
|
||||||
|
<iconify-icon class="text-2xl" icon="mdi:chevron-left"></iconify-icon>
|
||||||
|
<span class="text-base">返回</span>
|
||||||
|
</button>
|
||||||
|
<h1 class="text-lg font-bold text-white absolute left-1/2 -translate-x-1/2">运单追踪</h1>
|
||||||
|
<div class="w-10"></div> <!-- 占位保持平衡 -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 可滚动内容区 -->
|
||||||
|
<div class="flex-1 overflow-y-auto no-scrollbar px-5 pt-6 pb-12">
|
||||||
|
<!-- 流转状态卡片 -->
|
||||||
|
<div class="bg-white rounded-2xl p-5 shadow-sm border border-gray-100/50 mb-5">
|
||||||
|
<!-- 运单号 Header -->
|
||||||
|
<div class="flex items-center justify-between pt-2 pb-5 mb-8 border-b border-gray-100">
|
||||||
|
<div class="text-xl font-black text-gray-900 leading-none tracking-tight">
|
||||||
|
78133358743
|
||||||
|
</div>
|
||||||
|
<span class="text-[11px] font-medium text-blue-600 bg-blue-50 px-2.5 py-1 rounded-full border border-blue-100">国际进港</span>
|
||||||
|
</div>
|
||||||
|
<!-- 流转状态标题 -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<h2 class="text-base font-semibold text-gray-700 flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4 text-gray-700 inline-block" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewbox="0 0 24 24">
|
||||||
|
<circle cx="12" cy="12" r="10"></circle>
|
||||||
|
<polyline points="12 6 12 12 16 14"></polyline>
|
||||||
|
</svg>
|
||||||
|
流转状态
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div class="relative pl-7 pb-2">
|
||||||
|
<div class="absolute left-[9px] top-2 bottom-4 w-[2px] bg-gray-100"></div>
|
||||||
|
|
||||||
|
<!-- 状态 1: 当前 -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<div class="absolute -left-[27px] top-1 w-[20px] h-[20px] rounded-full bg-green-600 border-4 border-green-100 flex items-center justify-center ring-1 ring-green-600/20">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-white"></div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span class="text-sm font-medium text-green-700">原始舱单</span>
|
||||||
|
<span class="text-green-600 text-xs font-normal bg-green-50 px-2 py-0.5 rounded-full">放行状态:01</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-gray-400 text-xs font-normal flex items-center gap-1.5">
|
||||||
|
<span>2026-07-10 11:03:38</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 状态 2 -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<div class="absolute -left-[22px] top-1.5 w-[10px] h-[10px] rounded-full bg-gray-200 border-2 border-white"></div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm font-bold text-gray-400">航班落地</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 状态 2 -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<div class="absolute -left-[22px] top-1.5 w-[10px] h-[10px] rounded-full bg-gray-200 border-2 border-white"></div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm font-bold text-gray-400">分拣理货</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 状态 3 -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<div class="absolute -left-[22px] top-1.5 w-[10px] h-[10px] rounded-full bg-gray-200 border-2 border-white"></div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm font-bold text-gray-400">理货申报</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 状态 4 -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<div class="absolute -left-[22px] top-1.5 w-[10px] h-[10px] rounded-full bg-gray-200 border-2 border-white"></div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm font-bold text-gray-400">海关放行</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 状态 5 -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<div class="absolute -left-[22px] top-1.5 w-[10px] h-[10px] rounded-full bg-gray-200 border-2 border-white"></div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm font-bold text-gray-400">柜台办结</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 状态 6 -->
|
||||||
|
<div class="relative mb-2">
|
||||||
|
<div class="absolute -left-[22px] top-1.5 w-[10px] h-[10px] rounded-full bg-gray-200 border-2 border-white"></div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm font-bold text-gray-400">提取出库</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 模块 4: 操作详情卡片 -> 已删除 -->
|
||||||
|
<!-- 底部占位 -->
|
||||||
|
<div class="text-center py-6">
|
||||||
|
<p class="text-[10px] text-gray-300 uppercase tracking-[0.2em] font-bold">查询信息已触底</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 底部 Home Indicator 模拟 -->
|
||||||
|
<div class="h-8 w-full flex justify-center items-center flex-none bg-white/60 backdrop-blur-md">
|
||||||
|
<div class="w-32 h-1.5 bg-black rounded-full opacity-20"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>ml>
|
||||||
951
documents/5.5寸手持端设计文件/10_进港查询/进港查询.html
Normal file
951
documents/5.5寸手持端设计文件/10_进港查询/进港查询.html
Normal file
@@ -0,0 +1,951 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||||
|
<title>进港查询</title>
|
||||||
|
<!-- Tailwind CSS (本地) -->
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/tailwindcss.js"></script>
|
||||||
|
<!-- Iconify 图标 -->
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/iconify-icon.min.js"></script>
|
||||||
|
<style>
|
||||||
|
@font-face {
|
||||||
|
font-family: 'PingFang SC';
|
||||||
|
src: local('PingFang SC');
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: 'PingFang SC', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||||
|
background-color: #e5e7eb;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
padding: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
/* 隐藏滚动条但保留功能 */
|
||||||
|
.hide-scrollbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.hide-scrollbar {
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-tag {
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.tag-occupied { background-color: #dcfce7; color: #22c55e; } /* 已出库 - 绿色 */
|
||||||
|
.tag-available { background-color: #dcfce7; color: #22c55e; } /* 已出库 - 绿色 */
|
||||||
|
.tag-repair { background-color: #fce7e7; color: #ef4444; } /* 离港 - 红色 */
|
||||||
|
|
||||||
|
/* 页面切换动画 */
|
||||||
|
.page {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
transition: transform 0.3s ease-in-out;
|
||||||
|
background-color: #f3f4f6;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-y: auto;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
.page::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.page-hidden-right { transform: translateX(100%); }
|
||||||
|
.page-hidden-left { transform: translateX(-100%); }
|
||||||
|
|
||||||
|
|
||||||
|
/* 统一的深蓝色调 */
|
||||||
|
.bg-header-blue { background-color: #2563EB; }
|
||||||
|
|
||||||
|
|
||||||
|
/* 标签页样式 */
|
||||||
|
.tab-item {
|
||||||
|
position: relative;
|
||||||
|
padding: 12px 0;
|
||||||
|
color: #999;
|
||||||
|
font-size: 14px;
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.tab-item.active {
|
||||||
|
color: #2563eb;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.tab-item::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 0;
|
||||||
|
height: 2px;
|
||||||
|
background-color: #2563eb;
|
||||||
|
transition: width 0.3s ease;
|
||||||
|
}
|
||||||
|
.tab-item.active::after {
|
||||||
|
width: 40%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 筛选弹窗样式 提升层级+动画稳定 ========== */
|
||||||
|
.filter-overlay {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background-color: rgba(0,0,0,0.4);
|
||||||
|
z-index: 9999;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
transition: opacity 0.25s ease, visibility 0.25s ease;
|
||||||
|
}
|
||||||
|
.filter-overlay.show {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-sheet {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: #fff;
|
||||||
|
border-top-left-radius: 20px;
|
||||||
|
border-top-right-radius: 20px;
|
||||||
|
padding: 20px;
|
||||||
|
z-index: 10000;
|
||||||
|
transform: translateY(100%);
|
||||||
|
transition: transform 0.25s ease-out;
|
||||||
|
max-height: 80vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.filter-sheet.show {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
/* 筛选输入框统一样式 */
|
||||||
|
.filter-input {
|
||||||
|
width: 100%;
|
||||||
|
height: 40px;
|
||||||
|
padding: 0 12px;
|
||||||
|
background: #f3f4f6;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
outline: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.filter-input:focus {
|
||||||
|
border-color: #2563EB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 下拉框箭头浅灰色 + 全浏览器兼容修复 */
|
||||||
|
select.filter-input {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%239ca3af' viewBox='0 0 16 16'%3E%3Cpath d='M8 11L3 6h10l-5 5z'/%3E%3C/svg%3E");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: right 12px center;
|
||||||
|
background-size: 16px;
|
||||||
|
padding-right: 36px;
|
||||||
|
}
|
||||||
|
/* 清除IE默认下拉箭头 */
|
||||||
|
select.filter-input::-ms-expand {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="w-[375px] h-[812px] bg-[#F3F4F6] overflow-hidden flex flex-col relative shadow-2xl rounded-[40px] border-[8px] border-gray-800">
|
||||||
|
<!-- 状态栏 -->
|
||||||
|
<div class="bg-header-blue flex-none z-50">
|
||||||
|
<div class="flex justify-between items-center px-6 pt-3 pb-1 text-[12px] font-medium text-white">
|
||||||
|
<span>09:41</span>
|
||||||
|
<div class="flex gap-1.5 items-center">
|
||||||
|
<iconify-icon icon="material-symbols:signal-cellular-4-bar-rounded"></iconify-icon>
|
||||||
|
<iconify-icon icon="material-symbols:wifi"></iconify-icon>
|
||||||
|
<iconify-icon icon="material-symbols:battery-full-rounded"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 筛选弹窗容器 移到最外层,层级提升 -->
|
||||||
|
<div class="filter-overlay" id="filterOverlay"></div>
|
||||||
|
<div class="filter-sheet" id="filterSheet">
|
||||||
|
<!-- 顶部标题栏 -->
|
||||||
|
<div class="relative flex items-center justify-center mb-6">
|
||||||
|
<button class="absolute right-0 top-0 text-gray-400" onclick="closeFilter()">
|
||||||
|
<iconify-icon class="text-2xl" icon="mdi:close"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
<h2 class="text-[18px] font-bold text-gray-900">筛选条件</h2>
|
||||||
|
</div>
|
||||||
|
<!-- 筛选表单区域 -->
|
||||||
|
<div class="space-y-4 mb-7">
|
||||||
|
<!-- 1.航班日期 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">航班日期起</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择航班日期" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:calendar" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 1.航班日期 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">航班日期止</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择航班日期" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:calendar" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 2.航班号 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">航班号</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请输入航班号" type="text" id="filterFlightNo">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 3.代理 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">代理</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择代理" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:chevron-down" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 4.特码 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">特码</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择特码" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:chevron-down" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 5.始发站 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">始发站</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请输入始发站" type="text" id="filterOrigin">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 6.运单类型 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">运单类型</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择运单类型" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:chevron-down" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 7.业务类型 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">业务类型</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择业务类型" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:chevron-down" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 8.品名(中) -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">品名(中)</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请输入中文品名" type="text" id="filterCnName">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 底部操作按钮 -->
|
||||||
|
<div class="flex gap-3">
|
||||||
|
<button class="flex-1 h-11 bg-gray-100 text-gray-600 rounded-lg text-sm font-medium" onclick="resetFilter()">重置</button>
|
||||||
|
<button class="flex-1 h-11 bg-[#2563EB] text-white rounded-lg text-sm font-medium" onclick="confirmFilter()">确定</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 页面主容器 -->
|
||||||
|
<div class="flex-1 relative overflow-hidden">
|
||||||
|
<!-- 列表页 -->
|
||||||
|
<div class="page z-10" id="listPage">
|
||||||
|
<!-- 头部 -->
|
||||||
|
<header class="bg-header-blue pt-2 pb-4 px-4 flex items-center relative flex-none">
|
||||||
|
<button class="flex items-center text-white text-sm absolute left-4">
|
||||||
|
<iconify-icon class="text-xl" icon="mdi:chevron-left"></iconify-icon>
|
||||||
|
<span>返回</span>
|
||||||
|
</button>
|
||||||
|
<h1 class="mx-auto text-white font-bold text-lg">进港查询</h1>
|
||||||
|
</header>
|
||||||
|
<!-- 搜索栏 筛选按钮已移除边框 -->
|
||||||
|
<div class="p-3 bg-transparent flex items-center gap-3 border-b border-gray-100 flex-none">
|
||||||
|
<div class="flex-1 bg-white rounded-xl flex items-center px-3 py-[10px] gap-2 border border-gray-50">
|
||||||
|
<iconify-icon class="text-[#9ca3af] text-lg" icon="mdi:magnify"></iconify-icon>
|
||||||
|
<input class="bg-transparent text-[14px] w-full outline-none text-gray-700 placeholder-[#9ca3af]" placeholder="搜索运单号" type="text"/>
|
||||||
|
<iconify-icon class="text-[#2563eb] text-lg" icon="mdi:qrcode-scan" onclick="alert('开启扫码功能')"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
<!-- 筛选按钮 无圆形实线边框 -->
|
||||||
|
<button id="filterBtn" class="w-10 h-10 flex items-center justify-center bg-white rounded-full relative z-[99999]">
|
||||||
|
<iconify-icon class="text-[#2563eb] text-xl" icon="mdi:filter-variant"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- 统计标签 -->
|
||||||
|
<div class="flex items-center gap-2 px-4 pb-3">
|
||||||
|
<div class="flex-1 bg-white rounded-lg px-3 py-2.5 shadow-sm border-l-[4px] border-l-[#2563EB]">
|
||||||
|
<div class="text-[11px] text-gray-500">总票数</div>
|
||||||
|
<div class="text-[22px] font-bold text-[#2563EB] leading-tight mt-0.5">4</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 bg-white rounded-lg px-3 py-2.5 shadow-sm border-l-[4px] border-l-orange-500">
|
||||||
|
<div class="text-[11px] text-gray-500">已入库</div>
|
||||||
|
<div class="text-[22px] font-bold text-orange-500 leading-tight mt-0.5">2</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 bg-white rounded-lg px-3 py-2.5 shadow-sm border-l-[4px] border-l-[#10B981]">
|
||||||
|
<div class="text-[11px] text-gray-500">已出库</div>
|
||||||
|
<div class="text-[22px] font-bold text-[#10B981] leading-tight mt-0.5">2</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- ULD 列表内容 -->
|
||||||
|
<div class="p-3 space-y-3 pb-24 overflow-y-auto hide-scrollbar">
|
||||||
|
<!-- 卡片 1 -->
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-sm active:bg-gray-50 transition-colors border border-gray-50 cursor-pointer" onclick="showDetail('78133363396')">
|
||||||
|
<div class="flex justify-between items-center mb-3">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-blue-500"></div>
|
||||||
|
<span class="font-bold text-[#1a1a1a]">78133363396</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="bg-green-100 text-green-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">已出库</span>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:chevron-right"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-y-2 text-[13px] text-gray-500">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:package-variant-closed"></iconify-icon>
|
||||||
|
<span>件数:444</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:weight-kilogram"></iconify-icon>
|
||||||
|
<span>重量:555</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:account-tie"></iconify-icon>
|
||||||
|
<span>代理人:中外运</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:tag-outline"></iconify-icon>
|
||||||
|
<span>特码:DGR</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片 2 -->
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-sm active:bg-gray-50 transition-colors border border-gray-50 cursor-pointer" onclick="showDetail('78133363397')">
|
||||||
|
<div class="flex justify-between items-center mb-3">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-blue-500"></div>
|
||||||
|
<span class="font-bold text-[#1a1a1a]">78133363397</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="bg-green-100 text-green-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">已出库</span>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:chevron-right"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-y-2 text-[13px] text-gray-500">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:package-variant-closed"></iconify-icon>
|
||||||
|
<span>件数:120</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:weight-kilogram"></iconify-icon>
|
||||||
|
<span>重量:320</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:account-tie"></iconify-icon>
|
||||||
|
<span>代理人:徽远</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:tag-outline"></iconify-icon>
|
||||||
|
<span>特码:PER</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片 3 -->
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-sm active:bg-gray-50 transition-colors border border-gray-50 cursor-pointer" onclick="showDetail('78133363398')">
|
||||||
|
<div class="flex justify-between items-center mb-3">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-blue-500"></div>
|
||||||
|
<span class="font-bold text-[#1a1a1a]">78133363398</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="bg-orange-100 text-orange-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">已入库</span>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:chevron-right"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-y-2 text-[13px] text-gray-500">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:package-variant-closed"></iconify-icon>
|
||||||
|
<span>件数:268</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:weight-kilogram"></iconify-icon>
|
||||||
|
<span>重量:780</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:account-tie"></iconify-icon>
|
||||||
|
<span>代理人:中外运</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:tag-outline"></iconify-icon>
|
||||||
|
<span>特码:NOR</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片 4 -->
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-sm active:bg-gray-50 transition-colors border border-gray-50 cursor-pointer" onclick="showDetail('78133363399')">
|
||||||
|
<div class="flex justify-between items-center mb-3">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-blue-500"></div>
|
||||||
|
<span class="font-bold text-[#1a1a1a]">78133363399</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="bg-green-100 text-green-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">已出库</span>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:chevron-right"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-y-2 text-[13px] text-gray-500">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:package-variant-closed"></iconify-icon>
|
||||||
|
<span>件数:85</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:weight-kilogram"></iconify-icon>
|
||||||
|
<span>重量:210</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:account-tie"></iconify-icon>
|
||||||
|
<span>代理人:徽远</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:tag-outline"></iconify-icon>
|
||||||
|
<span>特码:DGR</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片 5 -->
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-sm active:bg-gray-50 transition-colors border border-gray-50 cursor-pointer" onclick="showDetail('78133363400')">
|
||||||
|
<div class="flex justify-between items-center mb-3">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-blue-500"></div>
|
||||||
|
<span class="font-bold text-[#1a1a1a]">78133363400</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="bg-green-100 text-green-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">已出库</span>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:chevron-right"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-y-2 text-[13px] text-gray-500">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:package-variant-closed"></iconify-icon>
|
||||||
|
<span>件数:350</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:weight-kilogram"></iconify-icon>
|
||||||
|
<span>重量:430</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:account-tie"></iconify-icon>
|
||||||
|
<span>代理人:中外运</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:tag-outline"></iconify-icon>
|
||||||
|
<span>特码:PER</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 详情页 -->
|
||||||
|
<div class="page z-20 page-hidden-right !bg-[#f0f2f5]" id="detailPage">
|
||||||
|
<!-- 头部 -->
|
||||||
|
<header class="bg-header-blue pt-2 pb-4 px-4 flex items-center relative flex-none">
|
||||||
|
<button class="flex items-center text-white text-sm absolute left-4 active:opacity-70" onclick="goBack()">
|
||||||
|
<iconify-icon class="text-xl" icon="mdi:chevron-left"></iconify-icon>
|
||||||
|
<span>返回</span>
|
||||||
|
</button>
|
||||||
|
<h1 class="mx-auto text-white font-bold text-lg">进港货物</h1>
|
||||||
|
<div class="absolute right-4 flex items-center">
|
||||||
|
<iconify-icon class="text-red-500 text-2xl" icon="mdi:file-document-edit-outline"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<!-- 标签页 -->
|
||||||
|
<div class="bg-white px-4 border-b border-gray-200 flex-none">
|
||||||
|
<div class="flex justify-around">
|
||||||
|
<div class="tab-item active cursor-pointer" onclick="switchTab(0)">运单信息</div>
|
||||||
|
<div class="tab-item cursor-pointer" onclick="switchTab(1)">仓库信息</div>
|
||||||
|
<div class="tab-item cursor-pointer" onclick="switchTab(2)">库位信息</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 详情内容区 -->
|
||||||
|
<div class="flex-1 overflow-y-auto hide-scrollbar">
|
||||||
|
<!-- 运单信息标签页 -->
|
||||||
|
<div class="tab-pane p-3 space-y-3" id="tab-content-0">
|
||||||
|
<!-- 卡片1:基本信息 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
||||||
|
<div class="px-4 py-2.5 flex items-center border-b border-gray-100">
|
||||||
|
<div class="w-1 h-4 bg-blue-500 rounded-full inline-block mr-2"></div>
|
||||||
|
<span class="text-xs font-semibold text-gray-800" id="det-uldTitle">基本信息</span>
|
||||||
|
</div>
|
||||||
|
<div class="p-3 grid grid-cols-2 gap-2">
|
||||||
|
<!-- Row 1 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">运单号</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-billNo"></span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">代理人</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-agent"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 2 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">特码</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-code"></span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">承运人</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-carrier"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 3 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">始发港</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-route"></span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">中转站</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-outboundTime"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 4 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">目的站</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-dest"></span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">UN编号</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-unNo"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 5 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center" id="det-lockStatus-container">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5" id="det-lockStatus-label">锁定状态</span>
|
||||||
|
<div id="det-lockStatus-wrapper">
|
||||||
|
<span class="text-xs font-semibold" id="det-lockStatus"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">包装类型</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-packType"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 6 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">业务类型</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-type"></span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">出库时间</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-outboundTime"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 7 运单类型单独一行 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center col-span-2">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">运单类型</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-billType"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 8 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center col-span-2">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">品名(中)</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-itemNameCn"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 9 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center col-span-2">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">品名(英)</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-itemNameEn"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Row 10 -->
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center col-span-2">
|
||||||
|
<span class="text-[10px] text-gray-500 text-[14px] mb-0.5">备注</span>
|
||||||
|
<span class="text-xs text-gray-800 font-semibold truncate" id="det-remark"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片2:件重信息 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
||||||
|
<div class="px-4 py-2.5 flex items-center border-b border-gray-100">
|
||||||
|
<div class="w-1 h-4 bg-blue-500 rounded-full inline-block mr-2"></div>
|
||||||
|
<span class="text-xs font-semibold text-gray-800">件重信息</span>
|
||||||
|
</div>
|
||||||
|
<div class="p-3 grid grid-cols-3 gap-2">
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">运单件数</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-pieces"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">运单重量</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-weight"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">计费重量</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-calcWeight"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">已出库件数</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-inPieces"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">已出库重量</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-inWeight"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center opacity-0">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">—</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold">—</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片3:回执信息 -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
||||||
|
<div class="px-4 py-2.5 flex items-center border-b border-gray-100">
|
||||||
|
<div class="w-1 h-4 bg-blue-500 rounded-full inline-block mr-2"></div>
|
||||||
|
<span class="text-xs font-semibold text-gray-800">回执信息</span>
|
||||||
|
</div>
|
||||||
|
<div class="p-3 grid grid-cols-3 gap-2">
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">原始舱单</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-originalManifest"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">理货报告</div>
|
||||||
|
<div class="text-xs text-gray-800 font-semibold" id="det-tallyReport"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/30 rounded-lg p-2.5 flex flex-col justify-center" id="det-customsRelease-container">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">海关放行</div>
|
||||||
|
<div id="det-customsRelease-wrapper">
|
||||||
|
<div class="text-xs font-semibold" id="det-customsRelease"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 仓库信息标签页 -->
|
||||||
|
<div class="tab-pane p-3 space-y-3 hidden" id="tab-content-1"></div>
|
||||||
|
<!-- 库位信息标签页 -->
|
||||||
|
<div class="tab-pane p-3 space-y-3 hidden" id="tab-content-2"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const uldData = {
|
||||||
|
'78133363396': {
|
||||||
|
billNo: '78133363396', agent: '中外运', code: 'DGR',
|
||||||
|
pieces: '444', weight: '555.0', type: '普通货物运输',
|
||||||
|
inPieces: '444', inWeight: '555.0', calcWeight: '555.0',
|
||||||
|
carrier: 'CA', route: 'LAX', packType: '纸箱',
|
||||||
|
billType: '国际进港(国际直航)', unNo: '—', dest: 'HFE',
|
||||||
|
itemNameCn: '电子元器件', itemNameEn: 'Electronic Components',
|
||||||
|
lockStatus: '未锁定', outboundTime: '—', remark: '需冷藏存储',
|
||||||
|
originalManifest: '01', tallyReport: '01', customsRelease: '11',
|
||||||
|
warehouse: [
|
||||||
|
{ batch: '1', pieces: 200, weight: 300.0, flightDate: '2026-07-08', flightNo: 'CA1234',route: 'LAX',dest: 'HFE', time: '2026-07-08 14:30:00' },
|
||||||
|
{ batch: '2', pieces: 244, weight: 255.0, flightDate: '2026-07-09', flightNo: 'CA5678',route: 'LAX',dest: 'HFE', time: '2026-07-09 09:10:46' }
|
||||||
|
],
|
||||||
|
locations: [
|
||||||
|
{ id: 'A-01-001', inPerson: '张三', inTime: '2026-07-08 14:30', outPerson: '李四', outTime: '2026-07-09 10:00' },
|
||||||
|
{ id: 'B-02-005', inPerson: '王五', inTime: '2026-07-09 09:10', outPerson: '—', outTime: '—' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'78133363397': {
|
||||||
|
billNo: '78133363397', agent: '徽远', code: 'PER',
|
||||||
|
pieces: '120', weight: '320.0', type: '普通货物运输',
|
||||||
|
inPieces: '120', inWeight: '320.0', calcWeight: '320.0',
|
||||||
|
carrier: 'MU', route: 'PVG-NRT', packType: '托盘',
|
||||||
|
billType: '国际进港(国际直航)', unNo: '—', dest: 'PVG',
|
||||||
|
itemNameCn: '服装', itemNameEn: 'Garments',
|
||||||
|
lockStatus: '未锁定', outboundTime: '—', remark: '易碎品,轻拿轻放',
|
||||||
|
originalManifest: '01', tallyReport: '01', customsRelease: '11',
|
||||||
|
warehouse: [
|
||||||
|
{ batch: '3', pieces: 60, weight: 150.0, flightDate: '2026-07-07', flightNo: 'MU123',route: 'LAX',dest: 'HFE', time: '2026-07-07 16:20:00' },
|
||||||
|
{ batch: '4', pieces: 60, weight: 170.0, flightDate: '2026-07-08', flightNo: 'MU456',route: 'LAX',dest: 'HFE', time: '2026-07-08 11:00:00' }
|
||||||
|
],
|
||||||
|
locations: [
|
||||||
|
{ id: 'A-03-012', inPerson: '赵六', inTime: '2026-07-07 16:20', outPerson: '钱七', outTime: '2026-07-08 14:00' },
|
||||||
|
{ id: 'C-01-008', inPerson: '孙八', inTime: '2026-07-08 11:00', outPerson: '—', outTime: '—' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'78133363398': {
|
||||||
|
billNo: '78133363398', agent: '中外运', code: 'NOR',
|
||||||
|
pieces: '268', weight: '780.0', type: '普通货物运输',
|
||||||
|
inPieces: '268', inWeight: '780.0', calcWeight: '780.0',
|
||||||
|
carrier: 'CZ', route: 'CAN-AMS', packType: '托盘',
|
||||||
|
billType: '国际进港(国际直航)', unNo: '—', dest: 'CAN',
|
||||||
|
itemNameCn: '机械设备', itemNameEn: 'Machinery Equipment',
|
||||||
|
lockStatus: '锁定', outboundTime: '2026-07-09 08:00', remark: '需叉车装卸',
|
||||||
|
originalManifest: '01', tallyReport: '01', customsRelease: '11',
|
||||||
|
warehouse: [
|
||||||
|
{ batch: '5', pieces: 150, weight: 420.0, flightDate: '2026-07-08', flightNo: 'CZ789',route: 'LAX',dest: 'HFE', time: '2026-07-08 22:15:00' },
|
||||||
|
{ batch: '6', pieces: 118, weight: 360.0, flightDate: '2026-07-09', flightNo: 'CZ012',route: 'LAX',dest: 'HFE', time: '2026-07-09 06:30:00' },
|
||||||
|
{ batch: '7', pieces: 100, weight: 200.0, flightDate: '2026-07-09', flightNo: 'CZ345',route: 'LAX',dest: 'HFE', time: '2026-07-09 13:00:00' }
|
||||||
|
],
|
||||||
|
locations: [
|
||||||
|
{ id: 'B-01-003', inPerson: '张三', inTime: '2026-07-08 22:15', outPerson: '李四', outTime: '2026-07-09 06:00' },
|
||||||
|
{ id: 'A-02-010', inPerson: '王五', inTime: '2026-07-09 06:30', outPerson: '—', outTime: '—' },
|
||||||
|
{ id: 'C-03-007', inPerson: '赵六', inTime: '2026-07-09 13:00', outPerson: '—', outTime: '—' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'78133363399': {
|
||||||
|
billNo: '78133363399', agent: '徽远', code: 'DGR',
|
||||||
|
pieces: '85', weight: '210.0', type: '危险品运输',
|
||||||
|
inPieces: '85', inWeight: '210.0', calcWeight: '210.0',
|
||||||
|
carrier: '3U', route: 'CTU-SIN', packType: '铁箱',
|
||||||
|
billType: '国际进港(国际直航)', unNo: 'UN3480', dest: 'CTU',
|
||||||
|
itemNameCn: '锂电池', itemNameEn: 'Lithium Battery',
|
||||||
|
lockStatus: '锁定', outboundTime: '—', remark: '危险品,单独存放',
|
||||||
|
originalManifest: '01', tallyReport: '01', customsRelease: '11',
|
||||||
|
warehouse: [
|
||||||
|
{ batch: '8', pieces: 45, weight: 110.0, flightDate: '2026-07-08', flightNo: '3U678',route: 'LAX',dest: 'HFE', time: '2026-07-08 18:00:00' },
|
||||||
|
{ batch: '9', pieces: 40, weight: 100.0, flightDate: '2026-07-09', flightNo: '3U901',route: 'LAX',dest: 'HFE', time: '2026-07-09 07:45:00' }
|
||||||
|
],
|
||||||
|
locations: [
|
||||||
|
{ id: 'D-01-002', inPerson: '钱七', inTime: '2026-07-08 18:00', outPerson: '孙八', outTime: '2026-07-09 08:00' },
|
||||||
|
{ id: 'A-04-015', inPerson: '张三', inTime: '2026-07-09 07:45', outPerson: '—', outTime: '—' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'78133363400': {
|
||||||
|
billNo: '78133363400', agent: '中外运', code: 'PER',
|
||||||
|
pieces: '350', weight: '430.0', type: '普通货物运输',
|
||||||
|
inPieces: '350', inWeight: '430.0', calcWeight: '430.0',
|
||||||
|
carrier: 'HU', route: 'HKG-HFE', packType: '纸箱',
|
||||||
|
billType: '国际进港(国际直航)', unNo: '—', dest: 'HFE',
|
||||||
|
itemNameCn: '食品', itemNameEn: 'Food Products',
|
||||||
|
lockStatus: '未锁定', outboundTime: '2026-07-09 11:30', remark: '保质期至2026-12',
|
||||||
|
originalManifest: '01', tallyReport: '01', customsRelease: '11',
|
||||||
|
warehouse: [
|
||||||
|
{ batch: '10', pieces: 180, weight: 220.0, flightDate: '2026-07-07', flightNo: 'HU234',route: 'LAX',dest: 'HFE', time: '2026-07-07 20:00:00' },
|
||||||
|
{ batch: '11', pieces: 170, weight: 210.0, flightDate: '2026-07-09', flightNo: 'HU567',route: 'LAX',dest: 'HFE', time: '2026-07-09 10:30:00' }
|
||||||
|
],
|
||||||
|
locations: [
|
||||||
|
{ id: 'B-02-011', inPerson: '李四', inTime: '2026-07-07 20:00', outPerson: '王五', outTime: '2026-07-08 16:00' },
|
||||||
|
{ id: 'C-01-009', inPerson: '赵六', inTime: '2026-07-09 10:30', outPerson: '—', outTime: '—' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 核心修复:等待DOM全部渲染完成后再绑定点击事件,避免获取元素为null
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const filterOverlay = document.getElementById('filterOverlay');
|
||||||
|
const filterSheet = document.getElementById('filterSheet');
|
||||||
|
const filterBtn = document.getElementById('filterBtn');
|
||||||
|
|
||||||
|
// 点击遮罩空白关闭,添加self防止弹窗内部点击穿透关闭
|
||||||
|
filterOverlay.addEventListener('click', function(e) {
|
||||||
|
if (e.target === filterOverlay) {
|
||||||
|
closeFilter();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 筛选按钮点击打开弹窗
|
||||||
|
filterBtn.addEventListener('click', openFilter);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 打开筛选弹窗
|
||||||
|
function openFilter() {
|
||||||
|
const filterOverlay = document.getElementById('filterOverlay');
|
||||||
|
const filterSheet = document.getElementById('filterSheet');
|
||||||
|
filterOverlay.classList.add('show');
|
||||||
|
setTimeout(() => filterSheet.classList.add('show'), 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭筛选弹窗
|
||||||
|
function closeFilter() {
|
||||||
|
const filterOverlay = document.getElementById('filterOverlay');
|
||||||
|
const filterSheet = document.getElementById('filterSheet');
|
||||||
|
filterSheet.classList.remove('show');
|
||||||
|
setTimeout(() => filterOverlay.classList.remove('show'), 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置所有筛选输入框
|
||||||
|
function resetFilter() {
|
||||||
|
document.querySelectorAll('.filter-input').forEach(input => {
|
||||||
|
input.value = '';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确定筛选(模拟查询,可对接后端筛选逻辑)
|
||||||
|
function confirmFilter() {
|
||||||
|
const params = {
|
||||||
|
flightDate: document.getElementById('filterFlightDate').value,
|
||||||
|
flightNo: document.getElementById('filterFlightNo').value,
|
||||||
|
agent: document.getElementById('filterAgent').value,
|
||||||
|
code: document.getElementById('filterCode').value,
|
||||||
|
origin: document.getElementById('filterOrigin').value,
|
||||||
|
billType: document.getElementById('filterBillType').value,
|
||||||
|
bizType: document.getElementById('filterBizType').value,
|
||||||
|
cnName: document.getElementById('filterCnName').value
|
||||||
|
};
|
||||||
|
console.log('筛选参数:', params);
|
||||||
|
alert('筛选执行成功,控制台可查看筛选条件');
|
||||||
|
closeFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showDetail(id) {
|
||||||
|
const listPage = document.getElementById('listPage');
|
||||||
|
const detailPage = document.getElementById('detailPage');
|
||||||
|
|
||||||
|
const data = uldData[id];
|
||||||
|
if (data) {
|
||||||
|
document.getElementById('det-uldTitle').innerText = '基本信息';
|
||||||
|
document.getElementById('det-billNo').innerText = data.billNo;
|
||||||
|
document.getElementById('det-agent').innerText = data.agent;
|
||||||
|
document.getElementById('det-code').innerText = data.code;
|
||||||
|
document.getElementById('det-carrier').innerText = data.carrier;
|
||||||
|
document.getElementById('det-route').innerText = data.route;
|
||||||
|
document.getElementById('det-dest').innerText = data.dest;
|
||||||
|
document.getElementById('det-billType').innerText = data.billType;
|
||||||
|
document.getElementById('det-unNo').innerText = data.unNo;
|
||||||
|
|
||||||
|
// 锁定状态渲染
|
||||||
|
const lockStatusEl = document.getElementById('det-lockStatus');
|
||||||
|
if (data.lockStatus === '锁定') {
|
||||||
|
lockStatusEl.innerHTML = '<iconify-icon icon="mdi:lock" class="mr-1"></iconify-icon>锁定';
|
||||||
|
lockStatusEl.className = 'text-xs font-semibold px-2 py-0.5 rounded-md bg-red-50 text-red-600 inline-flex items-center';
|
||||||
|
} else {
|
||||||
|
lockStatusEl.innerHTML = '—';
|
||||||
|
lockStatusEl.className = 'text-xs font-semibold text-gray-800';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('det-packType').innerText = data.packType;
|
||||||
|
document.getElementById('det-type').innerText = data.type;
|
||||||
|
document.getElementById('det-outboundTime').innerText = data.outboundTime || '—';
|
||||||
|
document.getElementById('det-itemNameCn').innerText = data.itemNameCn || '—';
|
||||||
|
document.getElementById('det-itemNameEn').innerText = data.itemNameEn || '—';
|
||||||
|
document.getElementById('det-remark').innerText = data.remark || '—';
|
||||||
|
|
||||||
|
// 件重信息
|
||||||
|
document.getElementById('det-pieces').innerText = data.pieces;
|
||||||
|
document.getElementById('det-weight').innerText = data.weight;
|
||||||
|
document.getElementById('det-calcWeight').innerText = data.calcWeight;
|
||||||
|
document.getElementById('det-inPieces').innerText = data.inPieces;
|
||||||
|
document.getElementById('det-inWeight').innerText = data.inWeight;
|
||||||
|
|
||||||
|
// 海关放行标签
|
||||||
|
const customsReleaseEl = document.getElementById('det-customsRelease');
|
||||||
|
if (data.customsRelease === '11') {
|
||||||
|
customsReleaseEl.innerText = '已放行';
|
||||||
|
customsReleaseEl.className = 'text-xs font-semibold px-2 py-0.5 rounded-md bg-green-50 text-green-600 inline-block';
|
||||||
|
} else {
|
||||||
|
customsReleaseEl.innerText = data.customsRelease || '未放行';
|
||||||
|
customsReleaseEl.className = 'text-xs font-semibold px-2 py-0.5 rounded-md bg-gray-100 text-gray-600 inline-block';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 渲染仓库批次列表
|
||||||
|
const warehouseContainer = document.getElementById('tab-content-1');
|
||||||
|
warehouseContainer.innerHTML = '';
|
||||||
|
data.warehouse.forEach(item => {
|
||||||
|
warehouseContainer.innerHTML += `
|
||||||
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
||||||
|
<div class="flex justify-between items-center pt-3 pb-1.5 px-3 mb-2 border-b border-gray-100">
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<span class="w-1.5 h-1.5 rounded-full bg-blue-500 inline-block"></span>
|
||||||
|
<span class="text-xs font-semibold text-gray-900">批次号: ${item.batch}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-1.5 px-3 pb-2">
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">件数</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${item.pieces}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">重量</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${parseFloat(item.weight).toFixed(1)} kg</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">航班日期</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${item.flightDate}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">航班号</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${item.flightNo}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">始发站</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${item.route}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">目的站</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${item.dest}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 渲染库位信息
|
||||||
|
const locationContainer = document.getElementById('tab-content-2');
|
||||||
|
locationContainer.innerHTML = '';
|
||||||
|
data.locations.forEach(loc => {
|
||||||
|
locationContainer.innerHTML += `
|
||||||
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
||||||
|
<div class="flex justify-between items-center pt-3 pb-1.5 px-3 mb-2 border-b border-gray-100">
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<span class="w-1.5 h-1.5 rounded-full bg-blue-500 inline-block"></span>
|
||||||
|
<span class="text-xs font-bold text-gray-900">${loc.id}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-1.5 px-3 pb-2">
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">入库人</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${loc.inPerson}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">入库时间</div>
|
||||||
|
<div class="text-xs font-semibold text-gray-800">${loc.inTime}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">出库人</div>
|
||||||
|
<div class="text-xs ${loc.outPerson === '—' ? 'text-gray-500 text-[14px]' : 'text-gray-800'} font-semibold">${loc.outPerson}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50/50 rounded-lg p-2">
|
||||||
|
<div class="text-[10px] text-gray-500 text-[14px] mb-0.5">出库时间</div>
|
||||||
|
<div class="text-xs ${loc.outTime === '—' ? 'text-gray-500 text-[14px]' : 'text-gray-800'} font-semibold">${loc.outTime}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
switchTab(0);
|
||||||
|
listPage.classList.add('page-hidden-left');
|
||||||
|
detailPage.classList.remove('page-hidden-right');
|
||||||
|
}
|
||||||
|
|
||||||
|
function goBack() {
|
||||||
|
const listPage = document.getElementById('listPage');
|
||||||
|
const detailPage = document.getElementById('detailPage');
|
||||||
|
listPage.classList.remove('page-hidden-left');
|
||||||
|
detailPage.classList.add('page-hidden-right');
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchTab(index) {
|
||||||
|
const tabs = document.querySelectorAll('.tab-item');
|
||||||
|
const contents = document.querySelectorAll('.tab-pane');
|
||||||
|
tabs.forEach((tab, i) => {
|
||||||
|
if (i === index) {
|
||||||
|
tab.classList.add('active');
|
||||||
|
contents[i].classList.remove('hidden');
|
||||||
|
} else {
|
||||||
|
tab.classList.remove('active');
|
||||||
|
contents[i].classList.add('hidden');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索框聚焦监听
|
||||||
|
document.querySelector('input[placeholder="搜索ULD编号"]').addEventListener('focus', () => {
|
||||||
|
console.log('搜索框已激活');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
134
documents/5.5寸手持端设计文件/11_进港移库/photo.html
Normal file
134
documents/5.5寸手持端设计文件/11_进港移库/photo.html
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||||
|
<title>拍照上传</title>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/tailwindcss.js"></script>
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/iconify-icon.min.js"></script>
|
||||||
|
<style>
|
||||||
|
@font-face {
|
||||||
|
font-family: 'PingFang SC';
|
||||||
|
src: local('PingFang SC');
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: 'PingFang SC', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||||
|
background-color: #e2e8f0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.phone-container {
|
||||||
|
width: 375px;
|
||||||
|
height: 812px;
|
||||||
|
background-color: #f5f6fa;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
||||||
|
border: 8px solid #1a1a1a;
|
||||||
|
border-radius: 40px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="phone-container">
|
||||||
|
<!-- 状态栏 -->
|
||||||
|
<div class="h-10 w-full flex justify-between items-center px-8 flex-none bg-[#2563EB] text-white">
|
||||||
|
<span class="text-xs font-semibold">09:41</span>
|
||||||
|
<div class="flex gap-1 items-center">
|
||||||
|
<iconify-icon icon="mdi:signal" width="14"></iconify-icon>
|
||||||
|
<iconify-icon icon="mdi:wifi" width="14"></iconify-icon>
|
||||||
|
<iconify-icon icon="mdi:battery" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 顶部导航栏 -->
|
||||||
|
<div class="bg-[#2563EB] text-white h-12 flex items-center justify-between px-4 flex-none">
|
||||||
|
<div class="flex items-center" onclick="closeWin()">
|
||||||
|
<iconify-icon icon="mdi:chevron-left" width="28"></iconify-icon>
|
||||||
|
<span class="text-sm font-bold -ml-1">返回</span>
|
||||||
|
</div>
|
||||||
|
<h1 class="text-lg font-medium">拍照上传</h1>
|
||||||
|
<div class="w-16"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 内容区域 -->
|
||||||
|
<div class="flex-1 overflow-y-auto p-4 bg-[#f5f6fa]">
|
||||||
|
<div class="bg-white rounded-xl p-5 shadow">
|
||||||
|
<div class="flex justify-between items-center mb-4">
|
||||||
|
<h2 class="text-lg font-bold">运单照片上传</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="previewWrap" class="grid grid-cols-3 gap-2 mb-4 min-h-[100px]"></div>
|
||||||
|
|
||||||
|
<input type="file" id="fileInput" accept="image/*" capture="camera" multiple class="hidden">
|
||||||
|
|
||||||
|
<div class="flex gap-3">
|
||||||
|
<button class="flex-1 bg-blue-600 text-white py-2 rounded" onclick="fileInput.click()">
|
||||||
|
拍照/上传
|
||||||
|
</button>
|
||||||
|
<button class="flex-1 bg-green-600 text-white py-2 rounded" onclick="submitPhotos()">
|
||||||
|
确认提交
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const awb = sessionStorage.getItem('currentAwb');
|
||||||
|
const fileInput = document.getElementById('fileInput');
|
||||||
|
const previewWrap = document.getElementById('previewWrap');
|
||||||
|
let fileList = [];
|
||||||
|
|
||||||
|
// 选择图片
|
||||||
|
fileInput.onchange = function () {
|
||||||
|
for (let file of this.files) {
|
||||||
|
const url = URL.createObjectURL(file);
|
||||||
|
fileList.push({ file, url });
|
||||||
|
renderPreview();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 渲染预览
|
||||||
|
function renderPreview() {
|
||||||
|
previewWrap.innerHTML = '';
|
||||||
|
fileList.forEach((item, idx) => {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.className = 'relative border rounded h-20 overflow-hidden';
|
||||||
|
div.innerHTML = `
|
||||||
|
<img src="${item.url}" class="w-full h-full object-cover">
|
||||||
|
<button onclick="delImg(${idx})"
|
||||||
|
class="absolute top-1 right-1 w-5 h-5 bg-red-500 text-white rounded-full text-xs flex items-center justify-center">
|
||||||
|
×
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
|
previewWrap.appendChild(div);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
function delImg(index) {
|
||||||
|
fileList.splice(index, 1);
|
||||||
|
renderPreview();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交
|
||||||
|
function submitPhotos() {
|
||||||
|
const urls = fileList.map(item => item.url);
|
||||||
|
sessionStorage.setItem('uploadedPhotos', JSON.stringify(urls));
|
||||||
|
closeWin();
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeWin() {
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
831
documents/5.5寸手持端设计文件/11_进港移库/进港移库.html
Normal file
831
documents/5.5寸手持端设计文件/11_进港移库/进港移库.html
Normal file
@@ -0,0 +1,831 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
|
||||||
|
<title>进港移库 - 移动端原型</title>
|
||||||
|
<!-- Tailwind CSS -->
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/tailwindcss.js"></script>
|
||||||
|
<!-- Iconify -->
|
||||||
|
<script src="https://modao.cc/agent-py/static/source/js/iconify-icon.min.js"></script>
|
||||||
|
<style>
|
||||||
|
@font-face {
|
||||||
|
font-family: 'PingFang SC';
|
||||||
|
src: local('PingFang SC');
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: 'PingFang SC', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||||
|
background-color: #e2e8f0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.phone-container {
|
||||||
|
width: 375px;
|
||||||
|
height: 812px;
|
||||||
|
background-color: #f5f6fa;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
||||||
|
border: 8px solid #1a1a1a;
|
||||||
|
border-radius: 40px;
|
||||||
|
}
|
||||||
|
.no-scrollbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.no-scrollbar {
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
.page {
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.page.active {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
#filter-panel {
|
||||||
|
transform: translateY(100%);
|
||||||
|
transition: transform 0.3s ease-out;
|
||||||
|
}
|
||||||
|
#filter-panel.show {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
.overlay {
|
||||||
|
background-color: rgba(0,0,0,0.5);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.overlay.show {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
.btn-active:active {
|
||||||
|
opacity: 0.7;
|
||||||
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
|
.custom-checkbox {
|
||||||
|
appearance: none;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border: 2px solid #cbd5e1;
|
||||||
|
border-radius: 4px;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.2s;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
.custom-checkbox:checked {
|
||||||
|
background-color: #2563EB;
|
||||||
|
border-color: #2563EB;
|
||||||
|
}
|
||||||
|
.custom-checkbox:checked::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 6px;
|
||||||
|
top: 2px;
|
||||||
|
width: 5px;
|
||||||
|
height: 10px;
|
||||||
|
border: solid white;
|
||||||
|
border-width: 0 2px 2px 0;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
.custom-checkbox-round {
|
||||||
|
appearance: none;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border: 2px solid #cbd5e1;
|
||||||
|
border-radius: 50%;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.2s;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
.custom-checkbox-round:checked {
|
||||||
|
background-color: #2563EB;
|
||||||
|
border-color: #2563EB;
|
||||||
|
}
|
||||||
|
.custom-checkbox-round:checked::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 6px;
|
||||||
|
top: 2px;
|
||||||
|
width: 5px;
|
||||||
|
height: 10px;
|
||||||
|
border: solid white;
|
||||||
|
border-width: 0 2px 2px 0;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
/* 长按拍照浮层核心样式 */
|
||||||
|
.card-action-overlay {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0,0,0,0.5);
|
||||||
|
border-radius: 20px;
|
||||||
|
z-index: 10;
|
||||||
|
display: none;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.card-action-overlay.show {
|
||||||
|
display: flex;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
/* 卡片必须相对定位,浮层才能盖住自身 */
|
||||||
|
.pending-card, #list-shipped > div {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="phone-container">
|
||||||
|
<!-- 状态栏 -->
|
||||||
|
<div class="h-10 w-full flex justify-between items-center px-8 flex-none bg-[#2563EB] text-white">
|
||||||
|
<span class="text-xs font-semibold">09:41</span>
|
||||||
|
<div class="flex gap-1 items-center">
|
||||||
|
<iconify-icon icon="mdi:signal" width="14"></iconify-icon>
|
||||||
|
<iconify-icon icon="mdi:wifi" width="14"></iconify-icon>
|
||||||
|
<iconify-icon icon="mdi:battery" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 列表首页 -->
|
||||||
|
<div class="page active" id="page-home">
|
||||||
|
<!-- 顶部导航栏 -->
|
||||||
|
<div class="bg-[#2563EB] text-white h-12 flex items-center justify-between px-4 flex-none">
|
||||||
|
<div class="flex items-center btn-active" onclick="alert('返回首页')">
|
||||||
|
<iconify-icon icon="mdi:chevron-left" width="28"></iconify-icon>
|
||||||
|
<span class="text-sm font-bold -ml-1">返回</span>
|
||||||
|
</div>
|
||||||
|
<h1 class="text-lg font-medium">进港移库</h1>
|
||||||
|
<div class="w-16"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 滚动内容区域 -->
|
||||||
|
<div class="flex-1 overflow-y-auto no-scrollbar pb-24">
|
||||||
|
<!-- 搜索栏 -->
|
||||||
|
<section class="px-4 pt-4 pb-3 bg-white">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 shadow-sm rounded-[12px] h-10 px-3 gap-2 flex-1">
|
||||||
|
<iconify-icon class="text-gray-400 text-lg flex-none" icon="mdi:magnify"></iconify-icon>
|
||||||
|
<input class="flex-1 bg-transparent text-[14px] text-gray-800 placeholder-gray-400 outline-none border-none rounded-lg px-2" placeholder="搜索运单号" type="text"/>
|
||||||
|
<button class="flex-none text-blue-500">
|
||||||
|
<iconify-icon class="text-lg" icon="mdi:qrcode-scan"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button class="bg-white p-2.5 rounded-full shadow-sm border border-gray-200 text-[#2563EB] flex items-center justify-center flex-none" onclick="toggleFilterDrawer(true)">
|
||||||
|
<iconify-icon class="text-xl" icon="mdi:filter-variant"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Tab切换 -->
|
||||||
|
<div class="flex bg-white border-b sticky top-0 z-20">
|
||||||
|
<button class="flex-1 py-3 text-sm font-bold text-[#1F2937] border-b-2 border-[#1F2937] transition-all" id="tab-pending" onclick="switchTab('pending')">
|
||||||
|
待移库 <span class="bg-[#DBEAF6] text-[#2563EB] text-[11px] font-medium px-1.5 py-0.5 rounded-md ml-1.5">3</span>
|
||||||
|
</button>
|
||||||
|
<button class="flex-1 py-3 text-sm font-bold text-gray-400 border-b-2 border-transparent transition-all" id="tab-shipped" onclick="switchTab('shipped')">
|
||||||
|
已移库 <span class="bg-[#DBEAF6] text-[#2563EB] text-[11px] font-medium px-1.5 py-0.5 rounded-md ml-1.5">3</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 待移库列表 -->
|
||||||
|
<div class="p-3 pt-4 space-y-3" id="list-pending">
|
||||||
|
<!-- 卡片1 -->
|
||||||
|
<div class="pending-card bg-white rounded-xl shadow-sm p-4 mb-3 overflow-hidden"
|
||||||
|
onmousedown="startLongPress(this, event)"
|
||||||
|
onmouseup="endLongPress()"
|
||||||
|
onmouseleave="endLongPress()"
|
||||||
|
ontouchstart="startLongPress(this, event)"
|
||||||
|
ontouchmove="cancelLongPress()"
|
||||||
|
ontouchend="endLongPress()">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input class="item-checkbox custom-checkbox-round flex-none" onclick="handleCheckboxClick(this, event)" type="checkbox"/>
|
||||||
|
<div class="text-[#2563EB] text-[15px] font-bold">78133363573</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="bg-orange-100 text-orange-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">待移库</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon icon="mdi:airplane" class="text-gray-500 text-[14px]"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">航班信息:20260709/MU2311</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">特码</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">NOR</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">件数</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">100件</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">重量</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">200kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:map-marker"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">出运路径:HFE-NKG-LAX</span>
|
||||||
|
</div>
|
||||||
|
<div class="mt-4 flex justify-end border-t border-gray-100 pt-3">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer btn-active" onclick="showDetail({id: '78133363573', status: '待移库', agent: 'NOR', pieces: '100', weight: '200', goodsName: '电子元器件', carrier: 'MU', route: 'HFE-NKG-LAX', location: 'A区-03货位', code: 'NOR', counterPerson: '--', counterTime: '--', outboundPerson: '', outboundTime: ''})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 拍照浮层 -->
|
||||||
|
<div class="card-action-overlay" onclick="closeSelf(this)">
|
||||||
|
<button class="bg-purple-500 text-white w-14 h-14 rounded-full shadow-lg shadow-purple-500/30 flex items-center justify-center text-[10px] font-bold leading-tight" onclick="event.stopPropagation();goToPhoto('78133363573')">拍照</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片2 -->
|
||||||
|
<div class="pending-card bg-white rounded-xl shadow-sm p-4 mb-3 overflow-hidden"
|
||||||
|
onmousedown="startLongPress(this, event)"
|
||||||
|
onmouseup="endLongPress()"
|
||||||
|
onmouseleave="endLongPress()"
|
||||||
|
ontouchstart="startLongPress(this, event)"
|
||||||
|
ontouchmove="cancelLongPress()"
|
||||||
|
ontouchend="endLongPress()">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input class="item-checkbox custom-checkbox-round flex-none" onclick="handleCheckboxClick(this, event)" type="checkbox"/>
|
||||||
|
<div class="text-[#2563EB] text-[15px] font-bold">78133363574</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="bg-orange-100 text-orange-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">待移库</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon icon="mdi:airplane" class="text-gray-500 text-[14px]"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">航班信息:20260709/MU2311</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">特码</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">PER</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">件数</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">85件</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">重量</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">150kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:map-marker"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">出运路径:HFE-PEK-LAX</span>
|
||||||
|
</div>
|
||||||
|
<div class="mt-4 flex justify-end border-t border-gray-100 pt-3">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer btn-active" onclick="showDetail({id: '78133363574', status: '待移库', agent: 'PER', pieces: '85', weight: '150', goodsName: '服装鞋帽', carrier: 'CA', route: 'HFE-PEK-LAX', location: 'B区-05货位', code: 'NOR', counterPerson: '--', counterTime: '--', outboundPerson: '', outboundTime: ''})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-action-overlay" onclick="closeSelf(this)">
|
||||||
|
<button class="bg-purple-500 text-white w-14 h-14 rounded-full shadow-lg shadow-purple-500/30 flex items-center justify-center text-[10px] font-bold leading-tight" onclick="event.stopPropagation();goToPhoto('78133363574')">拍照</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片3 -->
|
||||||
|
<div class="pending-card bg-white rounded-xl shadow-sm p-4 mb-3 overflow-hidden"
|
||||||
|
onmousedown="startLongPress(this, event)"
|
||||||
|
onmouseup="endLongPress()"
|
||||||
|
onmouseleave="endLongPress()"
|
||||||
|
ontouchstart="startLongPress(this, event)"
|
||||||
|
ontouchmove="cancelLongPress()"
|
||||||
|
ontouchend="endLongPress()">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input class="item-checkbox custom-checkbox-round flex-none" onclick="handleCheckboxClick(this, event)" type="checkbox"/>
|
||||||
|
<div class="text-[#2563EB] text-[15px] font-bold">78133363575</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span class="bg-orange-100 text-orange-600 text-[11px] px-2 h-5 flex items-center rounded-[6px] font-medium">待移库</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon icon="mdi:airplane" class="text-gray-500 text-[14px]"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">航班信息:20260709/MU2311</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">特码</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">DHL</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">件数</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">200件</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">重量</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">450kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:map-marker"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">出运路径:HFE-NKG-LAX</span>
|
||||||
|
</div>
|
||||||
|
<div class="mt-4 flex justify-end border-t border-gray-100 pt-3">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer btn-active" onclick="showDetail({id: '78133363575', status: '待移库', agent: 'DHL', pieces: '200', weight: '450', goodsName: '精密模具', carrier: '3U', route: 'HFE-NKG-LAX', location: 'C区-01货位', code: 'NOR', counterPerson: '--', counterTime: '--', outboundPerson: '', outboundTime: ''})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-action-overlay" onclick="closeSelf(this)">
|
||||||
|
<button class="bg-purple-500 text-white w-14 h-14 rounded-full shadow-lg shadow-purple-500/30 flex items-center justify-center text-[10px] font-bold leading-tight" onclick="event.stopPropagation();goToPhoto('78133363575')">拍照</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 已移库列表 -->
|
||||||
|
<div class="p-3 pt-4 space-y-3 hidden" id="list-shipped">
|
||||||
|
<div class="bg-white rounded-xl shadow-sm p-4 mb-3 overflow-hidden"
|
||||||
|
onmousedown="startLongPress(this, event)"
|
||||||
|
onmouseup="endLongPress()"
|
||||||
|
onmouseleave="endLongPress()"
|
||||||
|
ontouchstart="startLongPress(this, event)"
|
||||||
|
ontouchmove="cancelLongPress()"
|
||||||
|
ontouchend="endLongPress()">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="text-[#1F2937] text-[15px] font-bold">78133363001</div>
|
||||||
|
<div class="flex items-center gap-1 text-[#1F2937] text-[13px] font-medium">
|
||||||
|
<iconify-icon class="text-[#10B981]" icon="mdi:check-circle" width="16"></iconify-icon>
|
||||||
|
<span>已移库</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon icon="mdi:airplane" class="text-gray-500 text-[14px]"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">航班信息:20260709/MU2311</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">特码</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">NOR</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">件数</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">50件</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">重量</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">80kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:account-outline"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">出运路径:HFE-NKG-LAX</span>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2 flex justify-end border-t border-gray-50 pt-2">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer btn-active" onclick="showDetail({id: '78133363001', status: '已移库', agent: 'NOR', pieces: '50', weight: '80', pickupNo: 'TH20260701001', goodsName: '精密仪器', carrier: 'MU', route: 'HFE-NKG-LAX', location: 'B区-05货位', code: 'NOR', counterTime: '2026-07-05 10:30', counterPerson: '张三', outboundTime: '2026-07-05 11:45', outboundPerson: '张三'})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-action-overlay" onclick="closeSelf(this)">
|
||||||
|
<button class="bg-purple-500 text-white w-14 h-14 rounded-full shadow-lg shadow-purple-500/30 flex items-center justify-center text-[10px] font-bold leading-tight" onclick="event.stopPropagation();goToPhoto('78133363001')">拍照</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white rounded-xl shadow-sm p-4 mb-3 overflow-hidden"
|
||||||
|
onmousedown="startLongPress(this, event)"
|
||||||
|
onmouseup="endLongPress()"
|
||||||
|
onmouseleave="endLongPress()"
|
||||||
|
ontouchstart="startLongPress(this, event)"
|
||||||
|
ontouchmove="cancelLongPress()"
|
||||||
|
ontouchend="endLongPress()">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="text-[#1F2937] text-[15px] font-bold">78133363002</div>
|
||||||
|
<div class="flex items-center gap-1 text-[#1F2937] text-[13px] font-medium">
|
||||||
|
<iconify-icon class="text-[#10B981]" icon="mdi:check-circle" width="16"></iconify-icon>
|
||||||
|
<span>已移库</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon icon="mdi:airplane" class="text-gray-500 text-[14px]"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">航班信息:20260709/MU2311</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">特码</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">PER</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">件数</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">120件</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">重量</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">300kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:account-outline"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">出运路径:HFE-PEK-LAX</span>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2 flex justify-end border-t border-gray-50 pt-2">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer btn-active" onclick="showDetail({id: '78133363002', status: '已移库', agent: 'PER', pieces: '120', weight: '300', pickupNo: 'TH20260702002', goodsName: '鲜花绿植', carrier: 'CA', route: 'HFE-PEK-LAX', location: 'A区-08货位', code: 'NOR', counterTime: '2026-07-06 09:15', counterPerson: '王五', outboundTime: '2026-07-06 10:30', outboundPerson: '赵六'})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-action-overlay" onclick="closeSelf(this)">
|
||||||
|
<button class="bg-purple-500 text-white w-14 h-14 rounded-full shadow-lg shadow-purple-500/30 flex items-center justify-center text-[10px] font-bold leading-tight" onclick="event.stopPropagation();goToPhoto('78133363002')">拍照</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white rounded-xl shadow-sm p-4 mb-3 overflow-hidden"
|
||||||
|
onmousedown="startLongPress(this, event)"
|
||||||
|
onmouseup="endLongPress()"
|
||||||
|
onmouseleave="endLongPress()"
|
||||||
|
ontouchstart="startLongPress(this, event)"
|
||||||
|
ontouchmove="cancelLongPress()"
|
||||||
|
ontouchend="endLongPress()">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="text-[#1F2937] text-[15px] font-bold">78133363003</div>
|
||||||
|
<div class="flex items-center gap-1 text-[#1F2937] text-[13px] font-medium">
|
||||||
|
<iconify-icon class="text-[#10B981]" icon="mdi:check-circle" width="16"></iconify-icon>
|
||||||
|
<span>已移库</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 mb-3 flex items-center gap-1">
|
||||||
|
<iconify-icon icon="mdi:airplane" class="text-gray-500 text-[14px]"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">航班信息:20260709/MU2311</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-[#F3F4F6] rounded-lg p-3 grid grid-cols-3 text-center">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">特码</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">DHL</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">件数</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">75件</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border-l border-gray-200">
|
||||||
|
<span class="text-[#9CA3AF] text-[11px]">重量</span>
|
||||||
|
<span class="text-[#1F2937] text-[14px] font-semibold">160kg</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 flex items-center gap-1.5">
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px]" icon="mdi:account-outline"></iconify-icon>
|
||||||
|
<span class="text-[#6B7280] text-[13px]">出运路径:HFE-NKG-LAX</span>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2 flex justify-end border-t border-gray-50 pt-2">
|
||||||
|
<div class="text-[#2563EB] text-[14px] font-medium flex items-center cursor-pointer btn-active" onclick="showDetail({id: '78133363003', status: '已移库', agent: 'DHL', pieces: '75', weight: '160', pickupNo: 'TH20260703003', goodsName: '生鲜食品', carrier: '3U', route: 'HFE-NKG-LAX', location: 'D区-02货位', code: 'NOR', counterTime: '2026-07-06 14:00', counterPerson: '钱七', outboundTime: '2026-07-06 15:20', outboundPerson: '孙八'})">
|
||||||
|
查看详情 <iconify-icon icon="mdi:chevron-right" width="16"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-action-overlay" onclick="closeSelf(this)">
|
||||||
|
<button class="bg-purple-500 text-white w-14 h-14 rounded-full shadow-lg shadow-purple-500/30 flex items-center justify-center text-[10px] font-bold leading-tight" onclick="event.stopPropagation();goToPhoto('78133363003')">拍照</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 底部操作栏 -->
|
||||||
|
<div class="absolute bottom-0 w-full bg-white border-t border-gray-200 z-40 flex flex-col pt-4 pb-4" id="bottom-toolbar">
|
||||||
|
<div class="px-4 flex items-center w-full">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input class="custom-checkbox-round" id="select-all-cb" onclick="toggleSelePERll(this.checked)" type="checkbox"/>
|
||||||
|
<label class="text-[13px] text-[#1F2937] font-medium cursor-pointer" for="select-all-cb">全选</label>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1"></div>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<span class="text-[12px] text-[#9CA3AF]">已选 <span id="selected-count">0</span> 项</span>
|
||||||
|
<button class="bg-[#2563EB] text-white text-[15px] font-bold px-5 py-2 rounded-[10px] shadow-lg shadow-blue-500/25 btn-active" onclick="alert('移库操作')">
|
||||||
|
移库
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 运单详情页面 -->
|
||||||
|
<div class="page" id="page-detail">
|
||||||
|
<div class="bg-[#2563EB] text-white h-12 flex items-center justify-between px-4 flex-none">
|
||||||
|
<div class="flex items-center btn-active" onclick="switchPage('page-home')">
|
||||||
|
<iconify-icon icon="mdi:chevron-left" width="28"></iconify-icon>
|
||||||
|
<span class="text-sm font-bold -ml-1">返回</span>
|
||||||
|
</div>
|
||||||
|
<h1 class="text-lg font-medium">运单详情</h1>
|
||||||
|
<div class="w-16"></div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 overflow-y-auto no-scrollbar pb-8 p-4">
|
||||||
|
<div class="bg-white rounded-xl shadow-sm overflow-hidden border border-gray-100">
|
||||||
|
<div class="bg-[#2563EB] px-4 py-3 flex justify-between items-center text-white">
|
||||||
|
<span class="font-bold text-[17px] leading-tight" id="detail-awb">781-22222620</span>
|
||||||
|
<div class="flex items-center text-[13px] font-normal opacity-90">
|
||||||
|
<span class="w-2 h-2 bg-green-400 rounded-full mr-1.5"></span>
|
||||||
|
<span id="detail-time">2026-05-10 08:30</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-4">
|
||||||
|
<div class="flex items-center justify-between mb-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="bg-[#EF4444] text-white text-[11px] px-1.5 py-0.5 rounded leading-tight font-medium">国际进港</span>
|
||||||
|
<span class="text-[13px] font-normal text-[#666666] border-l border-gray-300 pl-2">普通货物运输</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-[22px] font-bold text-[#111827] mb-3" id="detail-goods-name">电子元器件</div>
|
||||||
|
<div class="grid grid-cols-2 gap-x-8 gap-y-3">
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">件数</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-count">55</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">重量</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-weight">622.00 kg</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">特码</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-code">NOR</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">代理</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-agent">NOR</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">出运路径</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-medium" id="detail-route">HFE-PEK-LAX</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-y-[2px]">
|
||||||
|
<div class="text-[12px] text-[#9CA3AF] font-normal">承运人</div>
|
||||||
|
<div class="text-[15px] text-[#1F2937] font-bold" id="detail-carrier">MU</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 移库信息卡片-->
|
||||||
|
<div class="mt-4 bg-white rounded-xl shadow-sm overflow-hidden border border-gray-200 hidden" id="detail-outbound-card">
|
||||||
|
<div class="bg-[#10B981] px-4 py-2.5">
|
||||||
|
<span class="text-white font-semibold text-[15px]">移库信息</span>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white px-4 py-3 grid grid-cols-2 gap-y-3">
|
||||||
|
<div class="flex flex-col" id="detail-outbound-person-row">
|
||||||
|
<span class="text-[12px] text-[#9CA3AF] font-normal mb-[2px]">移库人</span>
|
||||||
|
<span class="text-[14px] text-[#1F2937] font-medium" id="detail-outbound-person">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col" id="detail-outbound-time-row">
|
||||||
|
<span class="text-[12px] text-[#9CA3AF] font-normal mb-[2px]">移库时间</span>
|
||||||
|
<span class="text-[14px] text-[#1F2937] font-medium" id="detail-outbound-time">-</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 异常照片-->
|
||||||
|
<div class="mt-4 bg-white rounded-xl shadow-sm overflow-hidden border border-gray-100">
|
||||||
|
<div class="bg-[#F9971E] px-4 py-3 flex items-center">
|
||||||
|
<span class="text-white font-semibold text-[15px]">异常照片</span>
|
||||||
|
</div>
|
||||||
|
<div class="p-4">
|
||||||
|
<div id="image-preview-list" class="grid grid-cols-3 gap-3">
|
||||||
|
<div class="border border-dashed border-gray-300 rounded-lg h-24 flex items-center justify-center text-gray-400 text-lg">+</div>
|
||||||
|
<div class="border border-dashed border-gray-300 rounded-lg h-24 flex items-center justify-center text-gray-400 text-lg">+</div>
|
||||||
|
<div class="border border-dashed border-gray-300 rounded-lg h-24 flex items-center justify-center text-gray-400 text-lg">+</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 底部筛选遮罩 -->
|
||||||
|
<div class="overlay absolute inset-0 z-30" id="filter-overlay" onclick="toggleFilterDrawer(false)"></div>
|
||||||
|
|
||||||
|
<!-- 筛选弹窗 -->
|
||||||
|
<div class="absolute bottom-0 w-full bg-white rounded-t-3xl z-50 p-6 shadow-2xl overflow-hidden" id="filter-panel">
|
||||||
|
<div class="relative flex items-center justify-center mb-6">
|
||||||
|
<h2 class="text-center text-[18px] font-bold text-gray-900">筛选条件</h2>
|
||||||
|
<button class="absolute right-0 top-0 text-gray-400" onclick="toggleFilterDrawer(false)">
|
||||||
|
<iconify-icon class="text-2xl" icon="mdi:close"></iconify-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<!-- 1.航班日期 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">航班日期</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3 cursor-pointer">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请选择航班日期" readonly="" type="text"/>
|
||||||
|
<iconify-icon class="text-gray-500 text-[14px] flex-none" icon="mdi:calendar" width="18"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 2.航班号 -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">航班号</label>
|
||||||
|
<div class="flex items-center bg-white border border-gray-200 rounded-lg h-10 px-3">
|
||||||
|
<input class="flex-1 text-[14px] text-gray-800 placeholder-gray-400 outline-none bg-transparent" placeholder="请输入航班号" type="text" id="filterFlightNo">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">特码</label>
|
||||||
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-3 flex items-center justify-between text-gray-400">
|
||||||
|
<span class="text-sm">请选择特码</span>
|
||||||
|
<iconify-icon icon="mdi:chevron-down"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-[14px] text-gray-700 mb-1.5">运单类型</label>
|
||||||
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-3 flex items-center justify-between text-gray-400">
|
||||||
|
<span class="text-sm">请选择特码</span>
|
||||||
|
<iconify-icon icon="mdi:chevron-down"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-4 pt-2">
|
||||||
|
<button class="flex-1 bg-white border border-gray-300 text-gray-600 py-3.5 rounded-xl font-bold btn-active" onclick="alert('已重置')">
|
||||||
|
重置
|
||||||
|
</button>
|
||||||
|
<button class="flex-1 bg-[#2563EB] text-white py-3.5 rounded-xl font-bold shadow-lg shadow-blue-500/20 btn-active" onclick="toggleFilterDrawer(false)">
|
||||||
|
确认
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// 页面切换
|
||||||
|
function switchPage(pageId) {
|
||||||
|
document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
|
||||||
|
document.getElementById(pageId).classList.add('active');
|
||||||
|
if(pageId === 'page-detail'){
|
||||||
|
document.querySelector('#page-detail .no-scrollbar').scrollTop = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tab切换
|
||||||
|
function switchTab(type) {
|
||||||
|
const tabPending = document.getElementById('tab-pending');
|
||||||
|
const tabShipped = document.getElementById('tab-shipped');
|
||||||
|
const listPending = document.getElementById('list-pending');
|
||||||
|
const listShipped = document.getElementById('list-shipped');
|
||||||
|
const bottomToolbar = document.getElementById('bottom-toolbar');
|
||||||
|
|
||||||
|
if (type === 'pending') {
|
||||||
|
tabPending.classList.add('text-[#1F2937]', 'border-[#1F2937]');
|
||||||
|
tabPending.classList.remove('text-gray-400', 'border-transparent');
|
||||||
|
tabShipped.classList.add('text-gray-400', 'border-transparent');
|
||||||
|
tabShipped.classList.remove('text-[#1F2937]', 'border-[#1F2937]');
|
||||||
|
|
||||||
|
listPending.classList.remove('hidden');
|
||||||
|
listShipped.classList.add('hidden');
|
||||||
|
bottomToolbar.style.display = 'flex';
|
||||||
|
} else {
|
||||||
|
tabShipped.classList.add('text-[#1F2937]', 'border-[#1F2937]');
|
||||||
|
tabShipped.classList.remove('text-gray-400', 'border-transparent');
|
||||||
|
tabPending.classList.add('text-gray-400', 'border-transparent');
|
||||||
|
tabPending.classList.remove('text-[#1F2937]', 'border-[#1F2937]');
|
||||||
|
|
||||||
|
listShipped.classList.remove('hidden');
|
||||||
|
listPending.classList.add('hidden');
|
||||||
|
bottomToolbar.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全选
|
||||||
|
function toggleSelePERll(checked) {
|
||||||
|
const checkboxes = document.querySelectorAll('.item-checkbox');
|
||||||
|
checkboxes.forEach(cb => {
|
||||||
|
cb.checked = checked;
|
||||||
|
});
|
||||||
|
updateSelectionCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单选
|
||||||
|
function handleCheckboxClick(checkbox, event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
updateSelectionCount();
|
||||||
|
const allBox = document.getElementById('select-all-cb');
|
||||||
|
const all = Array.from(document.querySelectorAll('.item-checkbox')).every(i => i.checked);
|
||||||
|
allBox.checked = all;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新选中数量
|
||||||
|
function updateSelectionCount() {
|
||||||
|
const cnt = document.querySelectorAll('.item-checkbox:checked').length;
|
||||||
|
document.getElementById('selected-count').textContent = cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 图片存储全局对象
|
||||||
|
let photoStore = {};
|
||||||
|
|
||||||
|
// 查看详情
|
||||||
|
function showDetail(data) {
|
||||||
|
if (!data) return;
|
||||||
|
const setText = (id, val) => {
|
||||||
|
const el = document.getElementById(id);
|
||||||
|
if(el) el.textContent = val || '-';
|
||||||
|
};
|
||||||
|
setText('detail-awb', data.id);
|
||||||
|
setText('detail-goods-name', data.goodsName);
|
||||||
|
setText('detail-count', data.pieces);
|
||||||
|
setText('detail-weight', data.weight + (String(data.weight).includes('kg') ? '' : ' kg'));
|
||||||
|
setText('detail-code', data.code);
|
||||||
|
setText('detail-agent', data.agent);
|
||||||
|
setText('detail-carrier', data.carrier);
|
||||||
|
setText('detail-route', data.route || 'HFE-PEK-LAX');
|
||||||
|
|
||||||
|
// 渲染图片:最多3格,有图显示图片,空位虚线+占位
|
||||||
|
const list = document.getElementById('image-preview-list');
|
||||||
|
list.innerHTML = '';
|
||||||
|
const imgs = photoStore[data.id] || [];
|
||||||
|
const maxSlot = 3;
|
||||||
|
for(let i = 0; i < maxSlot; i++){
|
||||||
|
if(imgs[i]){
|
||||||
|
// 已有图片
|
||||||
|
const imgWrap = document.createElement('div');
|
||||||
|
imgWrap.className = 'border border-gray-200 rounded-lg h-24 overflow-hidden';
|
||||||
|
imgWrap.innerHTML = `<img src="${imgs[i]}" class="w-full h-full object-cover">`;
|
||||||
|
list.appendChild(imgWrap);
|
||||||
|
}else{
|
||||||
|
// 空虚线占位框
|
||||||
|
const emptyBox = document.createElement('div');
|
||||||
|
emptyBox.className = 'border border-dashed border-gray-300 rounded-lg h-24 flex items-center justify-center text-gray-400 text-lg';
|
||||||
|
emptyBox.textContent = '+';
|
||||||
|
list.appendChild(emptyBox);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const outboundCard = document.getElementById('detail-outbound-card');
|
||||||
|
if(data.status === '待移库'){
|
||||||
|
outboundCard.classList.add('hidden');
|
||||||
|
}else{
|
||||||
|
outboundCard.classList.remove('hidden');
|
||||||
|
setText('detail-outbound-person', data.outboundPerson);
|
||||||
|
setText('detail-outbound-time', data.outboundTime);
|
||||||
|
}
|
||||||
|
switchPage('page-detail');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选抽屉
|
||||||
|
function toggleFilterDrawer(show) {
|
||||||
|
const panel = document.getElementById('filter-panel');
|
||||||
|
const overlay = document.getElementById('filter-overlay');
|
||||||
|
if(show){
|
||||||
|
panel.classList.add('show');
|
||||||
|
overlay.classList.add('show');
|
||||||
|
}else{
|
||||||
|
panel.classList.remove('show');
|
||||||
|
overlay.classList.remove('show');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================== 长按拍照完整逻辑 =====================
|
||||||
|
let longPressTimer = null;
|
||||||
|
const LONG_PRESS_DELAY = 600;
|
||||||
|
let isShowOverlay = false;
|
||||||
|
|
||||||
|
// 关闭单个遮罩
|
||||||
|
function closeSelf(dom) {
|
||||||
|
dom.classList.remove('show');
|
||||||
|
isShowOverlay = false;
|
||||||
|
}
|
||||||
|
// 关闭全部遮罩
|
||||||
|
function closeAllOverlay() {
|
||||||
|
document.querySelectorAll('.card-action-overlay').forEach(item => {
|
||||||
|
item.classList.remove('show');
|
||||||
|
})
|
||||||
|
isShowOverlay = false;
|
||||||
|
}
|
||||||
|
// 开始长按
|
||||||
|
function startLongPress(cardDom, e) {
|
||||||
|
if (e) e.preventDefault();
|
||||||
|
if (isShowOverlay) return;
|
||||||
|
closeAllOverlay();
|
||||||
|
clearTimeout(longPressTimer);
|
||||||
|
longPressTimer = setTimeout(() => {
|
||||||
|
cardDom.querySelector('.card-action-overlay').classList.add('show');
|
||||||
|
isShowOverlay = true;
|
||||||
|
}, LONG_PRESS_DELAY)
|
||||||
|
}
|
||||||
|
// 滑动取消长按
|
||||||
|
function cancelLongPress() {
|
||||||
|
if (!isShowOverlay) clearTimeout(longPressTimer);
|
||||||
|
}
|
||||||
|
// 松开鼠标/手指
|
||||||
|
function endLongPress() {
|
||||||
|
clearTimeout(longPressTimer);
|
||||||
|
}
|
||||||
|
// 跳转拍照页,传递运单号
|
||||||
|
function goToPhoto(awb) {
|
||||||
|
sessionStorage.setItem('currentAwb', awb);
|
||||||
|
window.open('photo.html', '_blank');
|
||||||
|
}
|
||||||
|
// 页面加载读取上传图片
|
||||||
|
window.onload = function() {
|
||||||
|
const uploadData = sessionStorage.getItem('uploadedPhotos');
|
||||||
|
const awb = sessionStorage.getItem('currentAwb');
|
||||||
|
if(uploadData && awb) {
|
||||||
|
photoStore[awb] = JSON.parse(uploadData);
|
||||||
|
sessionStorage.removeItem('uploadedPhotos');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
312
documents/5.5寸手持端适配技术方案.md
Normal file
312
documents/5.5寸手持端适配技术方案.md
Normal file
@@ -0,0 +1,312 @@
|
|||||||
|
# 5.5 寸手持端适配技术方案
|
||||||
|
|
||||||
|
> 适用范围:AirLogistics(航空物流信息管理系统)在现有 10 寸平板横屏基础上,增加 5.5 寸手机竖屏形态。
|
||||||
|
> 状态:核心技术已打通并双端实机验证,参考页面「国际出港移库」已完成。
|
||||||
|
> 最后更新:2026-07-28
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、背景与结论
|
||||||
|
|
||||||
|
设计稿位于 `documents/5.5寸手持端设计文件/`,共 11 个业务入口、约 66 个界面(37 主页面 + 17 弹层/筛选面板 + 12 详情页 Tab 子页)。手机版是全新 UI,但**功能与交互保持不变**。
|
||||||
|
|
||||||
|
前置调研结论:**本项目的逻辑与 UI 分离度很好,适配成本可集中在 XML 布局重写。**
|
||||||
|
|
||||||
|
| 层 | 现状 | 手机版可复用性 |
|
||||||
|
|---|---|---|
|
||||||
|
| ViewModel(业务逻辑/网络/校验/统计) | 继承 `BaseViewModel`/`BasePageViewModel`,只持有 `MutableLiveData`,不引用 View | 完全复用 |
|
||||||
|
| Activity | 极薄。如 `IntExpStorageUseActivity` 195 行仅引用 `binding.srl`/`binding.rv`/`binding.viewModel` | 完全复用 |
|
||||||
|
| ViewHolder | 通过 id 访问控件(`binding.ivIcon` 等) | 保留同名 id 即复用 |
|
||||||
|
| Adapter | `CommonAdapter` 由 `itemLayoutId` 驱动 | 完全复用 |
|
||||||
|
| 布局 XML | Pad 横屏专用,三列表单、宽表格式 item | 需全部重写 |
|
||||||
|
| 公共 UI 组件 | `PadSearchLayout` / `PadDataLayoutNew` / `title_tool_bar` 均为 Pad 形态 | 需新增手机版 |
|
||||||
|
|
||||||
|
两个必须先解决的工程前提:
|
||||||
|
|
||||||
|
1. `app/src/main/AndroidManifest.xml` 中 **95 个 Activity 全部为 `screenOrientation="userLandscape"`**(强制横屏)
|
||||||
|
—— 现已统一改为 `unspecified`,见下文「屏幕方向」一节
|
||||||
|
2. 项目**没有任何资源限定符目录**,只有 `res/layout/`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、核心机制:布局按资源限定符自动切换
|
||||||
|
|
||||||
|
```
|
||||||
|
res/layout-sw600dp/activity_xxx.xml ← 平板(最小宽度 >= 600dp,10 寸约 800dp)
|
||||||
|
res/layout/activity_xxx.xml ← 手机(兜底,5.5 寸约 360~411dp)
|
||||||
|
```
|
||||||
|
|
||||||
|
两个变体**同名**,DataBinding 会生成同一个 Binding 基类 + 两个变体实现:
|
||||||
|
|
||||||
|
```
|
||||||
|
ActivityIntExpMoveBinding.java 公共基类(Activity 中引用的就是它)
|
||||||
|
ActivityIntExpMoveBindingImpl.java 手机变体
|
||||||
|
ActivityIntExpMoveBindingSw600dpImpl.java 平板变体
|
||||||
|
```
|
||||||
|
|
||||||
|
因此 **Activity / ViewModel / ViewHolder 完全不需要设备判断**,`layoutId()` 与 `itemLayoutId` 保持原样。
|
||||||
|
|
||||||
|
### 为什么不用「不同文件名 + 代码判断」
|
||||||
|
|
||||||
|
这是本次实施中被否掉的第一版方案,务必不要走回去:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
// ❌ 错误做法
|
||||||
|
override fun layoutId() =
|
||||||
|
if (DeviceUtil.isPhone()) R.layout.activity_xxx_phone else R.layout.activity_xxx
|
||||||
|
```
|
||||||
|
|
||||||
|
`activity_xxx_phone.xml` 生成的是 `ActivityXxxPhoneBinding`,而 `binding` 字段声明的类型是 `ActivityXxxBinding`。
|
||||||
|
泛型擦除让**编译期完全不报错**,但一进入该页面就 `ClassCastException` 崩溃。
|
||||||
|
|
||||||
|
### 变体的强制约束
|
||||||
|
|
||||||
|
| 约束 | 说明 | 保障方式 |
|
||||||
|
|---|---|---|
|
||||||
|
| DataBinding 变量必须完全一致 | 两变体 `<data>` 中 `<variable>` 名称与类型相同 | 编译失败 |
|
||||||
|
| 共用控件 id 双方都要有 | Activity/ViewHolder 引用的 id(`srl`/`rv`/`checkIcon`/`iv_icon` 等) | 见下 |
|
||||||
|
| 单侧独有 id 自动 `@Nullable` | 只在一个变体存在的 id,基类中为可空字段 | Kotlin 强制 null 检查 |
|
||||||
|
|
||||||
|
实测生成的基类字段可空性(出港移库):
|
||||||
|
|
||||||
|
```java
|
||||||
|
@NonNull public final TextView btnMove; // 两变体都有
|
||||||
|
@NonNull public final ImageView checkIcon; // 两变体都有
|
||||||
|
@NonNull public final RecyclerView rv; // 两变体都有
|
||||||
|
@NonNull public final SmartRefreshLayout srl; // 两变体都有
|
||||||
|
@Nullable public final EditText etWaybillNo; // 仅手机变体
|
||||||
|
@Nullable public final PadSearchLayout searchWaybillNo; // 仅平板变体
|
||||||
|
```
|
||||||
|
|
||||||
|
即:**约束由编译器静态保障**,不依赖人工检查。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、已实现的基础设施
|
||||||
|
|
||||||
|
### 1. `DeviceUtil`(新增)
|
||||||
|
|
||||||
|
`module_base/src/main/java/com/lukouguoji/module_base/util/DeviceUtil.kt`
|
||||||
|
|
||||||
|
按 `smallestScreenWidthDp >= 600` 区分平板/手机。关键点:读取 `Resources.getSystem()`(系统资源)而非应用 Resources,以绕开 AndroidAutoSize 对 density 的动态改写,保证判定稳定。
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
DeviceUtil.isPhone() // 是否手机
|
||||||
|
DeviceUtil.isTablet() // 是否平板
|
||||||
|
DeviceUtil.describe() // "PHONE(sw=411dp, force=AUTO)",日志排查用
|
||||||
|
DeviceUtil.forceMode = DeviceUtil.ForceMode.PHONE // 调试:平板上强制走手机布局
|
||||||
|
```
|
||||||
|
|
||||||
|
`DeviceUtil.layout(padId, phoneId)` 仅用于极少数确实需要代码级判断的场景(如非 DataBinding 布局),**常规页面一律用资源限定符**。
|
||||||
|
|
||||||
|
### 2. 屏幕方向:Manifest 写 `unspecified` + `BaseActivity` 按形态锁定
|
||||||
|
|
||||||
|
方案演进过了两轮,两次失败都有明确的实测证据,记录如下以免重蹈。
|
||||||
|
|
||||||
|
**方案 A(一期,已废弃)**:Manifest 保持 `userLandscape`,靠 `BaseActivity` 在 `onCreate` 里纠正。
|
||||||
|
缺陷:手机上「先横屏、约 1 秒后转竖屏」+ Activity 重建。因为 `screenOrientation` 由系统在
|
||||||
|
**创建 Activity 窗口时**生效,那时业务代码还没跑,代码只能事后纠正。
|
||||||
|
|
||||||
|
**方案 B(二期,已废弃)**:Manifest 改 `@integer/screen_orientation`,
|
||||||
|
`values/`=portrait、`values-sw600dp/`=userLandscape。**看似优雅,实测是错的**:
|
||||||
|
|
||||||
|
> 系统解析 Manifest 属性时用的是**默认配置,不套用设备限定符**,`values-sw600dp/` 永远不会被选中。
|
||||||
|
> 于是所有 Activity 都拿到了 `values/` 的竖屏值,平板端出现两个回归:
|
||||||
|
> 1. 先竖屏、再被 `BaseActivity` 纠正成横屏(把闪屏从手机搬到了平板)
|
||||||
|
> 2. **AutoSize 在竖屏配置下选了平板竖屏基准 720dp**(density = 1280/720 ≈ 1.78,
|
||||||
|
> 正常应为 1280/1152 ≈ 1.11)→ 交互几次后整个 UI 放大约 1.6 倍
|
||||||
|
>
|
||||||
|
> 验证方法(可复现):把 `values/` 与 `values-sw600dp/` 的取值**互换**,并临时让
|
||||||
|
> `lockOrientationByDevice()` 返回 false 以排除运行时纠正,装到平板上看首屏方向 ——
|
||||||
|
> 结果平板取的是 `values/` 的值,证明限定符被忽略。
|
||||||
|
|
||||||
|
**方案 C(现行)**:Manifest 一律写 `unspecified`,系统按设备**当前物理方向**建窗口
|
||||||
|
(平板横屏摆放 → 横屏起;手机 → 竖屏起,两端起始方向本就正确),
|
||||||
|
`BaseActivity.applyDeviceOrientation()` 再按形态锁定,因方向一致故不产生二次纠正与重建。
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<activity android:name="…"
|
||||||
|
android:configChanges="orientation|keyboardHidden"
|
||||||
|
android:screenOrientation="unspecified" />
|
||||||
|
```
|
||||||
|
|
||||||
|
全项目 192 处已统一(`module_p` 等 24 处本就是 `portrait` 的 PDA 页面保持不变)。
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
applyDeviceOrientation() // 必须在 super 之前
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun applyDeviceOrientation() {
|
||||||
|
if (!lockOrientationByDevice()) return
|
||||||
|
requestedOrientation = if (DeviceUtil.isPhone(this))
|
||||||
|
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||||
|
else
|
||||||
|
ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun lockOrientationByDevice(): Boolean = true // 子类可覆写跳过
|
||||||
|
```
|
||||||
|
|
||||||
|
**已知边界**:若平板在启动瞬间被竖持且系统自动旋转开启,仍会先竖后横。
|
||||||
|
现场平板为横屏固定安装,实测无此现象。
|
||||||
|
|
||||||
|
**验证**:手机冷启动连拍 6 帧全为竖屏;平板冷启动连拍 6 帧全为横屏(1280×800),
|
||||||
|
登录后多次切换菜单与进出页面,UI 尺寸正常无放大。
|
||||||
|
|
||||||
|
### 3. AutoSize 设计基准(易漏,后果严重)
|
||||||
|
|
||||||
|
`MyApplication.initAutoSizeConfig()` 原先只按方向切换,现增加手机分支:
|
||||||
|
|
||||||
|
| 场景 | 设计基准 |
|
||||||
|
|---|---|
|
||||||
|
| 横屏(平板) | 1152 × 720 dp |
|
||||||
|
| 竖屏 + 手机 | **390 × 844 dp** ← 本次新增 |
|
||||||
|
| 竖屏 + 平板 | 720 × 1280 dp |
|
||||||
|
| PictureSelector | 360 × 480 dp |
|
||||||
|
|
||||||
|
**若手机沿用平板竖屏的 720dp 基准,手机上所有 dp 会被压缩约一半,布局全部错位。**
|
||||||
|
|
||||||
|
### 4. 手机端公共资源
|
||||||
|
|
||||||
|
| 资源 | 内容 |
|
||||||
|
|---|---|
|
||||||
|
| `colors.xml` | `phone_primary`(#2563EB)、`phone_primary_light`、`phone_bg`、`phone_text_title/body/hint`、`phone_divider`、`phone_tag_*` |
|
||||||
|
| `bg_phone_card.xml` | 列表卡片:白底 + 12dp 圆角 + 0.5dp 边框 |
|
||||||
|
| `bg_phone_search.xml` | 搜索框:白底 + 12dp 圆角 + 1dp 边框 |
|
||||||
|
| `bg_phone_btn_primary.xml` | 主按钮:主色实底 + 10dp 圆角 + 按下态 |
|
||||||
|
| `bg_phone_tag_gray/green.xml` | 状态标签底色 |
|
||||||
|
| `layout/title_tool_bar.xml` | 手机版标题栏(平板版已移至 `layout-sw600dp/`),保留 `toolbar`/`tool_back`/`title_name` id,`setBackArrow()` 零改动复用 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、手机版 UI 规范
|
||||||
|
|
||||||
|
| 部位 | 规范 |
|
||||||
|
|---|---|
|
||||||
|
| 画布基准 | 390 × 844 dp |
|
||||||
|
| 顶栏 | 高 48dp,`phone_primary`,左「‹ 返回」,标题居中 18sp 加粗 |
|
||||||
|
| 页面背景 | `phone_bg` (#F3F4F6) |
|
||||||
|
| 列表卡片 | `bg_phone_card`,`marginHorizontal=16dp`,`marginTop=12dp`,`padding=14dp` |
|
||||||
|
| 卡片头行 | 圆形勾选框 20dp(`radiobtn_checked_style`/`radiobtn_unchecked_style`)+ 主字段 15sp 加粗 + 状态标签 |
|
||||||
|
| 卡片字段 | 两列网格,13sp,`phone_text_body`,行距 8dp |
|
||||||
|
| 状态标签 | 绿底=已完成 / 灰底=未完成,11sp,高 20dp |
|
||||||
|
| 搜索行 | 搜索框高 40dp(放大镜 + 输入 + 扫码)+ 右侧筛选按钮 40dp |
|
||||||
|
| 状态 Tab | 高 42dp,选中文字 `phone_primary` + 底部 28×3dp 指示条 |
|
||||||
|
| 底部操作条 | 白底 + `elevation=8dp`,全选 + 统计(13sp/11sp 两行)+ 主按钮 |
|
||||||
|
| 筛选弹层 | 遮罩 `#80000000` + 底部白面板,重置 / 确定各占一半 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、页面改造步骤
|
||||||
|
|
||||||
|
1. **移动平板布局**
|
||||||
|
```bash
|
||||||
|
mkdir -p module_xxx/src/main/res/layout-sw600dp
|
||||||
|
git mv module_xxx/src/main/res/layout/activity_xxx.xml module_xxx/src/main/res/layout-sw600dp/activity_xxx.xml
|
||||||
|
git mv module_xxx/src/main/res/layout/item_xxx.xml module_xxx/src/main/res/layout-sw600dp/item_xxx.xml
|
||||||
|
```
|
||||||
|
2. **新建手机布局**:在 `res/layout/` 下创建**同名**文件,保持相同 `<variable>` 与共用控件 id
|
||||||
|
3. **Kotlin 侧不动**:`layoutId()`、`itemLayoutId`、ViewHolder 全部保持原样
|
||||||
|
4. **纯 UI 交互写在 Activity**,不污染 ViewModel;状态过滤优先复用 ViewModel 既有字段
|
||||||
|
5. 手机布局顶部 `<include layout="@layout/title_tool_bar" />` 不变(变体自动切换)
|
||||||
|
|
||||||
|
### 示例:状态 Tab 零 ViewModel 改动
|
||||||
|
|
||||||
|
出港移库的 `moveState` 字段(`""` 全部 / `"0"` 未移库 / `"1"` 已移库)与查询参数本就存在,Tab 直接复用:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
// IntExpMoveActivity 中新增纯 UI 方法
|
||||||
|
fun switchTab(state: String) {
|
||||||
|
if (viewModel.moveState.value == state) return
|
||||||
|
viewModel.moveState.value = state
|
||||||
|
viewModel.searchClick() // 复用原有查询链路
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<!-- 判等把字面量放前面,避免 LiveData 为 null 时崩溃 -->
|
||||||
|
android:textColor="@{`0`.equals(viewModel.moveState) ? @color/phone_primary : @color/phone_text_body}"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、参考页面实施结果:国际出港移库
|
||||||
|
|
||||||
|
| 文件 | 改动 |
|
||||||
|
|---|---|
|
||||||
|
| `IntExpMoveViewModel.kt` | **0 行业务改动**(仅补注释) |
|
||||||
|
| `IntExpMoveViewHolder.kt` | **完全未改** |
|
||||||
|
| `IntExpMoveActivity.kt` | 仅新增 4 个纯 UI 方法:`switchTab()` / `toggleFilterPanel()` / `resetFilter()` / `confirmFilter()`,以及 `filterPanelVisible` 状态 |
|
||||||
|
| `layout-sw600dp/activity_int_exp_move.xml` | 原平板布局,内容未变,仅移动目录 |
|
||||||
|
| `layout-sw600dp/item_int_exp_move.xml` | 同上 |
|
||||||
|
| `layout/activity_int_exp_move.xml` | 新增手机版 |
|
||||||
|
| `layout/item_int_exp_move.xml` | 新增手机版 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、双端验证
|
||||||
|
|
||||||
|
| | 手机模拟器 | 平板模拟器 |
|
||||||
|
|---|---|---|
|
||||||
|
| AVD | `Medium_Phone_API_36.1` | `Aerologic_Tablet` |
|
||||||
|
| 屏幕 | 1080×2400 @420dpi | 1280×800 @160dpi |
|
||||||
|
| 形态识别 | `PHONE(sw=411dp, force=AUTO)` | `TABLET(sw=800dp, force=AUTO)` |
|
||||||
|
| 方向 | 竖屏(`unspecified` + BaseActivity 锁定,无闪屏) | 横屏 |
|
||||||
|
| 加载布局 | 手机版 | 原平板布局,**行为无变化** |
|
||||||
|
| 交互 | Tab 切换选中态迁移并触发查询;筛选弹层正常弹出/关闭 | — |
|
||||||
|
|
||||||
|
APK 内两套变体均正确打包:
|
||||||
|
|
||||||
|
```
|
||||||
|
res/layout-sw600dp-v13/activity_int_exp_move.xml
|
||||||
|
res/layout-sw600dp-v13/item_int_exp_move.xml
|
||||||
|
res/layout-sw600dp-v13/title_tool_bar.xml
|
||||||
|
res/layout/activity_int_exp_move.xml
|
||||||
|
res/layout/item_int_exp_move.xml
|
||||||
|
res/layout/title_tool_bar.xml
|
||||||
|
```
|
||||||
|
|
||||||
|
### 验证命令
|
||||||
|
|
||||||
|
```bash
|
||||||
|
~/Library/Android/sdk/emulator/emulator -list-avds
|
||||||
|
~/Library/Android/sdk/emulator/emulator -avd Medium_Phone_API_36.1 -no-snapshot-load -no-boot-anim &
|
||||||
|
|
||||||
|
adb -s <设备> install -r -t app/build/outputs/apk/debug/app-debug.apk
|
||||||
|
adb -s <设备> shell wm size && adb -s <设备> shell wm density
|
||||||
|
adb -s <设备> logcat -d -s BaseActivity:D # 查看形态识别结果
|
||||||
|
adb -s <设备> exec-out screencap -p > /tmp/shot.png
|
||||||
|
```
|
||||||
|
|
||||||
|
### 调试便利
|
||||||
|
|
||||||
|
`app/src/debug/AndroidManifest.xml`(**仅 Debug 生效,不进 Release 包**)用 `tools:replace` 将适配调试页临时置为 `exported="true"`,免去每次登录再逐级点入:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
adb shell am start -n com.lukouguoji.aerologic/com.lukouguoji.gjc.page.move.IntExpMoveActivity
|
||||||
|
```
|
||||||
|
|
||||||
|
新增调试页时在该文件追加对应 `<activity>` 即可。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 八、待办
|
||||||
|
|
||||||
|
| 项 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| `PhoneDataLayout` 手机版表单组件 | 对标 `PadDataLayoutNew`(319 行 kt)+ `DataLayoutKtx`(404 行)+ `AutoQueryManager`(179 行),支持 INPUT/SPINNER/DATE + required + AutoQuery |
|
||||||
|
| `PhoneSearchBar` 手机版搜索组件 | 当前手机版搜索框为原生 `EditText`,组件化后恢复运单号 AutoQuery 联想能力 |
|
||||||
|
| 筛选弹层内控件替换 | 当前仍复用 `PadSearchLayout`(功能完整、视觉待统一) |
|
||||||
|
| 首页 / 登录 / 我的 | **设计稿缺失**,是手机端使用闭环的前置条件 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 九、注意事项
|
||||||
|
|
||||||
|
1. 改动 `BaseActivity` / `BaseBindingActivity` / 公共组件后,**必须在平板上回归**,确认现有平板版行为不变
|
||||||
|
2. 未适配手机的页面,布局保留在 `res/layout/` 即可(两端共用),手机上视觉不佳但不会崩溃——支持渐进式适配
|
||||||
|
3. 手机版资源统一使用 `phone_*` 颜色与 `bg_phone_*` drawable,禁止直接写死色值
|
||||||
|
4. 两个 git 仓库(`aerologic-app` 与 `air-cargo`)为同一份源码的独立副本,适配改动需同步
|
||||||
BIN
documents/后端接口对接问题清单.xlsx
Normal file
BIN
documents/后端接口对接问题清单.xlsx
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user