feat: 完成国际出港移库/出库交接页面5.5寸手机端适配
- 落地手机端双形态适配框架:同名布局+资源限定符(layout/手机、 layout-sw600dp/平板)自动切换,DeviceUtil 设备形态判定,7个 手机版公共组件(PhoneSearchBar/StatusTab/DataLayout/FilterPanel/ BottomBar/StatBox/KvItem) - 完成「国际出港移库」「国际出港出库交接」两页手机端适配,新增 各自详情页(IntExpMoveDetailActivity/IntExpOutHandoverDetailActivity) - 手机端首页菜单接入"出港移库""出库交接"入口 - 修复手机端进入页面先横屏后转竖屏的闪屏问题:Manifest 全项目 192 处改为 screenOrientation="unspecified",由 BaseActivity 按设备形态运行时锁定方向 - 修复该方案的中间版本在平板端引入的回归(先竖后横 + UI放大1.6倍) - AutoSize 补充手机竖屏 390×844 设计基准 - 修复 CHANGELOG.md 因脚本异常导致的内容重复损坏(膨胀至12万行), 恢复正常结构并补充本次变更记录 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -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"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
277
.claude/skills/phone-adapt/SKILL.md
Normal file
277
.claude/skills/phone-adapt/SKILL.md
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
---
|
||||||
|
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 状态、新下拉、新排序)→ **停下来问用户**要用什么接口参数名,
|
||||||
|
连带问数据源(如「交接人」用 `DictUtils.getWHSUserList()`)
|
||||||
|
|
||||||
|
这一步不能猜。出库交接就是实测发现后端 `pageQuery` 根本不认 `hoState`,两个 Tab 返回同一批数据——
|
||||||
|
参数名对不对只有后端知道。用 `AskUserQuestion` 一次问清,并在阶段 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(
|
||||||
|
/* 原有字段… */
|
||||||
|
"hoState" to handoverState.value?.ifEmpty { null },
|
||||||
|
)
|
||||||
|
|
||||||
|
// 手机专属的额外请求(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
|
||||||
|
$P <phone> req pageQuery # 核对请求体参数确实带上了新字段
|
||||||
|
```
|
||||||
|
|
||||||
|
逐项走查:列表/卡片两种形态、详情页、筛选弹层(重置+确认)、Tab 切换、单选与全选联动、
|
||||||
|
下拉真实取数、扫码入口。每步 `crash` 都要为 0。
|
||||||
|
|
||||||
|
点完**一定要断言效果**(`texts` 或截图),不要假设点中了——加载弹窗盖屏时 `input tap` 会被静默吞掉。
|
||||||
|
|
||||||
|
手机端还要确认方向没闪屏(冷启动采样 `mRotation` 应恒为 0),命令见 `references/verification.md`。
|
||||||
|
|
||||||
|
**Pad 端回归**(必做):同样安装到平板模拟器打开同一页面截图,与改造前逐项对比——
|
||||||
|
搜索条数量、默认值、按钮、底部统计都应一致。改过 `module_base` 公共组件时这步尤其不能省。
|
||||||
|
|
||||||
|
## 阶段 6:与设计稿二次核对
|
||||||
|
|
||||||
|
把阶段 1 的设计稿截图和阶段 5 的实机截图放在一起,用 Read 工具对照看,逐项核对:
|
||||||
|
|
||||||
|
配色 / 字号 / 字重 / 圆角 / 内外间距 / 图标形状与大小 / 控件顺序 / 选中态 / 状态标签配色 /
|
||||||
|
**空值兜底**(真实数据空字段很常见——出库交接就出现过「库位」为空时橙色高亮标签只剩一个孤零零的
|
||||||
|
小色块,需要空值时不套标签底)。
|
||||||
|
|
||||||
|
服务端当天没数据时(列表空)先放宽条件重查;仍为空就临时在 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,把**定位手法**也写上,不只写结论
|
||||||
|
- `CHANGELOG.md` 追加条目(新增 / 改进 / 修复 / 验证 四段),记忆文件
|
||||||
|
`phone-5.5inch-adaptation.md` 同步
|
||||||
|
|
||||||
|
向用户汇报时明确写出这四块:
|
||||||
|
|
||||||
|
1. 新增/修改的文件清单(布局、组件、Activity/ViewModel/Bean)
|
||||||
|
2. Pad 端零破坏的具体做法 + 回归结论
|
||||||
|
3. 复用与新增的公共组件
|
||||||
|
4. **待确认事项**:后端未生效的参数、自己推断的业务规则(如 IMP 代码红/绿的判定)、
|
||||||
|
设计稿与平板功能的差异。如实说,别含糊。
|
||||||
|
|
||||||
|
## 参考文件
|
||||||
|
|
||||||
|
- `references/components.md` — 7 个手机版公共组件的属性表、用法与封装新组件的规矩(写布局前读)
|
||||||
|
- `references/pad-safety.md` — 布局变体约束、Pad 零破坏模式、易崩点(写代码前读)
|
||||||
|
- `references/verification.md` — 双端 adb 命令、登录与直启、已知环境坑(验证前读)
|
||||||
|
- `scripts/design_shots.py` — 设计稿逐态渲染截图
|
||||||
|
- `scripts/ui_probe.sh` — 实机取文字/按文字点击/等待/截图/抓请求体/查崩溃
|
||||||
120
.claude/skills/phone-adapt/references/components.md
Normal file
120
.claude/skills/phone-adapt/references/components.md
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
# 手机版公共组件(`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 → 橙色高亮标签) |
|
||||||
|
|
||||||
|
`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_badge`
|
||||||
|
`bg_phone_tag_green/gray/red/orange` `bg_phone_card_header_blue/green`
|
||||||
|
- 图标:`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`(圆形复选框)
|
||||||
|
- 复用 Pad 的矢量图:`img_search` `img_scan` `img_filter`(可 `app:tint` 染色)
|
||||||
|
|
||||||
|
设计稿里的 MDI 图标若缺失,直接写 24×24 的 vector(用 MDI 官方 path),比找位图靠谱且能染色。
|
||||||
167
.claude/skills/phone-adapt/references/pad-safety.md
Normal file
167
.claude/skills/phone-adapt/references/pad-safety.md
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
# 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`。
|
||||||
|
|
||||||
|
## 业务层零破坏的三个模式
|
||||||
|
|
||||||
|
### 新增查询维度:默认空值 + 仅非空进请求
|
||||||
|
|
||||||
|
平板布局没有对应控件 → 字段恒为空 → 不进请求体 → 平板查询与改造前逐字节一致。
|
||||||
|
|
||||||
|
```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 必须写资源引用
|
||||||
|
|
||||||
|
新增 Activity 注册时:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<activity android:name="…"
|
||||||
|
android:configChanges="orientation|keyboardHidden"
|
||||||
|
android:exported="false"
|
||||||
|
android:screenOrientation="@integer/screen_orientation" />
|
||||||
|
```
|
||||||
|
|
||||||
|
**不要写死 `userLandscape`。** `screenOrientation` 由系统在创建 Activity 窗口时生效,
|
||||||
|
那时业务代码还没跑;写死横屏后即使 `BaseActivity` 在 `super.onCreate` 之前改成竖屏,
|
||||||
|
用户也会看到「先横屏、约 1 秒后转竖屏」的闪屏和重建。
|
||||||
|
|
||||||
|
资源取值:`module_base/res/values/integers.xml` = 1(portrait),
|
||||||
|
`values-sw600dp/integers.xml` = 11(userLandscape)。全项目已统一替换。
|
||||||
|
|
||||||
|
## 改 module_base 公共代码时
|
||||||
|
|
||||||
|
`module_base` 被所有业务模块依赖,改动会影响全部页面。原则:
|
||||||
|
|
||||||
|
- **只做增量**:加新组件、新颜色、新 drawable,别改既有组件的行为
|
||||||
|
- 确实要改公共基类(`BaseActivity` / `BaseBindingActivity` / Pad 系组件)时,
|
||||||
|
**必须在平板上回归**至少 2~3 个不同类型的既有页面
|
||||||
|
- Bean 上加只读计算属性是安全的(Gson 只序列化字段,不动 getter);
|
||||||
|
加**字段**要谨慎,会进请求体
|
||||||
|
|
||||||
|
## 已知的既有问题(不是你改坏的)
|
||||||
|
|
||||||
|
用 `am start` 直启页面时,若**先经过首页**再启目标页,会崩在
|
||||||
|
`LoadingModel.showLoading` → XPopup `popupInfo is null`。在**未改动**的页面上同样复现,
|
||||||
|
属于既有缺陷。**冷启动直启不受影响**(`force-stop` 后直接 `am start`)。
|
||||||
|
|
||||||
|
遇到崩溃先做这个对照实验再下结论:拿一个你没碰过的页面用同样方式打开,看是否同样崩。
|
||||||
166
.claude/skills/phone-adapt/references/verification.md
Normal file
166
.claude/skills/phone-adapt/references/verification.md
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
# 端到端验证手册
|
||||||
|
|
||||||
|
目标:在**真实接口**下把手机端走通,并确认平板端没退化。只看编译通过是不够的——
|
||||||
|
本次适配里"筛选条件被静默清空"和"后端不认新参数"两个问题,都只有跑真机才暴露。
|
||||||
|
|
||||||
|
## 环境
|
||||||
|
|
||||||
|
```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
|
||||||
|
```
|
||||||
|
|
||||||
|
登录页账号密码需要用户提供。填表用 `input text`,注意 `#` 等字符要转义(`Aa123456\#`)。
|
||||||
|
底部有「首页 / 国内 / 国际 / 我的」Tab,国际业务页找对应入口。
|
||||||
|
|
||||||
|
**首页菜单是按权限过滤的**:当前账号角色没有该权限时,入口根本不显示(本次 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。看到请求体里有你的字段(如 `"hoState": "0"`)只说明客户端对了。
|
||||||
|
**服务端是否生效要用行为验证**:切到另一个 Tab,看返回数据是否真的变了。
|
||||||
|
|
||||||
|
本次实测:请求正确携带 `hoState:"0"/"1"`,但两个 Tab 返回同一批数据 → 后端没做过滤。
|
||||||
|
这种情况**必须在交付说明里如实标注**,不能让它看起来是通的。
|
||||||
|
|
||||||
|
## 无数据时怎么核对 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="@integer/screen_orientation"`。
|
||||||
|
|
||||||
|
## 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
|
||||||
223
CHANGELOG.md
223
CHANGELOG.md
@@ -1,101 +1,122 @@
|
|||||||
# 版本变更日志 (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
|
## [1.9.0] - 2026-07-29
|
||||||
|
|
||||||
### 新增 (Added)
|
### 新增 (Added)
|
||||||
- 完善 Claude Code 配置,添加 Android 开发权限
|
- 5.5 寸手持端双形态适配框架:同名布局 + 资源限定符(`layout/` 手机、`layout-sw600dp/` 平板)自动切换,业务逻辑(ViewModel/ViewHolder)零改动
|
||||||
- 创建 8 个快捷命令 (/build-debug, /install, /logs 等)
|
- 新增 `DeviceUtil` 设备形态判定工具,及手机版公共组件库(`PhoneSearchBar`、`PhoneStatusTab`、`PhoneDataLayout`、`PhoneFilterPanel`、`PhoneBottomBar`、`PhoneStatBox`、`PhoneKvItem`)
|
||||||
- 定制 CLAUDE.md 为 Android 项目专用开发指南
|
- 完成「国际出港移库」「国际出港出库交接」两个页面的手机端适配,含各自的详情页(`IntExpMoveDetailActivity`、`IntExpOutHandoverDetailActivity`)
|
||||||
- 添加 CONTRIBUTING.md 贡献指南文档
|
- 手机端首页菜单接入「出港移库」「出库交接」入口
|
||||||
- 添加 CHANGELOG.md 版本变更日志
|
|
||||||
|
### 修复 (Fixed)
|
||||||
### 改进 (Changed)
|
- 修复手机端进入页面时「先横屏、约 1 秒后转竖屏」的闪屏问题:Manifest 统一改为 `android:screenOrientation="unspecified"`(全项目 192 处),由 `BaseActivity.applyDeviceOrientation()` 按设备形态在运行时锁定方向,避免系统建窗口时用错误方向
|
||||||
- 优化首页菜单交互体验
|
- 修复平板端因中间方案(`@integer/screen_orientation` 资源限定符)引入的回归:先竖屏再转横屏,且交互后 UI 整体放大约 1.6 倍(AutoSize 误选平板竖屏基准所致);验证系统解析 Manifest 属性不套用设备限定符,恢复为 `unspecified` 方案后两端方向与缩放均恢复正常
|
||||||
- 改进 UI 界面显示效果
|
- AutoSize 增加手机竖屏专用设计基准 390×844dp,避免手机端沿用平板竖屏 720dp 基准导致 UI 压缩
|
||||||
|
|
||||||
### 技术栈
|
### 技术栈
|
||||||
- Kotlin 1.6.21
|
- Kotlin 1.6.21
|
||||||
- Android Gradle Plugin 7.2.0
|
- Android Gradle Plugin 7.2.0
|
||||||
- Gradle 7.3.3
|
- Gradle 7.3.3
|
||||||
- minSdk 24, targetSdk 30, compileSdk 31
|
- minSdk 24, targetSdk 30, compileSdk 31
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## [1.8.x] - 之前版本
|
## [1.8.4] - 2024-12-02
|
||||||
|
|
||||||
### 主要功能
|
### 新增 (Added)
|
||||||
- 国内出港业务模块 (货物收运、复磅称重、转运管理、出库装机)
|
- 完善 Claude Code 配置,添加 Android 开发权限
|
||||||
- 国内进港业务模块 (舱单管理、卸机入库、出库提货、移库管理)
|
- 创建 8 个快捷命令 (/build-debug, /install, /logs 等)
|
||||||
- 国际出港业务模块 (国际货物收运、板箱组装、ULD容器管理)
|
- 定制 CLAUDE.md 为 Android 项目专用开发指南
|
||||||
- 国际进港业务模块 (国际舱单管理、报文解析、理货管理)
|
- 添加 CONTRIBUTING.md 贡献指南文档
|
||||||
- 航班管理模块 (航班查询、航班统计)
|
- 添加 CHANGELOG.md 版本变更日志
|
||||||
- 货物追踪模块 (货物状态追踪、运输日志)
|
|
||||||
- 监装监卸模块 (监装监卸管理)
|
### 改进 (Changed)
|
||||||
- PDA功能模块 (PDA专用功能)
|
- 优化首页菜单交互体验
|
||||||
- 蓝牙打印模块 (佳博打印机集成)
|
- 改进 UI 界面显示效果
|
||||||
|
|
||||||
### 核心架构
|
### 技术栈
|
||||||
- MVVM 架构模式
|
- Kotlin 1.6.21
|
||||||
- 组件化模块设计 (11个业务模块 + 1个基础库)
|
- Android Gradle Plugin 7.2.0
|
||||||
- DataBinding 双向绑定
|
- Gradle 7.3.3
|
||||||
- Kotlin Coroutines + Flow 异步处理
|
- minSdk 24, targetSdk 30, compileSdk 31
|
||||||
- ARouter 模块间通信
|
|
||||||
- Retrofit + OkHttp 网络请求
|
---
|
||||||
- Glide 图片加载
|
|
||||||
- MPAndroidChart 图表展示
|
## [1.8.x] - 之前版本
|
||||||
|
|
||||||
### 开发基础设施
|
### 主要功能
|
||||||
- BaseActivity/BaseBindingActivity 基类
|
- 国内出港业务模块 (货物收运、复磅称重、转运管理、出库装机)
|
||||||
- BaseViewModel/BasePageViewModel 基类
|
- 国内进港业务模块 (舱单管理、卸机入库、出库提货、移库管理)
|
||||||
- CommonAdapter + BaseViewHolder 列表适配
|
- 国际出港业务模块 (国际货物收运、板箱组装、ULD容器管理)
|
||||||
- PadSearchLayout/PadDataLayout 自定义组件
|
- 国际进港业务模块 (国际舱单管理、报文解析、理货管理)
|
||||||
- 完整的 Kotlin 扩展函数库
|
- 航班管理模块 (航班查询、航班统计)
|
||||||
- DataBinding 适配器集合
|
- 货物追踪模块 (货物状态追踪、运输日志)
|
||||||
|
- 监装监卸模块 (监装监卸管理)
|
||||||
---
|
- PDA功能模块 (PDA专用功能)
|
||||||
|
- 蓝牙打印模块 (佳博打印机集成)
|
||||||
## 版本说明
|
|
||||||
|
### 核心架构
|
||||||
### 版本号规则
|
- MVVM 架构模式
|
||||||
- **Major.Minor.Patch** (例: 1.8.4)
|
- 组件化模块设计 (11个业务模块 + 1个基础库)
|
||||||
- **Major**: 重大架构变更或不兼容的 API 修改
|
- DataBinding 双向绑定
|
||||||
- **Minor**: 新功能添加,向下兼容
|
- Kotlin Coroutines + Flow 异步处理
|
||||||
- **Patch**: Bug 修复和小的改进
|
- ARouter 模块间通信
|
||||||
|
- Retrofit + OkHttp 网络请求
|
||||||
### 变更类型
|
- Glide 图片加载
|
||||||
- **Added**: 新增功能
|
- MPAndroidChart 图表展示
|
||||||
- **Changed**: 功能改进或变更
|
|
||||||
- **Deprecated**: 即将废弃的功能
|
### 开发基础设施
|
||||||
- **Removed**: 已移除的功能
|
- BaseActivity/BaseBindingActivity 基类
|
||||||
- **Fixed**: Bug 修复
|
- BaseViewModel/BasePageViewModel 基类
|
||||||
- **Security**: 安全性修复
|
- CommonAdapter + BaseViewHolder 列表适配
|
||||||
|
- PadSearchLayout/PadDataLayout 自定义组件
|
||||||
---
|
- 完整的 Kotlin 扩展函数库
|
||||||
|
- DataBinding 适配器集合
|
||||||
## 未来计划
|
|
||||||
|
---
|
||||||
### 待开发功能
|
|
||||||
- [ ] 优化数据同步机制
|
## 版本说明
|
||||||
- [ ] 增强离线模式支持
|
|
||||||
- [ ] 改进用户权限管理
|
### 版本号规则
|
||||||
- [ ] 优化蓝牙打印稳定性
|
- **Major.Minor.Patch** (例: 1.8.4)
|
||||||
- [ ] 添加数据导出功能
|
- **Major**: 重大架构变更或不兼容的 API 修改
|
||||||
- [ ] 性能监控和分析
|
- **Minor**: 新功能添加,向下兼容
|
||||||
|
- **Patch**: Bug 修复和小的改进
|
||||||
### 技术改进
|
|
||||||
- [ ] 升级到 Kotlin 2.0
|
### 变更类型
|
||||||
- [ ] 迁移到 Jetpack Compose
|
- **Added**: 新增功能
|
||||||
- [ ] 优化构建速度
|
- **Changed**: 功能改进或变更
|
||||||
- [ ] 完善单元测试覆盖
|
- **Deprecated**: 即将废弃的功能
|
||||||
- [ ] 添加 UI 自动化测试
|
- **Removed**: 已移除的功能
|
||||||
|
- **Fixed**: Bug 修复
|
||||||
---
|
- **Security**: 安全性修复
|
||||||
|
|
||||||
**维护**: 本文档应在每次版本发布时更新。
|
---
|
||||||
**负责人**: 项目维护团队
|
|
||||||
**最后更新**: 2024-12-02
|
## 未来计划
|
||||||
|
|
||||||
|
### 待开发功能
|
||||||
|
- [ ] 优化数据同步机制
|
||||||
|
- [ ] 增强离线模式支持
|
||||||
|
- [ ] 改进用户权限管理
|
||||||
|
- [ ] 优化蓝牙打印稳定性
|
||||||
|
- [ ] 添加数据导出功能
|
||||||
|
- [ ] 性能监控和分析
|
||||||
|
|
||||||
|
### 技术改进
|
||||||
|
- [ ] 升级到 Kotlin 2.0
|
||||||
|
- [ ] 迁移到 Jetpack Compose
|
||||||
|
- [ ] 优化构建速度
|
||||||
|
- [ ] 完善单元测试覆盖
|
||||||
|
- [ ] 添加 UI 自动化测试
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**维护**: 本文档应在每次版本发布时更新。
|
||||||
|
**负责人**: 项目维护团队
|
||||||
|
**最后更新**: 2026-07-29
|
||||||
|
|||||||
307
CLAUDE.md
307
CLAUDE.md
@@ -839,6 +839,281 @@ adb logcat | grep "com.lukouguoji.aerologic" # 日志
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 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. **回到手机端首页加菜单入口**(最易遗忘,见下节)——不加的话页面在手机上根本进不去
|
||||||
|
|
||||||
|
### 手机端首页菜单入口(适配完必须加,否则没入口)
|
||||||
|
|
||||||
|
手机端首页是 `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` |
|
||||||
|
|
||||||
|
**`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`(框架参考页,筛选弹层内暂仍用 `PadSearchLayout`)
|
||||||
|
- 「国际出港出库交接」`IntExpOutHandoverActivity` + 「板箱详情」`IntExpOutHandoverDetailActivity`
|
||||||
|
(公共组件首个完整落地页,双端实机验证通过)
|
||||||
|
- ⏳ **待办**:
|
||||||
|
- 把「移库」页筛选弹层内的 `PadSearchLayout` 换成 `PhoneDataLayout`,视觉统一
|
||||||
|
- `PhoneSearchBar` 接入 AutoQuery 联想(`AutoQueryManager` 目前只对接了 Pad 系组件)
|
||||||
|
|
||||||
|
### 调试便利:直接拉起页面
|
||||||
|
|
||||||
|
`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 路径速查
|
||||||
|
|
||||||
### 基类与常用类
|
### 基类与常用类
|
||||||
@@ -870,6 +1145,7 @@ adb logcat | grep "com.lukouguoji.aerologic" # 日志
|
|||||||
| 类 | 正确路径 |
|
| 类 | 正确路径 |
|
||||||
|----|----------|
|
|----|----------|
|
||||||
| `DictUtils` | `com.lukouguoji.module_base.util.DictUtils` |
|
| `DictUtils` | `com.lukouguoji.module_base.util.DictUtils` |
|
||||||
|
| `DeviceUtil` | `com.lukouguoji.module_base.util.DeviceUtil` |
|
||||||
| `MediaUtil` | `com.lukouguoji.module_base.util.MediaUtil` |
|
| `MediaUtil` | `com.lukouguoji.module_base.util.MediaUtil` |
|
||||||
| `UploadUtil` | `com.lukouguoji.module_base.util.UploadUtil` |
|
| `UploadUtil` | `com.lukouguoji.module_base.util.UploadUtil` |
|
||||||
| `KeyValue` | `dev.utils.app.info.KeyValue` |
|
| `KeyValue` | `dev.utils.app.info.KeyValue` |
|
||||||
@@ -896,6 +1172,12 @@ 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`(见「屏幕方向」小节的 ⛔ 说明) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -961,10 +1243,16 @@ private fun loadDictLists() {
|
|||||||
```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 寸手持端双形态适配规范」
|
||||||
|
|
||||||
### 常见业务操作
|
### 常见业务操作
|
||||||
|
|
||||||
@@ -1112,6 +1400,9 @@ Glide.with(itemView.context).load(glideUrl).into(binding.ivThumbnail)
|
|||||||
- `ic_new_expand`(全部展开/收起)36dp + padding 4dp
|
- `ic_new_expand`(全部展开/收起)36dp + padding 4dp
|
||||||
- **图标之间间距统一 `marginStart=16dp`**(禁止使用 8dp,会导致视觉过近)
|
- **图标之间间距统一 `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,禁止直接写死色值
|
||||||
|
|
||||||
### 环境配置
|
### 环境配置
|
||||||
|
|
||||||
@@ -1125,4 +1416,16 @@ Glide.with(itemView.context).load(glideUrl).into(binding.ivThumbnail)
|
|||||||
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)
|
||||||
|
|||||||
42
app/src/debug/AndroidManifest.xml
Normal file
42
app/src/debug/AndroidManifest.xml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?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" />
|
||||||
|
|
||||||
|
</application>
|
||||||
|
</manifest>
|
||||||
File diff suppressed because it is too large
Load Diff
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/航空货运APP-5.5寸手持端UI适配-工时报价明细.xlsx
Normal file
BIN
documents/航空货运APP-5.5寸手持端UI适配-工时报价明细.xlsx
Normal file
Binary file not shown.
BIN
documents/航空货运APP-5.5寸手持端适配报价单(对外).xlsx
Normal file
BIN
documents/航空货运APP-5.5寸手持端适配报价单(对外).xlsx
Normal file
Binary file not shown.
BIN
documents/航空货运APP-5.5寸手持端适配报价单.xlsx
Normal file
BIN
documents/航空货运APP-5.5寸手持端适配报价单.xlsx
Normal file
Binary file not shown.
BIN
documents/长卿科技-航空货运作业管理系统报价.xlsx
Normal file
BIN
documents/长卿科技-航空货运作业管理系统报价.xlsx
Normal file
Binary file not shown.
@@ -1,33 +1,33 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.lukouguoji.module_base">
|
package="com.lukouguoji.module_base">
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/logot"
|
android:icon="@mipmap/logot"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:roundIcon="@mipmap/logot"
|
android:roundIcon="@mipmap/logot"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.Aerologic">
|
android:theme="@style/Theme.Aerologic">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:screenOrientation="userLandscape"
|
android:screenOrientation="unspecified"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<!-- 屏幕适配 -->
|
<!-- 屏幕适配 -->
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="design_width_in_dp"
|
android:name="design_width_in_dp"
|
||||||
android:value="1152" />
|
android:value="1152" />
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="design_height_in_dp"
|
android:name="design_height_in_dp"
|
||||||
android:value="720" />
|
android:value="720" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -2,6 +2,7 @@ package com.lukouguoji.module_base
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.pm.ActivityInfo
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
@@ -26,6 +27,7 @@ import com.yanzhenjie.permission.runtime.Permission
|
|||||||
import com.yzq.zxinglibrary.android.CaptureActivity
|
import com.yzq.zxinglibrary.android.CaptureActivity
|
||||||
import com.yzq.zxinglibrary.bean.ZxingConfig
|
import com.yzq.zxinglibrary.bean.ZxingConfig
|
||||||
import com.yzq.zxinglibrary.common.Constant
|
import com.yzq.zxinglibrary.common.Constant
|
||||||
|
import com.lukouguoji.module_base.util.DeviceUtil
|
||||||
import dev.utils.app.HandlerUtils
|
import dev.utils.app.HandlerUtils
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -49,15 +51,48 @@ open class BaseActivity : AppCompatActivity(), CoroutineScope {
|
|||||||
private var timerTask: TimerTask? = null
|
private var timerTask: TimerTask? = null
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
// 必须在 super.onCreate 之前设置,避免进入页面后再旋转造成闪屏与重建
|
||||||
|
applyDeviceOrientation()
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
// requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
|
||||||
setContentView(R.layout.activity_base)
|
setContentView(R.layout.activity_base)
|
||||||
Log.d("BaseActivity", javaClass.simpleName)
|
Log.d("BaseActivity", "${javaClass.simpleName} ${DeviceUtil.describe()}")
|
||||||
ActivityCollector.addActivity(this)
|
ActivityCollector.addActivity(this)
|
||||||
ARouter.getInstance().inject(this); /////////必须要写这行,自动注入解析
|
ARouter.getInstance().inject(this); /////////必须要写这行,自动注入解析
|
||||||
loadingDialog = LoadingDialog(this)
|
loadingDialog = LoadingDialog(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按设备形态锁定屏幕方向 —— **兜底手段**
|
||||||
|
*
|
||||||
|
* 方向的主控权在 Manifest:各 Activity 统一写
|
||||||
|
* `android:screenOrientation="@integer/screen_orientation"`,
|
||||||
|
* 由资源限定符取值(`values/` = portrait,`values-sw600dp/` = userLandscape)。
|
||||||
|
* 这样方向在**窗口创建阶段**就已确定,不会出现"先横屏、约 1 秒后转竖屏"的闪屏。
|
||||||
|
*
|
||||||
|
* 本方法只作为安全网:万一某个 Activity 的 Manifest 漏配(仍写死 userLandscape),
|
||||||
|
* 至少还能在手机上纠正为竖屏——但那种情况下闪屏依旧存在,应当去补 Manifest。
|
||||||
|
*
|
||||||
|
* 子类如需特殊方向(如扫码页),覆写 [lockOrientationByDevice] 返回 false 即可跳过。
|
||||||
|
*/
|
||||||
|
protected open fun applyDeviceOrientation() {
|
||||||
|
if (!lockOrientationByDevice()) return
|
||||||
|
try {
|
||||||
|
requestedOrientation = if (DeviceUtil.isPhone(this)) {
|
||||||
|
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||||
|
} else {
|
||||||
|
ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// 半透明 / 悬浮类 Activity 不允许指定方向,忽略即可
|
||||||
|
Log.w("BaseActivity", "setRequestedOrientation failed: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否由基类按设备形态自动锁定方向,默认开启
|
||||||
|
*/
|
||||||
|
protected open fun lockOrientationByDevice(): Boolean = true
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
job.cancel()
|
job.cancel()
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import com.cretin.www.cretinautoupdatelibrary.model.UpdateConfig
|
|||||||
import com.cretin.www.cretinautoupdatelibrary.utils.AppUpdateUtils
|
import com.cretin.www.cretinautoupdatelibrary.utils.AppUpdateUtils
|
||||||
import com.cretin.www.cretinautoupdatelibrary.utils.SSLUtils.TrustAllHostnameVerifier
|
import com.cretin.www.cretinautoupdatelibrary.utils.SSLUtils.TrustAllHostnameVerifier
|
||||||
import com.lukouguoji.module_base.handler.MyCrashHandler
|
import com.lukouguoji.module_base.handler.MyCrashHandler
|
||||||
|
import com.lukouguoji.module_base.util.DeviceUtil
|
||||||
import com.lukouguoji.module_base.util.OkHttp3Connection
|
import com.lukouguoji.module_base.util.OkHttp3Connection
|
||||||
import com.scwang.smart.refresh.footer.ClassicsFooter
|
import com.scwang.smart.refresh.footer.ClassicsFooter
|
||||||
import com.scwang.smart.refresh.header.ClassicsHeader
|
import com.scwang.smart.refresh.header.ClassicsHeader
|
||||||
@@ -79,20 +80,26 @@ class MyApplication : Application() {
|
|||||||
.setScreenHeight(activity.resources.displayMetrics.heightPixels)
|
.setScreenHeight(activity.resources.displayMetrics.heightPixels)
|
||||||
//根据屏幕方向,设置设计尺寸
|
//根据屏幕方向,设置设计尺寸
|
||||||
if (activity.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
if (activity.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||||
//设置横屏设计尺寸
|
//设置横屏设计尺寸(平板)
|
||||||
AutoSizeConfig.getInstance()
|
AutoSizeConfig.getInstance()
|
||||||
.setDesignWidthInDp(1152)
|
.setDesignWidthInDp(DeviceUtil.TABLET_DESIGN_WIDTH_DP_LAND)
|
||||||
.setDesignHeightInDp(720)
|
.setDesignHeightInDp(DeviceUtil.TABLET_DESIGN_HEIGHT_DP_LAND)
|
||||||
} else {
|
} else {
|
||||||
if(activity.javaClass.simpleName.startsWith("PictureSelectorSupporterActivity")){
|
if(activity.javaClass.simpleName.startsWith("PictureSelectorSupporterActivity")){
|
||||||
AutoSizeConfig.getInstance()
|
AutoSizeConfig.getInstance()
|
||||||
.setDesignWidthInDp(360)
|
.setDesignWidthInDp(360)
|
||||||
.setDesignHeightInDp(480)
|
.setDesignHeightInDp(480)
|
||||||
}else{
|
} else if (DeviceUtil.isPhone(activity)) {
|
||||||
//设置竖屏设计尺寸
|
//手机竖屏:按 5.5 寸手持端设计稿画布 390 × 844 换算
|
||||||
|
//若沿用平板竖屏的 720 × 1280 基准,手机上所有 dp 会被压缩约一半,布局全部错位
|
||||||
AutoSizeConfig.getInstance()
|
AutoSizeConfig.getInstance()
|
||||||
.setDesignWidthInDp(720)
|
.setDesignWidthInDp(DeviceUtil.PHONE_DESIGN_WIDTH_DP)
|
||||||
.setDesignHeightInDp(1280)
|
.setDesignHeightInDp(DeviceUtil.PHONE_DESIGN_HEIGHT_DP)
|
||||||
|
} else {
|
||||||
|
//设置竖屏设计尺寸(平板)
|
||||||
|
AutoSizeConfig.getInstance()
|
||||||
|
.setDesignWidthInDp(DeviceUtil.TABLET_DESIGN_WIDTH_DP_PORT)
|
||||||
|
.setDesignHeightInDp(DeviceUtil.TABLET_DESIGN_HEIGHT_DP_PORT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,17 @@ abstract class BaseBindingActivity<T : ViewDataBinding, VM : ViewModel> : BaseAc
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
//dataBinding初始化
|
/*
|
||||||
|
* dataBinding初始化
|
||||||
|
*
|
||||||
|
* 平板 / 手机双形态的布局切换由 Android 资源限定符自动完成,此处无需分支:
|
||||||
|
* res/layout-sw600dp/xxx.xml → 平板(最小宽度 >= 600dp)
|
||||||
|
* res/layout/xxx.xml → 手机(兜底)
|
||||||
|
* 两个变体同名,DataBinding 会生成同一个 Binding 类,因此 Activity 与 ViewModel 无需改动。
|
||||||
|
*
|
||||||
|
* 注意:不要按「不同文件名 + 代码判断」的方式切换布局,
|
||||||
|
* 那样会生成两个不同的 Binding 类,泛型擦除下编译期无法发现,运行时必然 ClassCastException。
|
||||||
|
*/
|
||||||
binding = DataBindingUtil.setContentView(this, layoutId())
|
binding = DataBindingUtil.setContentView(this, layoutId())
|
||||||
binding.lifecycleOwner = this
|
binding.lifecycleOwner = this
|
||||||
|
|
||||||
@@ -37,6 +47,9 @@ abstract class BaseBindingActivity<T : ViewDataBinding, VM : ViewModel> : BaseAc
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 布局ID
|
* 布局ID
|
||||||
|
*
|
||||||
|
* 双形态适配时保持同一个 id 即可,具体加载哪份布局由资源限定符决定:
|
||||||
|
* res/layout-sw600dp/ 平板 res/layout/ 手机
|
||||||
*/
|
*/
|
||||||
abstract fun layoutId(): Int
|
abstract fun layoutId(): Int
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,19 @@
|
|||||||
package com.lukouguoji.module_base.bean
|
package com.lukouguoji.module_base.bean
|
||||||
|
|
||||||
class ActionBean(
|
/**
|
||||||
val title: String,
|
* 手持端(手机版)首页菜单项
|
||||||
val icon: Int,
|
*
|
||||||
val key: String = ""
|
* @param title 菜单显示名称
|
||||||
) {
|
* @param icon 菜单图标
|
||||||
}
|
* @param key 权限串(取 [com.lukouguoji.module_base.common.Constant.AuthName] 中的常量)。
|
||||||
|
* 菜单按登录返回的 authList 是否包含该串来决定显不显示
|
||||||
|
* @param route ARouter 路由路径。填了就由通用逻辑直接跳转,无需再写 when 分支;
|
||||||
|
* 留空表示由所在 ViewModel 的 onItemClick 自行处理(module_p 内的 PDA 页面走这条)
|
||||||
|
*/
|
||||||
|
class ActionBean(
|
||||||
|
val title: String,
|
||||||
|
val icon: Int,
|
||||||
|
val key: String = "",
|
||||||
|
val route: String = ""
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|||||||
@@ -56,4 +56,21 @@ data class GjcMove(
|
|||||||
var isSelected: Boolean
|
var isSelected: Boolean
|
||||||
get() = checked.get()
|
get() = checked.get()
|
||||||
set(value) = checked.set(value)
|
set(value) = checked.set(value)
|
||||||
|
|
||||||
|
// ========== 5.5 寸手持端展示辅助字段(仅用于手机版布局,不参与序列化) ==========
|
||||||
|
|
||||||
|
/** 是否已移库(moveState:0-未移交,1-已移交) */
|
||||||
|
val isMoved: Boolean
|
||||||
|
get() = moveState == 1
|
||||||
|
|
||||||
|
/** 品名:优先中文,为空回退英文 */
|
||||||
|
val goodsName: String
|
||||||
|
get() = goodsCn.ifEmpty { goods }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 详情页字段统一空值占位。
|
||||||
|
* 接口对 businessType / opdate / opId 等字段常返回 null,
|
||||||
|
* 直接绑会显示成 "null" 或空白,这里统一成 "-"。
|
||||||
|
*/
|
||||||
|
fun orDash(value: String?): String = if (value.isNullOrEmpty()) "-" else value
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,4 +108,19 @@ class GjcUldUseBean : Serializable {
|
|||||||
// 复磅状态文本
|
// 复磅状态文本
|
||||||
val wtStatusText: String
|
val wtStatusText: String
|
||||||
get() = if (wtDate.isNotEmpty()) "已复磅" else "未复磅"
|
get() = if (wtDate.isNotEmpty()) "已复磅" else "未复磅"
|
||||||
|
|
||||||
|
// ========== 5.5 寸手持端展示辅助字段(仅用于手机版布局,不参与序列化) ==========
|
||||||
|
|
||||||
|
/** 是否已交接:有交接时间即视为已交接 */
|
||||||
|
val isHandovered: Boolean
|
||||||
|
get() = hoDate.isNotEmpty()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IMP 代码是否属于危险品类 —— 决定手机版卡片上 IMP 代码标签是红底还是绿底。
|
||||||
|
*
|
||||||
|
* 依据 IATA IMP 特货代码惯例:以 R 开头(RFL/RRY/REX 等)及 ICE 归为危险品。
|
||||||
|
* 若后端另有判定口径,只需改这一处。
|
||||||
|
*/
|
||||||
|
val isDgrDangerous: Boolean
|
||||||
|
get() = dgrCode.startsWith("R", ignoreCase = true) || dgrCode.equals("ICE", ignoreCase = true)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
package com.lukouguoji.module_base.ui.weight.phone
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Parcelable
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.util.SparseArray
|
||||||
|
import android.view.Gravity
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import com.lukouguoji.module_base.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机版底部操作条(5.5 寸手持端公共组件)
|
||||||
|
*
|
||||||
|
* 结构:全选(圆形勾选框 + 文字)+ 已选统计 + 主操作按钮。
|
||||||
|
* 对应设计稿各多选列表页底部的白色操作条。
|
||||||
|
*
|
||||||
|
* XML 用法:
|
||||||
|
* ```xml
|
||||||
|
* <com.lukouguoji.module_base.ui.weight.phone.PhoneBottomBar
|
||||||
|
* android:layout_width="match_parent"
|
||||||
|
* android:layout_height="wrap_content"
|
||||||
|
* allChecked="@{viewModel.isAllChecked}"
|
||||||
|
* countText='@{"已选 " + viewModel.selectedCount + " 项"}'
|
||||||
|
* actionText="@{`交接`}"
|
||||||
|
* setOnAllCheckClick="@{(v)-> viewModel.checkAllClick()}"
|
||||||
|
* setOnActionClick="@{(v)-> viewModel.completeHandover()}" />
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
class PhoneBottomBar @JvmOverloads constructor(
|
||||||
|
context: Context,
|
||||||
|
attrs: AttributeSet? = null,
|
||||||
|
defStyleAttr: Int = 0
|
||||||
|
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
|
val llCheckAll: LinearLayout
|
||||||
|
val ivCheckAll: ImageView
|
||||||
|
val tvCount: TextView
|
||||||
|
val tvAction: TextView
|
||||||
|
|
||||||
|
/** 全选状态(驱动勾选框图标切换) */
|
||||||
|
var allChecked: Boolean = false
|
||||||
|
set(v) {
|
||||||
|
field = v
|
||||||
|
ivCheckAll.setImageResource(
|
||||||
|
if (v) R.drawable.ic_phone_check_round_checked
|
||||||
|
else R.drawable.ic_phone_check_round_unchecked
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 已选统计文案,如「已选 3 项」 */
|
||||||
|
var countText: String = ""
|
||||||
|
set(v) {
|
||||||
|
field = v
|
||||||
|
tvCount.text = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 主按钮文字 */
|
||||||
|
var actionText: String = ""
|
||||||
|
set(v) {
|
||||||
|
field = v
|
||||||
|
tvAction.text = v
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
orientation = HORIZONTAL
|
||||||
|
gravity = Gravity.CENTER_VERTICAL
|
||||||
|
setBackgroundColor(ContextCompat.getColor(context, R.color.white))
|
||||||
|
elevation = 8 * resources.displayMetrics.density
|
||||||
|
val padH = (16 * resources.displayMetrics.density).toInt()
|
||||||
|
val padV = (14 * resources.displayMetrics.density).toInt()
|
||||||
|
setPadding(padH, padV, padH, padV)
|
||||||
|
|
||||||
|
inflate(context, R.layout.layout_phone_bottom_bar, this)
|
||||||
|
|
||||||
|
llCheckAll = findViewById(R.id.ll_check_all)
|
||||||
|
ivCheckAll = findViewById(R.id.iv_check_all)
|
||||||
|
tvCount = findViewById(R.id.tv_count)
|
||||||
|
tvAction = findViewById(R.id.tv_action)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 只保存/恢复自身状态,避免内部子控件 id 与其他复合组件实例串档 */
|
||||||
|
override fun dispatchSaveInstanceState(container: SparseArray<Parcelable>) {
|
||||||
|
dispatchFreezeSelfOnly(container)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispatchRestoreInstanceState(container: SparseArray<Parcelable>) {
|
||||||
|
dispatchThawSelfOnly(container)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,238 @@
|
|||||||
|
package com.lukouguoji.module_base.ui.weight.phone
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Parcelable
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.util.SparseArray
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.EditText
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.Spinner
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.core.widget.doOnTextChanged
|
||||||
|
import androidx.databinding.InverseBindingListener
|
||||||
|
import com.lukouguoji.module_base.R
|
||||||
|
import com.lukouguoji.module_base.adapter.bindAdapter
|
||||||
|
import com.lukouguoji.module_base.adapter.bindOnSelected
|
||||||
|
import com.lukouguoji.module_base.interfaces.IOnSpinnerSelected
|
||||||
|
import com.lukouguoji.module_base.ktx.formatDate
|
||||||
|
import com.lukouguoji.module_base.ktx.getActivity
|
||||||
|
import com.lukouguoji.module_base.util.Common
|
||||||
|
import dev.utils.app.info.KeyValue
|
||||||
|
import java.util.Calendar
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机版表单 / 筛选项(5.5 寸手持端公共组件)
|
||||||
|
*
|
||||||
|
* 结构:上方标题(14sp #374151)+ 下方 40dp 高控件框(白底 + 1px 边框 + 8dp 圆角)。
|
||||||
|
* 支持三种形态,由 [type] 决定:
|
||||||
|
*
|
||||||
|
* | type | 控件 | 右侧图标 |
|
||||||
|
* |-----------|-----------|----------|
|
||||||
|
* | `INPUT` | EditText | 无 |
|
||||||
|
* | `DATE` | TextView(点击弹日历)| 日历 |
|
||||||
|
* | `SPINNER` | Spinner | 下箭头 |
|
||||||
|
*
|
||||||
|
* XML 用法:
|
||||||
|
* ```xml
|
||||||
|
* <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}" />
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* 手机端专用,与平板端 PadDataLayoutNew 并列存在,互不影响。
|
||||||
|
*/
|
||||||
|
class PhoneDataLayout @JvmOverloads constructor(
|
||||||
|
context: Context,
|
||||||
|
attrs: AttributeSet? = null,
|
||||||
|
defStyleAttr: Int = 0
|
||||||
|
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
|
val tvTitle: TextView
|
||||||
|
val tvMust: TextView
|
||||||
|
val llContent: LinearLayout
|
||||||
|
val et: EditText
|
||||||
|
val tv: TextView
|
||||||
|
val spinner: Spinner
|
||||||
|
val iv: ImageView
|
||||||
|
|
||||||
|
/** 双向绑定回调 */
|
||||||
|
var onChangeListener: InverseBindingListener? = null
|
||||||
|
|
||||||
|
/** 输入完成 / 选择完成回调 */
|
||||||
|
var refreshCallBack: (() -> Unit)? = null
|
||||||
|
|
||||||
|
var type: PhoneDataLayoutType = PhoneDataLayoutType.INPUT
|
||||||
|
set(v) {
|
||||||
|
field = v
|
||||||
|
applyType()
|
||||||
|
applyValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
var title: String = ""
|
||||||
|
set(v) {
|
||||||
|
field = v
|
||||||
|
tvTitle.text = v
|
||||||
|
}
|
||||||
|
|
||||||
|
var hint: String = ""
|
||||||
|
set(v) {
|
||||||
|
field = v
|
||||||
|
et.hint = v
|
||||||
|
tv.hint = v
|
||||||
|
bindAdapter(spinner, list, v, R.layout.item_spinner_list_14sp)
|
||||||
|
}
|
||||||
|
|
||||||
|
var value: String = ""
|
||||||
|
set(v) {
|
||||||
|
if (field == v) return
|
||||||
|
field = v
|
||||||
|
applyValue()
|
||||||
|
onChangeListener?.onChange()
|
||||||
|
}
|
||||||
|
|
||||||
|
var list: List<KeyValue> = emptyList()
|
||||||
|
set(v) {
|
||||||
|
field = v
|
||||||
|
bindAdapter(spinner, v, hint, R.layout.item_spinner_list_14sp)
|
||||||
|
applyValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
var required: Boolean = false
|
||||||
|
set(v) {
|
||||||
|
field = v
|
||||||
|
tvMust.visibility = if (v) VISIBLE else GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
var enable: Boolean = true
|
||||||
|
set(v) {
|
||||||
|
field = v
|
||||||
|
llContent.isEnabled = v
|
||||||
|
et.isEnabled = v
|
||||||
|
spinner.isEnabled = v
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
orientation = VERTICAL
|
||||||
|
inflate(context, R.layout.layout_phone_data_layout, this)
|
||||||
|
|
||||||
|
tvTitle = findViewById(R.id.tv_title)
|
||||||
|
tvMust = findViewById(R.id.tv_must)
|
||||||
|
llContent = findViewById(R.id.ll_content)
|
||||||
|
et = findViewById(R.id.et)
|
||||||
|
tv = findViewById(R.id.tv)
|
||||||
|
spinner = findViewById(R.id.spinner)
|
||||||
|
iv = findViewById(R.id.iv)
|
||||||
|
|
||||||
|
et.doOnTextChanged { text, _, _, _ ->
|
||||||
|
// 仅 INPUT 形态才回写,避免隐藏的 EditText 被系统状态恢复时误清空值
|
||||||
|
if (type == PhoneDataLayoutType.INPUT) {
|
||||||
|
value = text.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bindOnSelected(spinner, object : IOnSpinnerSelected {
|
||||||
|
override fun onSelected(position: Int) {
|
||||||
|
value = list.getOrNull(position)?.value ?: ""
|
||||||
|
refreshCallBack?.invoke()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
applyType()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val dateClick: (v: View) -> Unit = {
|
||||||
|
if (enable) {
|
||||||
|
Common.onYearMonthDay(context.getActivity(), value) { year, month, day ->
|
||||||
|
val calendar = Calendar.getInstance()
|
||||||
|
calendar.set(year, month - 1, day)
|
||||||
|
value = calendar.time.formatDate()
|
||||||
|
refreshCallBack?.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun applyType() {
|
||||||
|
when (type) {
|
||||||
|
PhoneDataLayoutType.INPUT -> {
|
||||||
|
et.visibility = VISIBLE
|
||||||
|
tv.visibility = GONE
|
||||||
|
spinner.visibility = GONE
|
||||||
|
iv.visibility = GONE
|
||||||
|
llContent.setOnClickListener(null)
|
||||||
|
llContent.isClickable = false
|
||||||
|
}
|
||||||
|
|
||||||
|
PhoneDataLayoutType.DATE -> {
|
||||||
|
et.visibility = GONE
|
||||||
|
tv.visibility = VISIBLE
|
||||||
|
spinner.visibility = GONE
|
||||||
|
iv.visibility = VISIBLE
|
||||||
|
iv.setImageResource(R.drawable.ic_phone_calendar)
|
||||||
|
llContent.setOnClickListener(dateClick)
|
||||||
|
}
|
||||||
|
|
||||||
|
PhoneDataLayoutType.SPINNER -> {
|
||||||
|
et.visibility = GONE
|
||||||
|
tv.visibility = GONE
|
||||||
|
spinner.visibility = VISIBLE
|
||||||
|
iv.visibility = VISIBLE
|
||||||
|
iv.setImageResource(R.drawable.ic_phone_chevron_down)
|
||||||
|
llContent.setOnClickListener(null)
|
||||||
|
llContent.isClickable = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun applyValue() {
|
||||||
|
when (type) {
|
||||||
|
PhoneDataLayoutType.INPUT -> {
|
||||||
|
if (et.text.toString() != value) et.setText(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
PhoneDataLayoutType.DATE -> {
|
||||||
|
tv.text = value
|
||||||
|
}
|
||||||
|
|
||||||
|
PhoneDataLayoutType.SPINNER -> {
|
||||||
|
if (value.isNotEmpty()) {
|
||||||
|
val position = list.indexOfFirst { it.value == value }
|
||||||
|
if (position >= 0) spinner.setSelection(position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同一页面往往放置多个本组件实例,而它们的内部子控件(et / tv / spinner)共用同一套 id。
|
||||||
|
* 系统按 id 保存/恢复视图状态会发生跨实例串档(典型表现:日期项被邻近输入框的空文本覆盖)。
|
||||||
|
* 这里只保存/恢复自身状态、不下发给子控件;控件取值本就由 ViewModel + DataBinding 持有,无需视图级恢复。
|
||||||
|
*/
|
||||||
|
override fun dispatchSaveInstanceState(container: SparseArray<Parcelable>) {
|
||||||
|
dispatchFreezeSelfOnly(container)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispatchRestoreInstanceState(container: SparseArray<Parcelable>) {
|
||||||
|
dispatchThawSelfOnly(container)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置为空值(筛选弹层「重置」按钮使用) */
|
||||||
|
fun reset() {
|
||||||
|
value = ""
|
||||||
|
if (type == PhoneDataLayoutType.SPINNER && list.isNotEmpty()) {
|
||||||
|
spinner.setSelection(if (hint.isEmpty()) list.size - 1 else list.size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** [PhoneDataLayout] 支持的控件形态 */
|
||||||
|
enum class PhoneDataLayoutType {
|
||||||
|
INPUT, // 文本输入
|
||||||
|
DATE, // 日期选择
|
||||||
|
SPINNER, // 下拉选择
|
||||||
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
package com.lukouguoji.module_base.ui.weight.phone
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import com.lukouguoji.module_base.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机版底部筛选弹层(5.5 寸手持端公共组件)
|
||||||
|
*
|
||||||
|
* 半透明遮罩 + 底部白色面板(顶部 20dp 圆角),面板内含标题行、内容插槽、重置/确认按钮行。
|
||||||
|
* 对应设计稿各列表页的「筛选条件」弹层。
|
||||||
|
*
|
||||||
|
* **内容插槽**:直接把筛选项(一般是 [PhoneDataLayout])写在本组件标签内即可,
|
||||||
|
* [onFinishInflate] 会自动把它们移入面板中部,无需关心内部层级:
|
||||||
|
*
|
||||||
|
* ```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 ... />
|
||||||
|
* <com.lukouguoji.module_base.ui.weight.phone.PhoneDataLayout ... />
|
||||||
|
*
|
||||||
|
* </com.lukouguoji.module_base.ui.weight.phone.PhoneFilterPanel>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* 相邻筛选项之间的 20dp 间距由本组件统一施加,使用方无需逐个写 marginTop。
|
||||||
|
*/
|
||||||
|
class PhoneFilterPanel @JvmOverloads constructor(
|
||||||
|
context: Context,
|
||||||
|
attrs: AttributeSet? = null,
|
||||||
|
defStyleAttr: Int = 0
|
||||||
|
) : FrameLayout(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
|
val llPanel: LinearLayout
|
||||||
|
val llContent: LinearLayout
|
||||||
|
val tvTitle: TextView
|
||||||
|
val ivClose: ImageView
|
||||||
|
val tvReset: TextView
|
||||||
|
val tvConfirm: TextView
|
||||||
|
|
||||||
|
/** 遮罩点击 / 关闭图标点击回调 */
|
||||||
|
private var dismissListener: OnClickListener? = null
|
||||||
|
|
||||||
|
var title: String = ""
|
||||||
|
set(v) {
|
||||||
|
field = v
|
||||||
|
if (v.isNotEmpty()) tvTitle.text = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 弹层显隐 */
|
||||||
|
var panelVisible: Boolean = false
|
||||||
|
set(v) {
|
||||||
|
field = v
|
||||||
|
visibility = if (v) VISIBLE else GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
setBackgroundColor(ContextCompat.getColor(context, R.color.black_tran50))
|
||||||
|
visibility = GONE
|
||||||
|
|
||||||
|
inflate(context, R.layout.layout_phone_filter_panel, this)
|
||||||
|
|
||||||
|
llPanel = findViewById(R.id.ll_panel)
|
||||||
|
llContent = findViewById(R.id.ll_content)
|
||||||
|
tvTitle = findViewById(R.id.tv_title)
|
||||||
|
ivClose = findViewById(R.id.iv_close)
|
||||||
|
tvReset = findViewById(R.id.tv_reset)
|
||||||
|
tvConfirm = findViewById(R.id.tv_confirm)
|
||||||
|
|
||||||
|
// 遮罩点击关闭;面板自身已 clickable,不会穿透
|
||||||
|
setOnClickListener { dismissListener?.onClick(this) }
|
||||||
|
ivClose.setOnClickListener { dismissListener?.onClick(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把 XML 中声明在本组件内的子 View 移入面板内容区,并统一施加 20dp 项间距。
|
||||||
|
*/
|
||||||
|
override fun onFinishInflate() {
|
||||||
|
super.onFinishInflate()
|
||||||
|
|
||||||
|
// index 0 是内部面板(init 中 inflate 得到),其后才是使用方声明的子 View
|
||||||
|
val declared = mutableListOf<View>()
|
||||||
|
for (i in childCount - 1 downTo 1) {
|
||||||
|
declared.add(0, getChildAt(i))
|
||||||
|
removeViewAt(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
declared.forEachIndexed { index, child ->
|
||||||
|
llContent.addView(child)
|
||||||
|
if (index > 0) {
|
||||||
|
(child.layoutParams as? LinearLayout.LayoutParams)?.let { lp ->
|
||||||
|
lp.topMargin = (20 * resources.displayMetrics.density).toInt()
|
||||||
|
child.layoutParams = lp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setOnDismiss(listener: OnClickListener?) {
|
||||||
|
dismissListener = listener
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 遍历内容区所有 [PhoneDataLayout] 并重置为空值 */
|
||||||
|
fun resetAllFields() {
|
||||||
|
for (i in 0 until llContent.childCount) {
|
||||||
|
(llContent.getChildAt(i) as? PhoneDataLayout)?.reset()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
package com.lukouguoji.module_base.ui.weight.phone
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.Gravity
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import com.lukouguoji.module_base.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机版详情页字段项(5.5 寸手持端公共组件)
|
||||||
|
*
|
||||||
|
* 竖排「小号灰标签(12sp)+ 数值(15sp)」,用于详情页两列信息网格。
|
||||||
|
* 对应设计稿「板箱详情」等详情卡片内的字段。
|
||||||
|
*
|
||||||
|
* XML 用法:
|
||||||
|
* ```xml
|
||||||
|
* <com.lukouguoji.module_base.ui.weight.phone.PhoneKvItem
|
||||||
|
* android:layout_width="0dp"
|
||||||
|
* android:layout_height="wrap_content"
|
||||||
|
* android:layout_weight="1"
|
||||||
|
* title="@{`装机重`}"
|
||||||
|
* value="@{bean.netWeight}" />
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* 需要突出的字段(如库位)设 `tag="@{true}"`,数值会渲染为橙色高亮标签。
|
||||||
|
*/
|
||||||
|
class PhoneKvItem @JvmOverloads constructor(
|
||||||
|
context: Context,
|
||||||
|
attrs: AttributeSet? = null,
|
||||||
|
defStyleAttr: Int = 0
|
||||||
|
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
|
val tvTitle: TextView
|
||||||
|
val tvValue: TextView
|
||||||
|
|
||||||
|
var title: String = ""
|
||||||
|
set(v) {
|
||||||
|
field = v
|
||||||
|
tvTitle.text = v
|
||||||
|
}
|
||||||
|
|
||||||
|
var value: String = ""
|
||||||
|
set(v) {
|
||||||
|
field = v
|
||||||
|
// 详情页空值统一显示为 "-",与设计稿一致
|
||||||
|
tvValue.text = v.ifEmpty { "-" }
|
||||||
|
applyStyle()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 是否以橙色高亮标签样式展示数值 */
|
||||||
|
var tag: Boolean = false
|
||||||
|
set(v) {
|
||||||
|
field = v
|
||||||
|
applyStyle()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 空值不套高亮标签底 —— 否则占位符 "-" 会显示成一个孤零零的橙色小方块。
|
||||||
|
*/
|
||||||
|
private fun applyStyle() {
|
||||||
|
if (tag && value.isNotEmpty()) {
|
||||||
|
tvValue.setBackgroundResource(R.drawable.bg_phone_value_orange)
|
||||||
|
tvValue.setTextColor(ContextCompat.getColor(context, R.color.phone_orange_text))
|
||||||
|
tvValue.setTypeface(tvValue.typeface, android.graphics.Typeface.BOLD)
|
||||||
|
val padH = (4 * resources.displayMetrics.density).toInt()
|
||||||
|
tvValue.setPadding(padH, 0, padH, 0)
|
||||||
|
} else {
|
||||||
|
tvValue.background = null
|
||||||
|
tvValue.setTextColor(ContextCompat.getColor(context, R.color.phone_text_title))
|
||||||
|
tvValue.setPadding(0, 0, 0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
orientation = VERTICAL
|
||||||
|
|
||||||
|
tvTitle = TextView(context).apply {
|
||||||
|
textSize = 12f
|
||||||
|
setTextColor(ContextCompat.getColor(context, R.color.phone_text_hint))
|
||||||
|
}
|
||||||
|
addView(
|
||||||
|
tvTitle,
|
||||||
|
LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
|
||||||
|
)
|
||||||
|
|
||||||
|
tvValue = TextView(context).apply {
|
||||||
|
textSize = 15f
|
||||||
|
setTextColor(ContextCompat.getColor(context, R.color.phone_text_title))
|
||||||
|
}
|
||||||
|
addView(
|
||||||
|
tvValue,
|
||||||
|
LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT).apply {
|
||||||
|
topMargin = (2 * resources.displayMetrics.density).toInt()
|
||||||
|
gravity = Gravity.START
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
package com.lukouguoji.module_base.ui.weight.phone
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Parcelable
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.util.SparseArray
|
||||||
|
import android.view.View
|
||||||
|
import android.view.inputmethod.EditorInfo
|
||||||
|
import android.widget.EditText
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import androidx.core.widget.doOnTextChanged
|
||||||
|
import androidx.databinding.InverseBindingListener
|
||||||
|
import com.lukouguoji.module_base.R
|
||||||
|
import com.lukouguoji.module_base.ktx.setUpperCaseAlphanumericFilter
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机版搜索栏(5.5 寸手持端公共组件)
|
||||||
|
*
|
||||||
|
* 结构:圆角搜索框(放大镜 + 输入框 + 扫码图标)+ 右侧圆形筛选按钮。
|
||||||
|
* 对应设计稿「5.5寸手持端设计文件」各列表页顶部搜索区。
|
||||||
|
*
|
||||||
|
* XML 用法:
|
||||||
|
* ```xml
|
||||||
|
* <com.lukouguoji.module_base.ui.weight.phone.PhoneSearchBar
|
||||||
|
* android:layout_width="match_parent"
|
||||||
|
* android:layout_height="wrap_content"
|
||||||
|
* hint="@{`搜索ULD编号`}"
|
||||||
|
* value="@={viewModel.uldNo}"
|
||||||
|
* upperCase="@{true}"
|
||||||
|
* setOnScanClickListener="@{(v)-> viewModel.scanUld()}"
|
||||||
|
* setOnFilterClickListener="@{(v)-> activity.toggleFilterPanel()}"
|
||||||
|
* setOnSearchListener="@{()-> viewModel.searchClick()}" />
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* 说明:与平板端 [com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout] 并列,
|
||||||
|
* 二者互不影响;手机布局用本组件,平板布局继续用 PadSearchLayout。
|
||||||
|
*/
|
||||||
|
class PhoneSearchBar @JvmOverloads constructor(
|
||||||
|
context: Context,
|
||||||
|
attrs: AttributeSet? = null,
|
||||||
|
defStyleAttr: Int = 0
|
||||||
|
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
|
val llSearch: LinearLayout
|
||||||
|
val ivSearch: ImageView
|
||||||
|
val et: EditText
|
||||||
|
val ivScan: ImageView
|
||||||
|
val ivFilter: ImageView
|
||||||
|
|
||||||
|
/** 双向绑定回调 */
|
||||||
|
var onChangeListener: InverseBindingListener? = null
|
||||||
|
|
||||||
|
/** 键盘「搜索」键 / 扫码完成后触发的查询回调 */
|
||||||
|
var searchCallBack: (() -> Unit)? = null
|
||||||
|
|
||||||
|
var value: String = ""
|
||||||
|
set(v) {
|
||||||
|
if (field == v) return
|
||||||
|
field = v
|
||||||
|
if (et.text.toString() != v) et.setText(v)
|
||||||
|
onChangeListener?.onChange()
|
||||||
|
}
|
||||||
|
|
||||||
|
var hint: String = ""
|
||||||
|
set(v) {
|
||||||
|
field = v
|
||||||
|
et.hint = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 是否显示扫码图标(默认显示) */
|
||||||
|
var showScan: Boolean = true
|
||||||
|
set(v) {
|
||||||
|
field = v
|
||||||
|
ivScan.visibility = if (v) VISIBLE else GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 是否显示右侧筛选按钮(默认显示) */
|
||||||
|
var showFilter: Boolean = true
|
||||||
|
set(v) {
|
||||||
|
field = v
|
||||||
|
ivFilter.visibility = if (v) VISIBLE else GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 输入内容强制大写字母数字(运单号 / ULD 编号等场景) */
|
||||||
|
var upperCase: Boolean = false
|
||||||
|
set(v) {
|
||||||
|
field = v
|
||||||
|
if (v) et.setUpperCaseAlphanumericFilter()
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
orientation = HORIZONTAL
|
||||||
|
gravity = android.view.Gravity.CENTER_VERTICAL
|
||||||
|
inflate(context, R.layout.layout_phone_search_bar, this)
|
||||||
|
|
||||||
|
llSearch = findViewById(R.id.ll_search)
|
||||||
|
ivSearch = findViewById(R.id.iv_search)
|
||||||
|
et = findViewById(R.id.et)
|
||||||
|
ivScan = findViewById(R.id.iv_scan)
|
||||||
|
ivFilter = findViewById(R.id.iv_filter)
|
||||||
|
|
||||||
|
et.doOnTextChanged { text, _, _, _ ->
|
||||||
|
value = text.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 软键盘「搜索」键触发查询
|
||||||
|
et.setOnEditorActionListener { _, actionId, _ ->
|
||||||
|
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
|
||||||
|
searchCallBack?.invoke()
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 只保存/恢复自身状态,不下发给内部子控件。
|
||||||
|
* 内部 et / iv_* 的 id 在每个实例中相同,交由系统按 id 恢复会跨实例串档;
|
||||||
|
* 取值本就由 ViewModel + DataBinding 持有,无需视图级恢复。
|
||||||
|
*/
|
||||||
|
override fun dispatchSaveInstanceState(container: SparseArray<Parcelable>) {
|
||||||
|
dispatchFreezeSelfOnly(container)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispatchRestoreInstanceState(container: SparseArray<Parcelable>) {
|
||||||
|
dispatchThawSelfOnly(container)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 供外部(如扫码回调)复用的图标点击入口 */
|
||||||
|
fun setOnScanClick(listener: View.OnClickListener?) {
|
||||||
|
ivScan.setOnClickListener(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setOnFilterClick(listener: View.OnClickListener?) {
|
||||||
|
ivFilter.setOnClickListener(listener)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
package com.lukouguoji.module_base.ui.weight.phone
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Parcelable
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.util.SparseArray
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.TextView
|
||||||
|
import com.lukouguoji.module_base.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机版卡片统计框(5.5 寸手持端公共组件)
|
||||||
|
*
|
||||||
|
* 浅灰底 + 8dp 圆角,横向等宽 2~4 列,每列为「小号灰标签 + 加粗数值」,列间带竖分隔线。
|
||||||
|
* 对应设计稿列表卡片中部的统计区(如「架子车号 / 目的港 / 装机重」)。
|
||||||
|
*
|
||||||
|
* XML 用法(列数由是否传 label 决定,未传的列自动隐藏):
|
||||||
|
* ```xml
|
||||||
|
* <com.lukouguoji.module_base.ui.weight.phone.PhoneStatBox
|
||||||
|
* android:layout_width="match_parent"
|
||||||
|
* android:layout_height="wrap_content"
|
||||||
|
* label1="@{`架子车号`}" value1="@{bean.carId}"
|
||||||
|
* label2="@{`目的港`}" value2="@{bean.fdest}"
|
||||||
|
* label3="@{`装机重`}" value3='@{bean.netWeight + "kg"}' />
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
class PhoneStatBox @JvmOverloads constructor(
|
||||||
|
context: Context,
|
||||||
|
attrs: AttributeSet? = null,
|
||||||
|
defStyleAttr: Int = 0
|
||||||
|
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
|
private val columns: List<LinearLayout>
|
||||||
|
private val labels: List<TextView>
|
||||||
|
private val values: List<TextView>
|
||||||
|
|
||||||
|
/** 分隔线(下标 0 对应第 2 列左侧,依次类推) */
|
||||||
|
private val dividers: List<View>
|
||||||
|
|
||||||
|
init {
|
||||||
|
orientation = HORIZONTAL
|
||||||
|
setBackgroundResource(R.drawable.bg_phone_stat_box)
|
||||||
|
val pad = (12 * resources.displayMetrics.density).toInt()
|
||||||
|
setPadding(pad, pad, pad, pad)
|
||||||
|
|
||||||
|
inflate(context, R.layout.layout_phone_stat_box, this)
|
||||||
|
|
||||||
|
columns = listOf(
|
||||||
|
findViewById(R.id.ll_col1),
|
||||||
|
findViewById(R.id.ll_col2),
|
||||||
|
findViewById(R.id.ll_col3),
|
||||||
|
findViewById(R.id.ll_col4)
|
||||||
|
)
|
||||||
|
labels = listOf(
|
||||||
|
findViewById(R.id.tv_label1),
|
||||||
|
findViewById(R.id.tv_label2),
|
||||||
|
findViewById(R.id.tv_label3),
|
||||||
|
findViewById(R.id.tv_label4)
|
||||||
|
)
|
||||||
|
values = listOf(
|
||||||
|
findViewById(R.id.tv_value1),
|
||||||
|
findViewById(R.id.tv_value2),
|
||||||
|
findViewById(R.id.tv_value3),
|
||||||
|
findViewById(R.id.tv_value4)
|
||||||
|
)
|
||||||
|
dividers = listOf(
|
||||||
|
findViewById(R.id.divider2),
|
||||||
|
findViewById(R.id.divider3),
|
||||||
|
findViewById(R.id.divider4)
|
||||||
|
)
|
||||||
|
|
||||||
|
// 默认只展示第 1 列,其余待 label 赋值后再显示
|
||||||
|
for (i in 1..3) setColumnVisible(i, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 只保存/恢复自身状态。列表中每个卡片都含一个本组件,内部子控件 id 相同,
|
||||||
|
* 交由系统按 id 恢复会跨实例串档。
|
||||||
|
*/
|
||||||
|
override fun dispatchSaveInstanceState(container: SparseArray<Parcelable>) {
|
||||||
|
dispatchFreezeSelfOnly(container)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispatchRestoreInstanceState(container: SparseArray<Parcelable>) {
|
||||||
|
dispatchThawSelfOnly(container)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 设置第 [index] 列(0 起)的标签,传空则隐藏该列 */
|
||||||
|
fun setLabel(index: Int, text: String?) {
|
||||||
|
if (index !in labels.indices) return
|
||||||
|
labels[index].text = text.orEmpty()
|
||||||
|
setColumnVisible(index, !text.isNullOrEmpty())
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 设置第 [index] 列(0 起)的数值 */
|
||||||
|
fun setValue(index: Int, text: String?) {
|
||||||
|
if (index !in values.indices) return
|
||||||
|
values[index].text = text.orEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setColumnVisible(index: Int, visible: Boolean) {
|
||||||
|
val flag = if (visible) VISIBLE else GONE
|
||||||
|
columns[index].visibility = flag
|
||||||
|
// 第 2~4 列连带其左侧分隔线一起显隐
|
||||||
|
if (index in 1..3) dividers[index - 1].visibility = flag
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
package com.lukouguoji.module_base.ui.weight.phone
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.Gravity
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.databinding.InverseBindingListener
|
||||||
|
import com.lukouguoji.module_base.R
|
||||||
|
import dev.utils.app.info.KeyValue
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机版状态 Tab 条(5.5 寸手持端公共组件)
|
||||||
|
*
|
||||||
|
* 每个 Tab = 文字 + 可选角标数字,选中态为「深色加粗文字 + 底部 2dp 全宽指示条」。
|
||||||
|
* 对应设计稿各列表页的「待交接 / 已交接」「全部 / 待移库 / 已移库」等状态切换栏。
|
||||||
|
*
|
||||||
|
* XML 用法:
|
||||||
|
* ```xml
|
||||||
|
* <com.lukouguoji.module_base.ui.weight.phone.PhoneStatusTab
|
||||||
|
* android:layout_width="match_parent"
|
||||||
|
* android:layout_height="wrap_content"
|
||||||
|
* tabs="@{viewModel.handoverStateTabs}"
|
||||||
|
* counts="@{viewModel.handoverStateCounts}"
|
||||||
|
* value="@={viewModel.handoverState}"
|
||||||
|
* setOnTabChanged="@{()-> activity.onTabChanged()}" />
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* [tabs] 用 [KeyValue]:`key` 为显示文字,`value` 为写回 [value] 的业务值。
|
||||||
|
* [counts] 为与 tabs 等长的角标文案列表,传 null 或空串则该 Tab 不显示角标。
|
||||||
|
*/
|
||||||
|
class PhoneStatusTab @JvmOverloads constructor(
|
||||||
|
context: Context,
|
||||||
|
attrs: AttributeSet? = null,
|
||||||
|
defStyleAttr: Int = 0
|
||||||
|
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
|
/** 双向绑定回调 */
|
||||||
|
var onChangeListener: InverseBindingListener? = null
|
||||||
|
|
||||||
|
/** Tab 切换回调(用户点击引起的变化才触发,外部赋值不触发) */
|
||||||
|
var tabChangedCallBack: (() -> Unit)? = null
|
||||||
|
|
||||||
|
var tabs: List<KeyValue> = emptyList()
|
||||||
|
set(v) {
|
||||||
|
field = v
|
||||||
|
buildTabs()
|
||||||
|
}
|
||||||
|
|
||||||
|
var counts: List<String> = emptyList()
|
||||||
|
set(v) {
|
||||||
|
field = v
|
||||||
|
refreshState()
|
||||||
|
}
|
||||||
|
|
||||||
|
var value: String = ""
|
||||||
|
set(v) {
|
||||||
|
if (field == v) return
|
||||||
|
field = v
|
||||||
|
refreshState()
|
||||||
|
onChangeListener?.onChange()
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
orientation = HORIZONTAL
|
||||||
|
setBackgroundColor(ContextCompat.getColor(context, R.color.white))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildTabs() {
|
||||||
|
removeAllViews()
|
||||||
|
tabs.forEachIndexed { index, tab ->
|
||||||
|
addView(createTab(tab, index))
|
||||||
|
}
|
||||||
|
refreshState()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createTab(tab: KeyValue, index: Int): View {
|
||||||
|
val column = LinearLayout(context).apply {
|
||||||
|
orientation = VERTICAL
|
||||||
|
layoutParams = LayoutParams(0, LayoutParams.WRAP_CONTENT, 1f)
|
||||||
|
setOnClickListener {
|
||||||
|
val target = tab.value ?: ""
|
||||||
|
if (value != target) {
|
||||||
|
value = target
|
||||||
|
tabChangedCallBack?.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文字 + 角标
|
||||||
|
val row = LinearLayout(context).apply {
|
||||||
|
orientation = HORIZONTAL
|
||||||
|
gravity = Gravity.CENTER
|
||||||
|
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, dp(42))
|
||||||
|
}
|
||||||
|
row.addView(TextView(context).apply {
|
||||||
|
id = titleIdOf(index)
|
||||||
|
text = tab.key
|
||||||
|
textSize = 14f
|
||||||
|
setTypeface(typeface, android.graphics.Typeface.BOLD)
|
||||||
|
})
|
||||||
|
row.addView(TextView(context).apply {
|
||||||
|
id = badgeIdOf(index)
|
||||||
|
textSize = 11f
|
||||||
|
gravity = Gravity.CENTER
|
||||||
|
setBackgroundResource(R.drawable.bg_phone_badge)
|
||||||
|
setTextColor(ContextCompat.getColor(context, R.color.phone_primary))
|
||||||
|
setPadding(dp(6), dp(1), dp(6), dp(1))
|
||||||
|
layoutParams = LayoutParams(
|
||||||
|
LayoutParams.WRAP_CONTENT,
|
||||||
|
LayoutParams.WRAP_CONTENT
|
||||||
|
).apply { marginStart = dp(6) }
|
||||||
|
})
|
||||||
|
column.addView(row)
|
||||||
|
|
||||||
|
// 底部指示条
|
||||||
|
column.addView(View(context).apply {
|
||||||
|
id = indicatorIdOf(index)
|
||||||
|
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, dp(2))
|
||||||
|
})
|
||||||
|
|
||||||
|
return column
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun refreshState() {
|
||||||
|
tabs.forEachIndexed { index, tab ->
|
||||||
|
val selected = (tab.value ?: "") == value
|
||||||
|
|
||||||
|
findViewById<TextView>(titleIdOf(index))?.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
context,
|
||||||
|
if (selected) R.color.phone_text_title else R.color.phone_text_body
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
findViewById<View>(indicatorIdOf(index))?.setBackgroundColor(
|
||||||
|
if (selected) ContextCompat.getColor(context, R.color.phone_text_title)
|
||||||
|
else android.graphics.Color.TRANSPARENT
|
||||||
|
)
|
||||||
|
|
||||||
|
findViewById<TextView>(badgeIdOf(index))?.apply {
|
||||||
|
val count = counts.getOrNull(index).orEmpty()
|
||||||
|
if (count.isEmpty()) {
|
||||||
|
visibility = GONE
|
||||||
|
} else {
|
||||||
|
visibility = VISIBLE
|
||||||
|
text = count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dp(value: Int): Int =
|
||||||
|
(value * resources.displayMetrics.density).toInt()
|
||||||
|
|
||||||
|
// 动态生成的子 View 用固定偏移量作为 id,避免与资源 id 冲突
|
||||||
|
private fun titleIdOf(index: Int) = ID_BASE_TITLE + index
|
||||||
|
private fun badgeIdOf(index: Int) = ID_BASE_BADGE + index
|
||||||
|
private fun indicatorIdOf(index: Int) = ID_BASE_INDICATOR + index
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val ID_BASE_TITLE = 0x7E100000
|
||||||
|
private const val ID_BASE_BADGE = 0x7E200000
|
||||||
|
private const val ID_BASE_INDICATOR = 0x7E300000
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,228 @@
|
|||||||
|
package com.lukouguoji.module_base.ui.weight.phone
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import androidx.databinding.BindingAdapter
|
||||||
|
import androidx.databinding.InverseBindingAdapter
|
||||||
|
import androidx.databinding.InverseBindingListener
|
||||||
|
import dev.utils.app.info.KeyValue
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 5.5 寸手持端公共组件的 DataBinding 适配器集合
|
||||||
|
*
|
||||||
|
* 所有属性均为无命名空间写法(与平板端 PadSearchLayout / PadDataLayoutNew 的用法一致)。
|
||||||
|
* 同名属性(hint / value / title / list 等)按控件类型解析,与平板端组件互不冲突。
|
||||||
|
*/
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// PhoneSearchBar
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@BindingAdapter("hint", "showScan", "showFilter", "upperCase", requireAll = false)
|
||||||
|
fun setPhoneSearchBarAttrs(
|
||||||
|
bar: PhoneSearchBar,
|
||||||
|
hint: String?,
|
||||||
|
showScan: Boolean?,
|
||||||
|
showFilter: Boolean?,
|
||||||
|
upperCase: Boolean?
|
||||||
|
) {
|
||||||
|
hint?.let { bar.hint = it }
|
||||||
|
showScan?.let { bar.showScan = it }
|
||||||
|
showFilter?.let { bar.showFilter = it }
|
||||||
|
upperCase?.let { bar.upperCase = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
@BindingAdapter("value", requireAll = false)
|
||||||
|
fun setPhoneSearchBarValue(bar: PhoneSearchBar, value: String?) {
|
||||||
|
value?.let { bar.value = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
@InverseBindingAdapter(attribute = "value", event = "valueAttrChanged")
|
||||||
|
fun getPhoneSearchBarValue(bar: PhoneSearchBar): String = bar.value
|
||||||
|
|
||||||
|
@BindingAdapter("valueAttrChanged", requireAll = false)
|
||||||
|
fun setPhoneSearchBarValueAttrChanged(bar: PhoneSearchBar, listener: InverseBindingListener) {
|
||||||
|
bar.onChangeListener = listener
|
||||||
|
}
|
||||||
|
|
||||||
|
@BindingAdapter("setOnScanClickListener", requireAll = false)
|
||||||
|
fun setPhoneSearchBarScanClick(bar: PhoneSearchBar, listener: View.OnClickListener?) {
|
||||||
|
bar.setOnScanClick(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
@BindingAdapter("setOnFilterClickListener", requireAll = false)
|
||||||
|
fun setPhoneSearchBarFilterClick(bar: PhoneSearchBar, listener: View.OnClickListener?) {
|
||||||
|
bar.setOnFilterClick(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
@BindingAdapter("setRefreshCallBack", requireAll = false)
|
||||||
|
fun setPhoneSearchBarRefreshCallBack(bar: PhoneSearchBar, callBack: (() -> Unit)?) {
|
||||||
|
bar.searchCallBack = callBack
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// PhoneStatusTab
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@BindingAdapter("tabs", requireAll = false)
|
||||||
|
fun setPhoneStatusTabTabs(tab: PhoneStatusTab, tabs: List<KeyValue>?) {
|
||||||
|
tabs?.let { tab.tabs = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
@BindingAdapter("counts", requireAll = false)
|
||||||
|
fun setPhoneStatusTabCounts(tab: PhoneStatusTab, counts: List<String>?) {
|
||||||
|
tab.counts = counts ?: emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
@BindingAdapter("value", requireAll = false)
|
||||||
|
fun setPhoneStatusTabValue(tab: PhoneStatusTab, value: String?) {
|
||||||
|
value?.let { tab.value = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
@InverseBindingAdapter(attribute = "value", event = "valueAttrChanged")
|
||||||
|
fun getPhoneStatusTabValue(tab: PhoneStatusTab): String = tab.value
|
||||||
|
|
||||||
|
@BindingAdapter("valueAttrChanged", requireAll = false)
|
||||||
|
fun setPhoneStatusTabValueAttrChanged(tab: PhoneStatusTab, listener: InverseBindingListener) {
|
||||||
|
tab.onChangeListener = listener
|
||||||
|
}
|
||||||
|
|
||||||
|
@BindingAdapter("setOnTabChanged", requireAll = false)
|
||||||
|
fun setPhoneStatusTabChanged(tab: PhoneStatusTab, callBack: (() -> Unit)?) {
|
||||||
|
tab.tabChangedCallBack = callBack
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// PhoneDataLayout
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@BindingAdapter("title", "hint", "type", "required", "enable", requireAll = false)
|
||||||
|
fun setPhoneDataLayoutAttrs(
|
||||||
|
layout: PhoneDataLayout,
|
||||||
|
title: String?,
|
||||||
|
hint: String?,
|
||||||
|
type: PhoneDataLayoutType?,
|
||||||
|
required: Boolean?,
|
||||||
|
enable: Boolean?
|
||||||
|
) {
|
||||||
|
// type 必须先于 value/hint 生效,否则控件形态与取值分支不匹配
|
||||||
|
type?.let { layout.type = it }
|
||||||
|
title?.let { layout.title = it }
|
||||||
|
hint?.let { layout.hint = it }
|
||||||
|
required?.let { layout.required = it }
|
||||||
|
enable?.let { layout.enable = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
@BindingAdapter("value", requireAll = false)
|
||||||
|
fun setPhoneDataLayoutValue(layout: PhoneDataLayout, value: String?) {
|
||||||
|
value?.let { layout.value = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
@InverseBindingAdapter(attribute = "value", event = "valueAttrChanged")
|
||||||
|
fun getPhoneDataLayoutValue(layout: PhoneDataLayout): String = layout.value
|
||||||
|
|
||||||
|
@BindingAdapter("valueAttrChanged", requireAll = false)
|
||||||
|
fun setPhoneDataLayoutValueAttrChanged(
|
||||||
|
layout: PhoneDataLayout,
|
||||||
|
listener: InverseBindingListener
|
||||||
|
) {
|
||||||
|
layout.onChangeListener = listener
|
||||||
|
}
|
||||||
|
|
||||||
|
@BindingAdapter("list", requireAll = false)
|
||||||
|
fun setPhoneDataLayoutList(layout: PhoneDataLayout, list: List<KeyValue>?) {
|
||||||
|
list?.let { layout.list = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
@BindingAdapter("setRefreshCallBack", requireAll = false)
|
||||||
|
fun setPhoneDataLayoutRefreshCallBack(layout: PhoneDataLayout, callBack: (() -> Unit)?) {
|
||||||
|
layout.refreshCallBack = callBack
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// PhoneFilterPanel
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@BindingAdapter("title", "panelVisible", requireAll = false)
|
||||||
|
fun setPhoneFilterPanelAttrs(panel: PhoneFilterPanel, title: String?, panelVisible: Boolean?) {
|
||||||
|
title?.let { panel.title = it }
|
||||||
|
panelVisible?.let { panel.panelVisible = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
@BindingAdapter("setOnResetClick", requireAll = false)
|
||||||
|
fun setPhoneFilterPanelResetClick(panel: PhoneFilterPanel, listener: View.OnClickListener?) {
|
||||||
|
panel.tvReset.setOnClickListener(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
@BindingAdapter("setOnConfirmClick", requireAll = false)
|
||||||
|
fun setPhoneFilterPanelConfirmClick(panel: PhoneFilterPanel, listener: View.OnClickListener?) {
|
||||||
|
panel.tvConfirm.setOnClickListener(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
@BindingAdapter("setOnDismissClick", requireAll = false)
|
||||||
|
fun setPhoneFilterPanelDismissClick(panel: PhoneFilterPanel, listener: View.OnClickListener?) {
|
||||||
|
panel.setOnDismiss(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// PhoneBottomBar
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@BindingAdapter("allChecked", "countText", "actionText", requireAll = false)
|
||||||
|
fun setPhoneBottomBarAttrs(
|
||||||
|
bar: PhoneBottomBar,
|
||||||
|
allChecked: Boolean?,
|
||||||
|
countText: String?,
|
||||||
|
actionText: String?
|
||||||
|
) {
|
||||||
|
allChecked?.let { bar.allChecked = it }
|
||||||
|
countText?.let { bar.countText = it }
|
||||||
|
actionText?.let { bar.actionText = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
@BindingAdapter("setOnAllCheckClick", requireAll = false)
|
||||||
|
fun setPhoneBottomBarAllCheckClick(bar: PhoneBottomBar, listener: View.OnClickListener?) {
|
||||||
|
bar.llCheckAll.setOnClickListener(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
@BindingAdapter("setOnActionClick", requireAll = false)
|
||||||
|
fun setPhoneBottomBarActionClick(bar: PhoneBottomBar, listener: View.OnClickListener?) {
|
||||||
|
bar.tvAction.setOnClickListener(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// PhoneStatBox
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@BindingAdapter(
|
||||||
|
"label1", "value1", "label2", "value2",
|
||||||
|
"label3", "value3", "label4", "value4",
|
||||||
|
requireAll = false
|
||||||
|
)
|
||||||
|
fun setPhoneStatBoxAttrs(
|
||||||
|
box: PhoneStatBox,
|
||||||
|
label1: String?, value1: String?,
|
||||||
|
label2: String?, value2: String?,
|
||||||
|
label3: String?, value3: String?,
|
||||||
|
label4: String?, value4: String?
|
||||||
|
) {
|
||||||
|
box.setLabel(0, label1)
|
||||||
|
box.setValue(0, value1)
|
||||||
|
box.setLabel(1, label2)
|
||||||
|
box.setValue(1, value2)
|
||||||
|
box.setLabel(2, label3)
|
||||||
|
box.setValue(2, value3)
|
||||||
|
box.setLabel(3, label4)
|
||||||
|
box.setValue(3, value4)
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// PhoneKvItem
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@BindingAdapter("title", "value", "tag", requireAll = false)
|
||||||
|
fun setPhoneKvItemAttrs(item: PhoneKvItem, title: String?, value: String?, tag: Boolean?) {
|
||||||
|
title?.let { item.title = it }
|
||||||
|
// tag 需先于 value 生效,确保样式切换后再填内容
|
||||||
|
tag?.let { item.tag = it }
|
||||||
|
item.value = value.orEmpty()
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
package com.lukouguoji.module_base.util
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.Resources
|
||||||
|
import androidx.annotation.LayoutRes
|
||||||
|
import com.lukouguoji.module_base.MyApplication
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备形态判定工具
|
||||||
|
*
|
||||||
|
* 用于「平板(10 寸横屏)」与「手机(5.5 寸竖屏)」双形态适配:
|
||||||
|
* 1. 识别当前设备是平板还是手机
|
||||||
|
* 2. 提供按形态选择布局的入口(Activity 布局 / RecyclerView item 布局通用)
|
||||||
|
* 3. 提供手机端 AutoSize 设计基准尺寸常量
|
||||||
|
*
|
||||||
|
* 判定依据:`smallestScreenWidthDp`(最小屏幕宽度,与横竖屏无关,是 Android 官方推荐的设备分类维度)
|
||||||
|
* - 5.5 寸手机 ≈ 360dp
|
||||||
|
* - 10 寸平板 ≈ 800dp
|
||||||
|
* - 分界线取官方标准 600dp
|
||||||
|
*
|
||||||
|
* 注意:这里读取的是 [Resources.getSystem](系统资源)而非应用 Resources,
|
||||||
|
* 目的是绕开 AndroidAutoSize 对 density 的动态改写,保证判定结果稳定。
|
||||||
|
*/
|
||||||
|
object DeviceUtil {
|
||||||
|
|
||||||
|
/** 平板判定阈值:最小屏幕宽度 >= 600dp 视为平板 */
|
||||||
|
private const val TABLET_MIN_WIDTH_DP = 600
|
||||||
|
|
||||||
|
/** 手机端设计稿基准尺寸(对应 5.5 寸手持端设计稿画布 390 × 844) */
|
||||||
|
const val PHONE_DESIGN_WIDTH_DP = 390
|
||||||
|
const val PHONE_DESIGN_HEIGHT_DP = 844
|
||||||
|
|
||||||
|
/** 平板端设计稿基准尺寸(沿用现有配置) */
|
||||||
|
const val TABLET_DESIGN_WIDTH_DP_LAND = 1152
|
||||||
|
const val TABLET_DESIGN_HEIGHT_DP_LAND = 720
|
||||||
|
const val TABLET_DESIGN_WIDTH_DP_PORT = 720
|
||||||
|
const val TABLET_DESIGN_HEIGHT_DP_PORT = 1280
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调试用:强制指定设备形态
|
||||||
|
*
|
||||||
|
* 开发阶段可在平板上强制走手机布局做验证,正式发布保持 [ForceMode.AUTO]。
|
||||||
|
* 用法:`DeviceUtil.forceMode = DeviceUtil.ForceMode.PHONE`
|
||||||
|
*/
|
||||||
|
enum class ForceMode { AUTO, PHONE, TABLET }
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
var forceMode: ForceMode = ForceMode.AUTO
|
||||||
|
|
||||||
|
/** 缓存自动判定结果,避免每次都读 Configuration */
|
||||||
|
private var cachedIsTablet: Boolean? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否平板
|
||||||
|
* @param context 可不传,默认用 Application 上下文(判定与具体 Activity 无关)
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
fun isTablet(context: Context? = null): Boolean = when (forceMode) {
|
||||||
|
ForceMode.PHONE -> false
|
||||||
|
ForceMode.TABLET -> true
|
||||||
|
ForceMode.AUTO -> cachedIsTablet ?: (smallestWidthDp(context) >= TABLET_MIN_WIDTH_DP)
|
||||||
|
.also { cachedIsTablet = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 是否手机 */
|
||||||
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
fun isPhone(context: Context? = null): Boolean = !isTablet(context)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取最小屏幕宽度(dp)
|
||||||
|
*
|
||||||
|
* 优先读系统资源(不受 AutoSize 影响);异常时回退到应用资源。
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
fun smallestWidthDp(context: Context? = null): Int {
|
||||||
|
val fromSystem = Resources.getSystem()?.configuration?.smallestScreenWidthDp ?: 0
|
||||||
|
if (fromSystem > 0) return fromSystem
|
||||||
|
|
||||||
|
val res = (context ?: runCatching { MyApplication.context }.getOrNull())?.resources
|
||||||
|
return res?.configuration?.smallestScreenWidthDp ?: TABLET_MIN_WIDTH_DP
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按设备形态选择布局
|
||||||
|
*
|
||||||
|
* @param tabletLayout 平板布局(现有布局,必填)
|
||||||
|
* @param phoneLayout 手机布局;传 0 或未提供时,手机上回退使用平板布局
|
||||||
|
* @return 当前设备应加载的布局 id
|
||||||
|
*
|
||||||
|
* 用法(ViewModel 中选择 item 布局):
|
||||||
|
* ```
|
||||||
|
* val itemLayoutId = DeviceUtil.layout(R.layout.item_xxx, R.layout.item_xxx_phone)
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
fun layout(
|
||||||
|
@LayoutRes tabletLayout: Int,
|
||||||
|
@LayoutRes phoneLayout: Int = 0,
|
||||||
|
context: Context? = null
|
||||||
|
): Int = if (phoneLayout != 0 && isPhone(context)) phoneLayout else tabletLayout
|
||||||
|
|
||||||
|
/** 配置发生变化时清空缓存(如分屏、折叠屏形态切换) */
|
||||||
|
@JvmStatic
|
||||||
|
fun clearCache() {
|
||||||
|
cachedIsTablet = null
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 设备形态描述,用于日志排查 */
|
||||||
|
@JvmStatic
|
||||||
|
fun describe(): String =
|
||||||
|
"${if (isTablet()) "TABLET" else "PHONE"}(sw=${smallestWidthDp()}dp, force=$forceMode)"
|
||||||
|
}
|
||||||
@@ -1,46 +1,46 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.lukouguoji.module_base">
|
package="com.lukouguoji.module_base">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:icon="@mipmap/logot"
|
android:icon="@mipmap/logot"
|
||||||
android:roundIcon="@mipmap/logot_round">
|
android:roundIcon="@mipmap/logot_round">
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.signature.SignatureActivity"
|
android:name=".ui.signature.SignatureActivity"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:screenOrientation="userLandscape" />
|
android:screenOrientation="unspecified" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:screenOrientation="userLandscape" />
|
android:screenOrientation="unspecified" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.page.preview.PreviewActivity"
|
android:name=".ui.page.preview.PreviewActivity"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:exported="true"/>
|
android:exported="true"/>
|
||||||
|
|
||||||
<!-- PDF预览Activity -->
|
<!-- PDF预览Activity -->
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.page.preview.PdfPreviewActivity"
|
android:name=".ui.page.preview.PdfPreviewActivity"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:screenOrientation="userLandscape" />
|
android:screenOrientation="unspecified" />
|
||||||
|
|
||||||
<!-- 屏幕适配 -->
|
<!-- 屏幕适配 -->
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="design_width_in_dp"
|
android:name="design_width_in_dp"
|
||||||
android:value="1152" />
|
android:value="1152" />
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="design_height_in_dp"
|
android:name="design_height_in_dp"
|
||||||
android:value="720" />
|
android:value="720" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
7
module_base/src/main/res/drawable/bg_phone_badge.xml
Normal file
7
module_base/src/main/res/drawable/bg_phone_badge.xml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 手机版 Tab 角标:主色浅底 + 6dp 圆角 -->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/phone_badge_bg" />
|
||||||
|
<corners android:radius="6dp" />
|
||||||
|
</shape>
|
||||||
22
module_base/src/main/res/drawable/bg_phone_btn_outline.xml
Normal file
22
module_base/src/main/res/drawable/bg_phone_btn_outline.xml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 手机版次要按钮(重置):白底 + 浅边框 + 10dp 圆角 -->
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_pressed="true">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="@color/phone_stat_bg" />
|
||||||
|
<corners android:radius="10dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/phone_divider" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="@color/white" />
|
||||||
|
<corners android:radius="10dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/phone_divider" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</selector>
|
||||||
16
module_base/src/main/res/drawable/bg_phone_btn_primary.xml
Normal file
16
module_base/src/main/res/drawable/bg_phone_btn_primary.xml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 手机版主操作按钮:主色实底 + 10dp 圆角 -->
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_pressed="true">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="#1D4FD8" />
|
||||||
|
<corners android:radius="10dp" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="@color/phone_primary" />
|
||||||
|
<corners android:radius="10dp" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</selector>
|
||||||
10
module_base/src/main/res/drawable/bg_phone_card.xml
Normal file
10
module_base/src/main/res/drawable/bg_phone_card.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 手机版列表卡片背景:白底 + 12dp 圆角 + 浅边框 -->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/white" />
|
||||||
|
<corners android:radius="12dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="0.5dp"
|
||||||
|
android:color="@color/phone_divider" />
|
||||||
|
</shape>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 手机版详情卡片表头:主色底 + 顶部 12dp 圆角(与 bg_phone_card 圆角一致) -->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/phone_primary" />
|
||||||
|
<corners
|
||||||
|
android:topLeftRadius="12dp"
|
||||||
|
android:topRightRadius="12dp" />
|
||||||
|
</shape>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 手机版详情卡片表头:完成态绿底 + 顶部 12dp 圆角 -->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/phone_green" />
|
||||||
|
<corners
|
||||||
|
android:topLeftRadius="12dp"
|
||||||
|
android:topRightRadius="12dp" />
|
||||||
|
</shape>
|
||||||
6
module_base/src/main/res/drawable/bg_phone_dot_green.xml
Normal file
6
module_base/src/main/res/drawable/bg_phone_dot_green.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="oval">
|
||||||
|
<solid android:color="@color/phone_green" />
|
||||||
|
</shape>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 手机版圆形图标按钮(搜索行右侧筛选按钮):白底 + 浅边框 -->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="oval">
|
||||||
|
<solid android:color="@color/white" />
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/phone_divider" />
|
||||||
|
</shape>
|
||||||
10
module_base/src/main/res/drawable/bg_phone_input.xml
Normal file
10
module_base/src/main/res/drawable/bg_phone_input.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 手机版表单/筛选输入框:白底 + 1px 边框 + 8dp 圆角 -->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/white" />
|
||||||
|
<corners android:radius="8dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/phone_divider" />
|
||||||
|
</shape>
|
||||||
9
module_base/src/main/res/drawable/bg_phone_panel_top.xml
Normal file
9
module_base/src/main/res/drawable/bg_phone_panel_top.xml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 手机版底部弹层面板:白底 + 顶部 20dp 圆角 -->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/white" />
|
||||||
|
<corners
|
||||||
|
android:topLeftRadius="20dp"
|
||||||
|
android:topRightRadius="20dp" />
|
||||||
|
</shape>
|
||||||
10
module_base/src/main/res/drawable/bg_phone_search.xml
Normal file
10
module_base/src/main/res/drawable/bg_phone_search.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 手机版搜索框背景:白底 + 12dp 圆角 + 浅边框 -->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/white" />
|
||||||
|
<corners android:radius="12dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/phone_divider" />
|
||||||
|
</shape>
|
||||||
7
module_base/src/main/res/drawable/bg_phone_stat_box.xml
Normal file
7
module_base/src/main/res/drawable/bg_phone_stat_box.xml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 手机版卡片内统计框:浅灰底 + 8dp 圆角 -->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/phone_stat_bg" />
|
||||||
|
<corners android:radius="8dp" />
|
||||||
|
</shape>
|
||||||
7
module_base/src/main/res/drawable/bg_phone_tag_gray.xml
Normal file
7
module_base/src/main/res/drawable/bg_phone_tag_gray.xml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 手机版状态标签:灰底(未完成态) -->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/phone_tag_gray_bg" />
|
||||||
|
<corners android:radius="6dp" />
|
||||||
|
</shape>
|
||||||
7
module_base/src/main/res/drawable/bg_phone_tag_green.xml
Normal file
7
module_base/src/main/res/drawable/bg_phone_tag_green.xml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 手机版状态标签:绿底(已完成态) -->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/phone_tag_green_bg" />
|
||||||
|
<corners android:radius="6dp" />
|
||||||
|
</shape>
|
||||||
11
module_base/src/main/res/drawable/bg_phone_tag_orange.xml
Normal file
11
module_base/src/main/res/drawable/bg_phone_tag_orange.xml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
手机版状态标签:橙底(待处理态,如「待移库」)
|
||||||
|
与 bg_phone_tag_green / gray / red 同属状态标签家族,统一 6dp 圆角。
|
||||||
|
数值高亮(详情页库位那种小色块)请用 bg_phone_value_orange。
|
||||||
|
-->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/phone_tag_orange_bg" />
|
||||||
|
<corners android:radius="6dp" />
|
||||||
|
</shape>
|
||||||
7
module_base/src/main/res/drawable/bg_phone_tag_red.xml
Normal file
7
module_base/src/main/res/drawable/bg_phone_tag_red.xml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 手机版状态标签:红底(危险品等强提示) -->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/phone_tag_red_bg" />
|
||||||
|
<corners android:radius="6dp" />
|
||||||
|
</shape>
|
||||||
11
module_base/src/main/res/drawable/bg_phone_value_orange.xml
Normal file
11
module_base/src/main/res/drawable/bg_phone_value_orange.xml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
手机版数值高亮底:浅橙 + 4dp 圆角
|
||||||
|
用于详情页需要突出的字段值(如库位),由 PhoneKvItem 的 tag=true 使用。
|
||||||
|
状态标签(待移库/已完成那类)请用 bg_phone_tag_* 家族。
|
||||||
|
-->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/phone_orange_bg" />
|
||||||
|
<corners android:radius="4dp" />
|
||||||
|
</shape>
|
||||||
12
module_base/src/main/res/drawable/ic_phone_airplane.xml
Normal file
12
module_base/src/main/res/drawable/ic_phone_airplane.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 手机版图标:飞机(航班信息行) -->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="@color/phone_text_body">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M21,16V14L13,9V3.5A1.5,1.5 0 0,0 11.5,2A1.5,1.5 0 0,0 10,3.5V9L2,14V16L10,13.5V19L8,20.5V22L11.5,21L15,22V20.5L13,19V13.5L21,16Z" />
|
||||||
|
</vector>
|
||||||
12
module_base/src/main/res/drawable/ic_phone_calendar.xml
Normal file
12
module_base/src/main/res/drawable/ic_phone_calendar.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 手机版图标:日历(日期选择) -->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="@color/phone_text_body">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M19,19H5V8H19M16,1V3H8V1H6V3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3H18V1H16Z" />
|
||||||
|
</vector>
|
||||||
12
module_base/src/main/res/drawable/ic_phone_check_circle.xml
Normal file
12
module_base/src/main/res/drawable/ic_phone_check_circle.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 手机版图标:圆形对勾(已完成状态) -->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="@color/phone_green">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M11,16.5L6.5,12L7.91,10.59L11,13.67L16.59,8.09L18,9.5L11,16.5Z" />
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
手机版圆形复选框 —— 选中态
|
||||||
|
主色实心圆 + 白色对勾(对应设计稿 .custom-checkbox-round:checked)
|
||||||
|
-->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="@color/phone_primary"
|
||||||
|
android:pathData="M12,1A11,11 0 1,0 12,23A11,11 0 1,0 12,1Z" />
|
||||||
|
<group
|
||||||
|
android:pivotX="12"
|
||||||
|
android:pivotY="12"
|
||||||
|
android:scaleX="0.6"
|
||||||
|
android:scaleY="0.6">
|
||||||
|
<path
|
||||||
|
android:fillColor="@color/white"
|
||||||
|
android:pathData="M9,20.42L2.79,14.21L5.62,11.38L9,14.77L18.88,4.88L21.71,7.71L9,20.42Z" />
|
||||||
|
</group>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
手机版圆形复选框 —— 未选中态
|
||||||
|
白色填充 + 2dp 灰边圆环(对应设计稿 .custom-checkbox-round 默认态)
|
||||||
|
-->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="@color/white"
|
||||||
|
android:pathData="M12,2A10,10 0 1,0 12,22A10,10 0 1,0 12,2Z"
|
||||||
|
android:strokeColor="@color/phone_check_border"
|
||||||
|
android:strokeWidth="2" />
|
||||||
|
</vector>
|
||||||
12
module_base/src/main/res/drawable/ic_phone_chevron_down.xml
Normal file
12
module_base/src/main/res/drawable/ic_phone_chevron_down.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 手机版图标:下箭头(下拉选择) -->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="@color/phone_text_body">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z" />
|
||||||
|
</vector>
|
||||||
12
module_base/src/main/res/drawable/ic_phone_chevron_right.xml
Normal file
12
module_base/src/main/res/drawable/ic_phone_chevron_right.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 手机版图标:右箭头(查看详情) -->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="@color/phone_primary">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M8.59,16.58L13.17,12L8.59,7.41L10,6L16,12L10,18L8.59,16.58Z" />
|
||||||
|
</vector>
|
||||||
12
module_base/src/main/res/drawable/ic_phone_close.xml
Normal file
12
module_base/src/main/res/drawable/ic_phone_close.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 手机版图标:关闭(弹层右上角) -->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="@color/phone_text_hint">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" />
|
||||||
|
</vector>
|
||||||
12
module_base/src/main/res/drawable/ic_phone_location.xml
Normal file
12
module_base/src/main/res/drawable/ic_phone_location.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 手机版图标:定位(库位行) -->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="@color/phone_text_body">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M12,11.5A2.5,2.5 0 0,1 9.5,9A2.5,2.5 0 0,1 12,6.5A2.5,2.5 0 0,1 14.5,9A2.5,2.5 0 0,1 12,11.5M12,2A7,7 0 0,0 5,9C5,14.25 12,22 12,22C12,22 19,14.25 19,9A7,7 0 0,0 12,2Z" />
|
||||||
|
</vector>
|
||||||
12
module_base/src/main/res/drawable/ic_phone_person.xml
Normal file
12
module_base/src/main/res/drawable/ic_phone_person.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 手机版图标:人像(操作人信息行) -->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="@color/phone_text_body">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,6A2,2 0 0,0 10,8A2,2 0 0,0 12,10A2,2 0 0,0 14,8A2,2 0 0,0 12,6M12,13C14.67,13 20,14.33 20,17V20H4V17C4,14.33 9.33,13 12,13M12,14.9C9,14.9 5.9,16.36 5.9,17V18.1H18.1V17C18.1,16.36 15,14.9 12,14.9Z" />
|
||||||
|
</vector>
|
||||||
42
module_base/src/main/res/layout-sw600dp/title_tool_bar.xml
Normal file
42
module_base/src/main/res/layout-sw600dp/title_tool_bar.xml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.appcompat.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:background="@color/colorPrimary"
|
||||||
|
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/tool_back"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/tool_iv_back"
|
||||||
|
android:layout_width="15dp"
|
||||||
|
android:layout_height="15dp"
|
||||||
|
android:src="@mipmap/left_icon"
|
||||||
|
app:tint="@color/white" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tool_tv_back"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical|left"
|
||||||
|
android:text="返回"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="18sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title_name"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:text="主页"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="18sp" />
|
||||||
|
</androidx.appcompat.widget.Toolbar>
|
||||||
15
module_base/src/main/res/layout/item_spinner_list_14sp.xml
Normal file
15
module_base/src/main/res/layout/item_spinner_list_14sp.xml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
手机版下拉选项条目(14sp)
|
||||||
|
与 PhoneDataLayout 输入框文字大小保持一致,供 5.5 寸手持端 SPINNER 使用。
|
||||||
|
-->
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@android:id/text1"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:minHeight="?android:attr/listPreferredItemHeightSmall"
|
||||||
|
android:paddingStart="10dp"
|
||||||
|
android:paddingEnd="10dp"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceListItemSmall"
|
||||||
|
android:textSize="14sp" />
|
||||||
64
module_base/src/main/res/layout/layout_phone_bottom_bar.xml
Normal file
64
module_base/src/main/res/layout/layout_phone_bottom_bar.xml
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
PhoneBottomBar 内部布局(手机版底部操作条)
|
||||||
|
|
||||||
|
结构:全选 + 已选统计 + 主操作按钮
|
||||||
|
对应设计稿各多选列表页底部的白色操作条
|
||||||
|
-->
|
||||||
|
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
tools:parentTag="android.widget.LinearLayout">
|
||||||
|
|
||||||
|
<!-- 全选 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/ll_check_all"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_check_all"
|
||||||
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:src="@drawable/ic_phone_check_round_unchecked" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:text="全选"
|
||||||
|
android:textColor="@color/phone_text_title"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 中间留白 -->
|
||||||
|
<View
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<!-- 已选统计 -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_count"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:textColor="@color/phone_text_hint"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<!-- 主操作按钮 -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_action"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_phone_btn_primary"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingHorizontal="20dp"
|
||||||
|
android:paddingVertical="9dp"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
</merge>
|
||||||
94
module_base/src/main/res/layout/layout_phone_data_layout.xml
Normal file
94
module_base/src/main/res/layout/layout_phone_data_layout.xml
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
PhoneDataLayout 内部布局(手机版表单 / 筛选项)
|
||||||
|
|
||||||
|
结构:上方标题 + 下方控件框(输入 / 日期 / 下拉三态互斥显示)
|
||||||
|
对应设计稿:5.5 寸手持端筛选弹层内的条件项
|
||||||
|
-->
|
||||||
|
<merge 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"
|
||||||
|
tools:parentTag="android.widget.LinearLayout">
|
||||||
|
|
||||||
|
<!-- 标题行:标题 + 必填星号 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="6dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/phone_text_label"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_must"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="2dp"
|
||||||
|
android:text="*"
|
||||||
|
android:textColor="@color/phone_tag_red_bg"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 控件框 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/ll_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:background="@drawable/bg_phone_input"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="12dp">
|
||||||
|
|
||||||
|
<!-- 文本输入 -->
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/et"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@null"
|
||||||
|
android:inputType="text"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="@color/phone_text_title"
|
||||||
|
android:textColorHint="@color/phone_text_hint"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<!-- 日期显示(点击弹日历) -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:textColor="@color/phone_text_title"
|
||||||
|
android:textColorHint="@color/phone_text_hint"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<!-- 下拉选择 -->
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/spinner"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@null"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<!-- 右侧指示图标(日期=日历 / 下拉=箭头 / 输入=隐藏) -->
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv"
|
||||||
|
android:layout_width="18dp"
|
||||||
|
android:layout_height="18dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:tint="@color/phone_text_body" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</merge>
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
PhoneFilterPanel 内部布局(手机版底部筛选弹层)
|
||||||
|
|
||||||
|
结构:底部白色面板(顶部 20dp 圆角)= 标题行 + 内容插槽 + 重置/确认按钮行
|
||||||
|
外层遮罩由 PhoneFilterPanel 自身(FrameLayout)承担。
|
||||||
|
XML 中声明在 PhoneFilterPanel 内的子 View 会被自动移入 ll_content。
|
||||||
|
-->
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/ll_panel"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:background="@drawable/bg_phone_panel_top"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingHorizontal="20dp"
|
||||||
|
android:paddingTop="24dp"
|
||||||
|
android:paddingBottom="32dp">
|
||||||
|
|
||||||
|
<!-- 标题行:标题居中 + 右上关闭 -->
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="24dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="筛选条件"
|
||||||
|
android:textColor="@color/phone_text_strong"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_close"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_gravity="end|center_vertical"
|
||||||
|
android:src="@drawable/ic_phone_close" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<!-- 内容插槽:筛选条件项由使用方在 XML 中声明 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/ll_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical" />
|
||||||
|
|
||||||
|
<!-- 底部按钮行 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="32dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_reset"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="44dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@drawable/bg_phone_btn_outline"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="重置"
|
||||||
|
android:textColor="@color/phone_text_weak_btn"
|
||||||
|
android:textSize="15sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_confirm"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="44dp"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@drawable/bg_phone_btn_primary"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="确认"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
65
module_base/src/main/res/layout/layout_phone_search_bar.xml
Normal file
65
module_base/src/main/res/layout/layout_phone_search_bar.xml
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
PhoneSearchBar 内部布局(手机版搜索行)
|
||||||
|
|
||||||
|
结构:圆角搜索框(放大镜 + 输入 + 扫码) + 右侧圆形筛选按钮
|
||||||
|
对应设计稿:5.5 寸手持端各列表页顶部搜索区
|
||||||
|
-->
|
||||||
|
<merge 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"
|
||||||
|
tools:parentTag="android.widget.LinearLayout">
|
||||||
|
|
||||||
|
<!-- 搜索框 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/ll_search"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@drawable/bg_phone_search"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="12dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_search"
|
||||||
|
android:layout_width="18dp"
|
||||||
|
android:layout_height="18dp"
|
||||||
|
android:src="@drawable/img_search"
|
||||||
|
app:tint="@color/phone_text_hint" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/et"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@null"
|
||||||
|
android:imeOptions="actionSearch"
|
||||||
|
android:inputType="text"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:paddingHorizontal="8dp"
|
||||||
|
android:textColor="@color/phone_text_title"
|
||||||
|
android:textColorHint="@color/phone_text_hint"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_scan"
|
||||||
|
android:layout_width="18dp"
|
||||||
|
android:layout_height="18dp"
|
||||||
|
android:src="@drawable/img_scan"
|
||||||
|
app:tint="@color/phone_primary" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 筛选按钮 -->
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_filter"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:background="@drawable/bg_phone_icon_round"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:src="@drawable/img_filter"
|
||||||
|
app:tint="@color/phone_primary" />
|
||||||
|
|
||||||
|
</merge>
|
||||||
138
module_base/src/main/res/layout/layout_phone_stat_box.xml
Normal file
138
module_base/src/main/res/layout/layout_phone_stat_box.xml
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
PhoneStatBox 内部布局(手机版卡片统计框)
|
||||||
|
|
||||||
|
最多 4 列,未设置 label 的列自动隐藏(含其左侧分隔线)。
|
||||||
|
对应设计稿列表卡片中间的浅灰统计区。
|
||||||
|
-->
|
||||||
|
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
tools:parentTag="android.widget.LinearLayout">
|
||||||
|
|
||||||
|
<!-- 第 1 列 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/ll_col1"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_label1"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/phone_text_hint"
|
||||||
|
android:textSize="11sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_value1"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:textColor="@color/phone_text_title"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/divider2"
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/phone_divider" />
|
||||||
|
|
||||||
|
<!-- 第 2 列 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/ll_col2"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_label2"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/phone_text_hint"
|
||||||
|
android:textSize="11sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_value2"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:textColor="@color/phone_text_title"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/divider3"
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/phone_divider" />
|
||||||
|
|
||||||
|
<!-- 第 3 列 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/ll_col3"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_label3"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/phone_text_hint"
|
||||||
|
android:textSize="11sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_value3"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:textColor="@color/phone_text_title"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/divider4"
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/phone_divider" />
|
||||||
|
|
||||||
|
<!-- 第 4 列 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/ll_col4"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_label4"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/phone_text_hint"
|
||||||
|
android:textSize="11sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_value4"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:textColor="@color/phone_text_title"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</merge>
|
||||||
@@ -1,42 +1,67 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.appcompat.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
|
<!--
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
手机版公共标题栏(5.5 寸手持端)
|
||||||
android:id="@+id/toolbar"
|
|
||||||
android:layout_width="match_parent"
|
与平板版 title_tool_bar.xml 保持相同的根类型(Toolbar)与控件 id:
|
||||||
android:layout_height="50dp"
|
toolbar / tool_back / tool_iv_back / tool_tv_back / title_name
|
||||||
android:background="@color/colorPrimary"
|
因此 BaseActivity.setBackArrow() 无需任何改动即可复用。
|
||||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
|
-->
|
||||||
|
<androidx.appcompat.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
<LinearLayout
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:id="@+id/tool_back"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="48dp"
|
||||||
android:gravity="center">
|
android:background="@color/phone_primary"
|
||||||
|
android:contentInsetStart="0dp"
|
||||||
<ImageView
|
android:contentInsetLeft="0dp"
|
||||||
android:id="@+id/tool_iv_back"
|
app:contentInsetStart="0dp"
|
||||||
android:layout_width="15dp"
|
app:contentInsetLeft="0dp"
|
||||||
android:layout_height="15dp"
|
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
|
||||||
android:src="@mipmap/left_icon"
|
|
||||||
app:tint="@color/white" />
|
<!-- 整条标题栏:左侧返回 + 居中标题 -->
|
||||||
|
<FrameLayout
|
||||||
<TextView
|
android:layout_width="match_parent"
|
||||||
android:id="@+id/tool_tv_back"
|
android:layout_height="match_parent">
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
<!-- 居中标题(先声明,保证在返回区下层,不抢占点击) -->
|
||||||
android:layout_gravity="center_vertical|left"
|
<TextView
|
||||||
android:text="返回"
|
android:id="@+id/title_name"
|
||||||
android:textColor="@color/white"
|
android:layout_width="wrap_content"
|
||||||
android:textSize="18sp" />
|
android:layout_height="wrap_content"
|
||||||
</LinearLayout>
|
android:layout_gravity="center"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
<TextView
|
android:text="标题"
|
||||||
android:id="@+id/title_name"
|
android:textColor="@color/white"
|
||||||
android:layout_width="wrap_content"
|
android:textSize="18sp"
|
||||||
android:layout_height="wrap_content"
|
android:textStyle="bold" />
|
||||||
android:layout_gravity="center"
|
|
||||||
android:text="主页"
|
<!-- 左侧返回区 -->
|
||||||
android:textColor="@color/white"
|
<LinearLayout
|
||||||
android:textSize="18sp" />
|
android:id="@+id/tool_back"
|
||||||
</androidx.appcompat.widget.Toolbar>
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="start|center_vertical"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/tool_iv_back"
|
||||||
|
android:layout_width="14dp"
|
||||||
|
android:layout_height="14dp"
|
||||||
|
android:src="@mipmap/left_icon"
|
||||||
|
app:tint="@color/white" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tool_tv_back"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="2dp"
|
||||||
|
android:text="返回"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="15sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
</androidx.appcompat.widget.Toolbar>
|
||||||
|
|||||||
@@ -47,4 +47,31 @@
|
|||||||
<color name="black_tran50">#80000000</color> <!-- 50%透明度 -->
|
<color name="black_tran50">#80000000</color> <!-- 50%透明度 -->
|
||||||
<color name="black_tran70">#B3000000</color> <!-- 70%透明度 -->
|
<color name="black_tran70">#B3000000</color> <!-- 70%透明度 -->
|
||||||
|
|
||||||
|
<!-- ==================== 5.5 寸手持端(手机版)配色 ==================== -->
|
||||||
|
<color name="phone_primary">#2563EB</color> <!-- 手机版主色(顶栏、主按钮) -->
|
||||||
|
<color name="phone_primary_light">#EAF1FE</color> <!-- 主色浅底(选中态背景) -->
|
||||||
|
<color name="phone_bg">#F3F4F6</color> <!-- 页面背景 -->
|
||||||
|
<color name="phone_text_title">#1F2937</color> <!-- 标题/主要文字 -->
|
||||||
|
<color name="phone_text_body">#6B7280</color> <!-- 次要文字 -->
|
||||||
|
<color name="phone_text_hint">#9CA3AF</color> <!-- 占位文字 -->
|
||||||
|
<color name="phone_divider">#E5E7EB</color> <!-- 分割线/边框 -->
|
||||||
|
<color name="phone_tag_gray_bg">#F3F4F6</color> <!-- 状态标签-灰底 -->
|
||||||
|
<color name="phone_tag_gray_text">#6B7280</color>
|
||||||
|
<color name="phone_tag_green_bg">#DCFCE7</color> <!-- 状态标签-绿底 -->
|
||||||
|
<color name="phone_tag_green_text">#16A34A</color>
|
||||||
|
<color name="phone_tag_red_bg">#DC2626</color> <!-- 状态标签-红底(危险品等强提示) -->
|
||||||
|
<color name="phone_tag_red_text">#FFFFFF</color>
|
||||||
|
<color name="phone_page_bg">#F5F6FA</color> <!-- 列表页滚动区背景 -->
|
||||||
|
<color name="phone_stat_bg">#F3F4F6</color> <!-- 卡片内统计框底色 -->
|
||||||
|
<color name="phone_badge_bg">#DBEAF6</color> <!-- Tab 角标底色 -->
|
||||||
|
<color name="phone_text_label">#374151</color> <!-- 表单/筛选项标题 -->
|
||||||
|
<color name="phone_text_strong">#111827</color> <!-- 强调标题(弹层标题、详情主字段) -->
|
||||||
|
<color name="phone_text_weak_btn">#4B5563</color> <!-- 次要按钮文字(重置) -->
|
||||||
|
<color name="phone_green">#10B981</color> <!-- 完成态强调色(对勾、信息卡表头) -->
|
||||||
|
<color name="phone_check_border">#CBD5E1</color> <!-- 未选中复选框边框 -->
|
||||||
|
<color name="phone_orange_bg">#FFF7ED</color> <!-- 数值高亮-浅橙底(详情页库位等) -->
|
||||||
|
<color name="phone_orange_text">#EA580C</color>
|
||||||
|
<color name="phone_tag_orange_bg">#FFEDD5</color> <!-- 状态标签-橙底(待处理态) -->
|
||||||
|
<color name="phone_tag_orange_text">#EA580C</color>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<application>
|
<application>
|
||||||
<activity
|
<activity
|
||||||
android:name="com.lukouguoji.cargo.activity.CargoTrackingActivity"
|
android:name="com.lukouguoji.cargo.activity.CargoTrackingActivity"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:screenOrientation="userLandscape"
|
android:screenOrientation="unspecified"
|
||||||
/>
|
/>
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -1,25 +1,25 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.lukouguoji.cargo">
|
package="com.lukouguoji.cargo">
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.Aerologic">
|
android:theme="@style/Theme.Aerologic">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:screenOrientation="userLandscape"
|
android:screenOrientation="unspecified"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.lukouguoji.cargo">
|
package="com.lukouguoji.cargo">
|
||||||
|
|
||||||
<application>
|
<application>
|
||||||
<activity android:name=".activity.CargoTrackingActivity"
|
<activity android:name=".activity.CargoTrackingActivity"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:screenOrientation="userLandscape"
|
android:screenOrientation="unspecified"
|
||||||
/>
|
/>
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:screenOrientation="userLandscape"
|
android:screenOrientation="unspecified"
|
||||||
android:exported="true" />
|
android:exported="true" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -1,25 +1,25 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.lukouguoji.gjc">
|
package="com.lukouguoji.gjc">
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.Aerologic">
|
android:theme="@style/Theme.Aerologic">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:screenOrientation="userLandscape"
|
android:screenOrientation="unspecified"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -1,56 +1,96 @@
|
|||||||
package com.lukouguoji.gjc.activity
|
package com.lukouguoji.gjc.activity
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
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 androidx.databinding.ObservableBoolean
|
||||||
import com.lukouguoji.gjc.R
|
import com.alibaba.android.arouter.facade.annotation.Route
|
||||||
import com.lukouguoji.gjc.databinding.ActivityIntExpOutHandoverBinding
|
import com.lukouguoji.gjc.R
|
||||||
import com.lukouguoji.gjc.viewModel.IntExpOutHandoverViewModel
|
import com.lukouguoji.gjc.databinding.ActivityIntExpOutHandoverBinding
|
||||||
import com.lukouguoji.module_base.base.BaseBindingActivity
|
import com.lukouguoji.gjc.viewModel.IntExpOutHandoverViewModel
|
||||||
import com.lukouguoji.module_base.common.Constant
|
import com.lukouguoji.module_base.base.BaseBindingActivity
|
||||||
import com.lukouguoji.module_base.common.ConstantEvent
|
import com.lukouguoji.module_base.common.Constant
|
||||||
import com.lukouguoji.module_base.impl.FlowBus
|
import com.lukouguoji.module_base.common.ConstantEvent
|
||||||
import com.lukouguoji.module_base.impl.observe
|
import com.lukouguoji.module_base.impl.FlowBus
|
||||||
import com.lukouguoji.module_base.ktx.addOnItemClickListener
|
import com.lukouguoji.module_base.impl.observe
|
||||||
import com.lukouguoji.module_base.router.ARouterConstants
|
import com.lukouguoji.module_base.ktx.addOnItemClickListener
|
||||||
|
import com.lukouguoji.module_base.router.ARouterConstants
|
||||||
/**
|
import com.lukouguoji.module_base.util.DeviceUtil
|
||||||
* 国际出港-出库交接页面
|
|
||||||
*/
|
/**
|
||||||
@Route(path = ARouterConstants.ACTIVITY_URL_INT_EXP_OUT_HANDOVER)
|
* 国际出港-出库交接页面
|
||||||
class IntExpOutHandoverActivity :
|
*
|
||||||
BaseBindingActivity<ActivityIntExpOutHandoverBinding, IntExpOutHandoverViewModel>() {
|
* 布局 id 不区分设备,平板/手机由资源限定符自动选择:
|
||||||
|
* layout-sw600dp/activity_int_exp_out_handover.xml(平板)
|
||||||
override fun layoutId() = R.layout.activity_int_exp_out_handover
|
* layout/activity_int_exp_out_handover.xml(手机)
|
||||||
override fun viewModelClass() = IntExpOutHandoverViewModel::class.java
|
*/
|
||||||
|
@Route(path = ARouterConstants.ACTIVITY_URL_INT_EXP_OUT_HANDOVER)
|
||||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
class IntExpOutHandoverActivity :
|
||||||
setBackArrow("国际出港出库交接")
|
BaseBindingActivity<ActivityIntExpOutHandoverBinding, IntExpOutHandoverViewModel>() {
|
||||||
binding.viewModel = viewModel
|
|
||||||
|
override fun layoutId() = R.layout.activity_int_exp_out_handover
|
||||||
// 绑定分页
|
override fun viewModelClass() = IntExpOutHandoverViewModel::class.java
|
||||||
viewModel.pageModel.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, this)
|
|
||||||
|
/** 手机版筛选弹层显隐(仅 UI 状态,不涉及业务逻辑) */
|
||||||
// 设置item点击监听
|
val filterPanelVisible = ObservableBoolean(false)
|
||||||
binding.rv.addOnItemClickListener(viewModel)
|
|
||||||
|
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||||
// 监听刷新事件
|
setBackArrow("国际出港出库交接")
|
||||||
FlowBus.with<String>(ConstantEvent.EVENT_CHECK_CHANGED).observe(this) { viewModel.onItemCheckChanged() }
|
binding.viewModel = viewModel
|
||||||
|
binding.activity = this
|
||||||
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).observe(this) {
|
|
||||||
viewModel.refresh()
|
// 手机版专属数据:默认「待交接」Tab、Tab 角标计数、交接人下拉
|
||||||
}
|
// 平板端不调用,查询链路与请求次数与改造前完全一致
|
||||||
|
if (DeviceUtil.isPhone()) {
|
||||||
// 初始加载数据
|
viewModel.initPhoneExtras()
|
||||||
viewModel.refresh()
|
}
|
||||||
}
|
|
||||||
|
// 绑定分页
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
viewModel.pageModel.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, this)
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
|
||||||
if (requestCode == Constant.RequestCode.ULD && resultCode == Activity.RESULT_OK) {
|
// 设置item点击监听
|
||||||
viewModel.uldNo.value = data?.getStringExtra(Constant.Result.CODED_CONTENT)
|
binding.rv.addOnItemClickListener(viewModel)
|
||||||
viewModel.searchClick()
|
|
||||||
}
|
// 监听刷新事件
|
||||||
}
|
FlowBus.with<String>(ConstantEvent.EVENT_CHECK_CHANGED).observe(this) { viewModel.onItemCheckChanged() }
|
||||||
}
|
|
||||||
|
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).observe(this) {
|
||||||
|
viewModel.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始加载数据
|
||||||
|
viewModel.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 手机版专用交互(纯 UI,复用既有 ViewModel 字段) ====================
|
||||||
|
|
||||||
|
/** 手机版筛选弹层显隐切换 */
|
||||||
|
fun toggleFilterPanel() {
|
||||||
|
filterPanelVisible.set(!filterPanelVisible.get())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机版筛选:重置
|
||||||
|
*
|
||||||
|
* 只清空弹层内的三个条件(航班日期 / 航班号 / 交接人),不影响 Tab 与顶部搜索框。
|
||||||
|
*/
|
||||||
|
fun resetFilter() {
|
||||||
|
viewModel.flightDate.value = ""
|
||||||
|
viewModel.flightNo.value = ""
|
||||||
|
viewModel.hoId.value = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 手机版筛选:确认 */
|
||||||
|
fun confirmFilter() {
|
||||||
|
filterPanelVisible.set(false)
|
||||||
|
viewModel.searchClick()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
if (requestCode == Constant.RequestCode.ULD && resultCode == Activity.RESULT_OK) {
|
||||||
|
viewModel.uldNo.value = data?.getStringExtra(Constant.Result.CODED_CONTENT)
|
||||||
|
viewModel.searchClick()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user