feat: 完成出港查询页面5.5寸手机端适配

- 列表/详情/运单追踪三页同名布局双变体(平板移 layout-sw600dp/,Kotlin 零设备分支)
- 列表:搜索行 + 三格统计(总票数/已入库/已离港,已加载数据客户端计数)+ 状态标签卡片
  (已离港/已入库/未入库,前端按 fclose/opDate 推断)+ 9 项底部筛选弹层(特码改下拉)
- 详情:3 Tab 复用 ViewPager2+Fragment,PhoneKvItem 网格;入库件数/重量按 warehouseList 求和
- 运单追踪:公共页 LogDetailActivity 双变体首例,手机竖排时间线动态构建,平板横向步骤条不动
- 修复 PhoneFilterPanel 筛选项超屏时底部按钮被挤出屏幕(内容插槽加 ScrollView)
- PhoneKvItem 新增 tagColor 绿色高亮(海关放行),占位符不套标签底
- 手机首页国际 Tab 加出港查询入口;后端缺口 #21/#22 登记问题清单
- 双端实机验证通过(内网真实数据 + Proxyman Map Local 补验未入库兜底态)
- skill 新增 references/proxyman.md:抓包/直调 A/B/Mock 与 api-doc 配合规范

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-31 18:13:44 +08:00
parent 436202f15b
commit 33c9f0e030
41 changed files with 3730 additions and 1629 deletions

View File

@@ -148,6 +148,20 @@ data class GjcMaWb(
else -> if (declareStatus.isNullOrEmpty()) "" else "amber"
}
/**
* 5.5寸手机版-出港查询:卡片状态标签。
* 已离港 = 航班关闭时间fclose非空已入库 = 入库时间opDate非空都为空 = 未入库(灰)。
* 接口无独立状态出参,此判定为前端推断(与卡片「入库时间/离港时间」两列同源)。
*/
val isQueryDeparted: Boolean
get() = !fclose.isNullOrEmpty()
val isQueryStored: Boolean
get() = !opDate.isNullOrEmpty()
/** 5.5寸手机版:空值统一占位 "--"(空串与 null 都兜底,布局绑定用) */
fun orDash(value: String?): String = if (value.isNullOrEmpty()) "--" else value
// ==================== 状态转换扩展属性 ====================
/**
* 计重状态中文

View File

@@ -56,13 +56,25 @@ class PhoneKvItem @JvmOverloads constructor(
applyStyle()
}
/** 高亮标签配色:"orange"(默认,如库位)/ "green"(如海关放行正常态) */
var tagColor: String = "orange"
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))
if (tag && value.isNotEmpty() && value != "-" && value != "--") {
if (tagColor == "green") {
tvValue.setBackgroundResource(R.drawable.bg_phone_tag_green)
tvValue.setTextColor(ContextCompat.getColor(context, R.color.phone_tag_green_text))
} else {
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)

View File

@@ -219,10 +219,17 @@ fun setPhoneStatBoxAttrs(
// PhoneKvItem
///////////////////////////////////////////////////////////////////////////
@BindingAdapter("title", "value", "tag", requireAll = false)
fun setPhoneKvItemAttrs(item: PhoneKvItem, title: String?, value: String?, tag: Boolean?) {
@BindingAdapter("title", "value", "tag", "tagColor", requireAll = false)
fun setPhoneKvItemAttrs(
item: PhoneKvItem,
title: String?,
value: String?,
tag: Boolean?,
tagColor: String?
) {
title?.let { item.title = it }
// tag 需先于 value 生效,确保样式切换后再填内容
// tag/tagColor 需先于 value 生效,确保样式切换后再填内容
tagColor?.let { item.tagColor = it }
tag?.let { item.tag = it }
item.value = value.orEmpty()
}

View 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_primary" />
</shape>

View 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_text_hint" />
</shape>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 手机版件数图标MDI package-variant-closed默认灰色可 tint -->
<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="#9CA3AF"
android:pathData="M21,16.5C21,16.88 20.79,17.21 20.47,17.38L12.57,21.82C12.41,21.94 12.21,22 12,22C11.79,22 11.59,21.94 11.43,21.82L3.53,17.38C3.21,17.21 3,16.88 3,16.5V7.5C3,7.12 3.21,6.79 3.53,6.62L11.43,2.18C11.59,2.06 11.79,2 12,2C12.21,2 12.41,2.06 12.57,2.18L20.47,6.62C20.79,6.79 21,7.12 21,7.5V16.5M12,4.15L10.11,5.22L16,8.61L17.96,7.5L12,4.15M6.04,7.5L12,10.85L13.96,9.75L8.08,6.35L6.04,7.5M5,15.91L11,19.29V12.58L5,9.21V15.91M19,15.91V9.21L13,12.58V19.29L19,15.91Z" />
</vector>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 手机版特码/标签图标MDI tag-outline默认灰色可 tint -->
<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="#9CA3AF"
android:pathData="M21.41,11.58L12.41,2.58C12.05,2.22 11.55,2 11,2H4C2.9,2 2,2.9 2,4V11C2,11.55 2.22,12.05 2.59,12.42L11.59,21.42C11.95,21.78 12.45,22 13,22C13.55,22 14.05,21.78 14.41,21.41L21.41,14.41C21.78,14.05 22,13.55 22,13C22,12.45 21.77,11.94 21.41,11.58M13,20L4,11V4H11L20,13M6.5,5C7.33,5 8,5.67 8,6.5C8,7.33 7.33,8 6.5,8C5.67,8 5,7.33 5,6.5C5,5.67 5.67,5 6.5,5Z" />
</vector>

View File

@@ -44,12 +44,24 @@
</FrameLayout>
<!-- 内容插槽:筛选条件项由使用方在 XML 中声明 -->
<LinearLayout
android:id="@+id/ll_content"
<!-- 内容插槽:筛选条件项由使用方在 XML 中声明
外包 ScrollView + weight=1筛选项少时行为不变wrap 高度),
筛选项多到超屏时内容区收缩滚动,保证底部「重置/确认」按钮始终可见
(出港查询 9 个筛选项时曾把按钮挤出屏幕) -->
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
android:layout_weight="1"
android:overScrollMode="never"
android:scrollbars="none">
<LinearLayout
android:id="@+id/ll_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</ScrollView>
<!-- 底部按钮行 -->
<LinearLayout