feat: 完成ULD管理页面5.5寸手机端适配

- 手机版列表(三色状态标签卡片 + 筛选弹层 + 浮动新增 + 全选/批量删除)、
  一套 activity_uld_edit 手机布局按 pageType 覆盖 ULD 新增/修改/详情三态
  (详情右上铅笔进修改、状态底部选择面板、所在港默认 HFE、手机端必填校验);
  平板布局迁至 layout-sw600dp,Kotlin 双端共用,平板端实机回归零变化
- 新增公共组件 PhoneFormRow(行式表单,INPUT/SELECT/DATE/TEXT 四形态,
  SELECT 内置底部选择面板);PhoneBottomBar 增加 actionDanger 危险按钮样式;
  新增 FAB/danger按钮/浅红标签/垃圾桶/铅笔等资源
- ULDBean 补解析接口既有出参 ifNo/efNo/checkInDate/checkOutDate 并预留 source;
  批量删除以队列串行调用单条 deleteUld 实现
- 手机首页「国际」Tab 接入 ULD管理入口(ARouter + ComprehensiveUld 权限),
  登录→菜单→页面全链路实机验证通过,方向无闪屏,crash=0
- 后端缺口 5 项(状态三态、来源字段、筛选入参、批量删除接口、字段语义)
  登记《后端接口对接问题清单.xlsx》#7~#11;skill 沉淀本次踩坑
  (FAB elevation 盖弹层、Spinner 异步回调竞态、登录哈希回填)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-29 16:30:42 +08:00
parent bbc29ca2e1
commit 5a019a55c4
33 changed files with 1848 additions and 422 deletions

View File

@@ -1,167 +1,267 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<!--
ULD新增 / 修改 / 详情 —— 手机版布局5.5 寸手持端,最小宽度 < 600dp 时生效)
平板版为同名文件 layout-sw600dp/activity_uld_edit.xmlPadDataLayoutNew 三列表单),
两者是同一布局的资源变体DataBinding 生成同一个 ActivityUldEditBinding 类。
变体之间必须满足:
· DataBinding 变量完全一致viewModel / activity
→ UldEditViewModel 的加载/保存逻辑全部复用,平板端行为不受影响
一套布局覆盖设计稿三个页面(标题由 Activity 按 pageType 设置):
· ULD新增Add :可编辑 + 底部保存;所在港默认 HFE、必填星编号/自重/入库时间)
· ULD修改Modify编号只读其余可编辑 + 底部保存
· ULD详情Details全只读右对齐 + 顶栏右侧铅笔进入修改 + 额外展示最大装载容积/最大载重
「来源」「状态三态(占用)」为后端暂不支持的设计稿要求,
已登记 documents/后端接口对接问题清单.xlsxUI 先行、后端补齐后自动生效。
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="com.lukouguoji.module_base.ui.weight.data.layout.DataLayoutType" />
<import type="android.view.View" />
<import type="com.lukouguoji.module_base.common.DetailsPageType" />
<import type="com.lukouguoji.module_base.ui.weight.phone.PhoneFormRowType" />
<variable
name="viewModel"
type="com.lukouguoji.aerologic.page.uld.edit.UldEditViewModel" />
<variable
name="activity"
type="com.lukouguoji.aerologic.page.uld.edit.UldEditActivity" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_f2"
android:background="@color/phone_page_bg"
android:orientation="vertical">
<include layout="@layout/title_tool_bar" />
<!-- 标题栏 + 详情态右侧铅笔(编辑入口) -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include layout="@layout/title_tool_bar" />
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="end"
android:onClick="@{()-> activity.onEditClick()}"
android:padding="14dp"
android:src="@drawable/ic_phone_edit"
android:visibility="@{viewModel.pageType == DetailsPageType.Details ? View.VISIBLE : View.GONE}" />
</FrameLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:fillViewport="true">
android:fillViewport="true"
android:overScrollMode="never">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="15dp">
android:padding="16dp">
<!-- ==================== 表单卡片 ==================== -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_white_radius_8"
android:background="@drawable/bg_phone_card"
android:orientation="vertical"
android:padding="15dp">
android:paddingHorizontal="16dp">
<!-- Row 1: ULD编号 / 状态 / 自重 -->
<!-- ULD编号新增可输修改/详情只读 -->
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
enable="@{viewModel.pageType == DetailsPageType.Add}"
hint='@{"请输入ULD编号"}'
required="@{viewModel.pageType == DetailsPageType.Add}"
title='@{"ULD编号"}'
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.INPUT}"
value="@={viewModel.uldBean.uld}" />
<!-- 状态:彩色标签 + 底部选择面板(详情态右对齐、无箭头) -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minHeight="54dp"
android:onClick="@{()-> activity.onStatusRowClick()}"
android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
<TextView
android:layout_width="110dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{viewModel.pageType == DetailsPageType.Add}"
hint='@{"请输入ULD编号"}'
title='@{"ULD编号"}'
titleLength="@{7}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.uldBean.uld}' />
android:text="状态"
android:textColor="@color/phone_text_label"
android:textSize="15sp" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
<!-- 详情态用这个占位把标签推到右侧 -->
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_height="1dp"
android:layout_weight="1"
enable="@{viewModel.pageType != DetailsPageType.Details}"
hint='@{"请选择状态"}'
list="@{viewModel.statusList}"
title='@{"状态"}'
titleLength="@{5}"
type="@{DataLayoutType.SPINNER}"
value='@={viewModel.uldBean.status}' />
android:visibility="@{viewModel.pageType == DetailsPageType.Details ? View.VISIBLE : View.GONE}" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
<TextView
android:layout_width="wrap_content"
android:layout_height="22dp"
android:background="@{viewModel.uldBean.status.empty ? null : (viewModel.uldBean.isStatusAvailable ? @drawable/bg_phone_tag_green : (viewModel.uldBean.isStatusOccupied ? @drawable/bg_phone_tag_orange : @drawable/bg_phone_tag_red_light))}"
android:gravity="center"
android:paddingHorizontal="8dp"
android:text='@{viewModel.uldBean.status.empty ? "请选择状态" : viewModel.uldBean.statusPhoneName}'
android:textColor="@{viewModel.uldBean.status.empty ? @color/phone_text_hint : (viewModel.uldBean.isStatusAvailable ? @color/phone_tag_green_text : (viewModel.uldBean.isStatusOccupied ? @color/phone_tag_orange_text : @color/phone_danger_text))}"
android:textSize="12sp" />
<!-- 编辑态右箭头 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{viewModel.pageType != DetailsPageType.Details}"
hint='@{"请输入自重"}'
title='@{"自重"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.uldBean.uldWeight}' />
android:gravity="end|center_vertical"
android:orientation="horizontal"
android:visibility="@{viewModel.pageType == DetailsPageType.Details ? View.GONE : View.VISIBLE}">
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@drawable/ic_phone_chevron_right" />
</LinearLayout>
</LinearLayout>
<!-- Row 2: 最大装载容积 / 最大载重 / 所属航司 -->
<LinearLayout
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/phone_divider" />
<!-- 所属航司 -->
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:orientation="horizontal">
enable="@{viewModel.pageType != DetailsPageType.Details}"
hint='@{"请选择所属航司"}'
list="@{viewModel.carrierList}"
title='@{"所属航司"}'
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.SELECT}"
value="@={viewModel.uldBean.carrier}" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{viewModel.pageType != DetailsPageType.Details}"
hint='@{"请输入最大装载容积"}'
title='@{"最大装载容积"}'
titleLength="@{7}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.uldBean.maxVolume}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{viewModel.pageType != DetailsPageType.Details}"
hint='@{"请输入最大载重"}'
title='@{"最大载重"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.uldBean.maxWeight}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{viewModel.pageType != DetailsPageType.Details}"
hint='@{"请选择所属航司"}'
list="@{viewModel.carrierList}"
title='@{"所属航司"}'
titleLength="@{5}"
type="@{DataLayoutType.SPINNER}"
value='@={viewModel.uldBean.carrier}' />
</LinearLayout>
<!-- 备注(全行,多行输入) -->
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
<!-- 来源(后端字段暂不支持,已登记清单;提交后端忽略) -->
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
enable="@{viewModel.pageType != DetailsPageType.Details}"
hint='@{"请选择来源"}'
list="@{viewModel.sourceEditList}"
title='@{"来源"}'
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.SELECT}"
value="@={viewModel.uldBean.source}" />
<!-- 自重(kg) -->
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
enable="@{viewModel.pageType != DetailsPageType.Details}"
hint='@{"请输入重"}'
numeric="@{true}"
required="@{viewModel.pageType == DetailsPageType.Add}"
title='@{"自重(kg)"}'
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.INPUT}"
value="@={viewModel.uldBean.uldWeight}" />
<!-- 最大装载容积(仅详情展示,与设计稿一致) -->
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
title='@{"最大装载容积(m³)"}'
type="@{PhoneFormRowType.TEXT}"
value="@{viewModel.uldBean.maxVolume}"
android:visibility="@{viewModel.pageType == DetailsPageType.Details ? View.VISIBLE : View.GONE}" />
<!-- 最大载重(仅详情展示,与设计稿一致) -->
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
title='@{"最大载重(kg)"}'
type="@{PhoneFormRowType.TEXT}"
value="@{viewModel.uldBean.maxWeight}"
android:visibility="@{viewModel.pageType == DetailsPageType.Details ? View.VISIBLE : View.GONE}" />
<!-- 进港航班号(绑 ifNo语义待后端确认已登记清单 -->
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
enable="@{viewModel.pageType != DetailsPageType.Details}"
hint='@{"请输入进港航班号"}'
title='@{"进港航班号"}'
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.INPUT}"
value="@={viewModel.uldBean.ifNo}" />
<!-- 所在港(新增默认 HFE由 ViewModel 手机开关预填) -->
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
enable="@{viewModel.pageType != DetailsPageType.Details}"
hint='@{"请输入所在港"}'
title='@{"所在港"}'
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.INPUT}"
value="@={viewModel.uldBean.airport}" />
<!-- 入库时间(绑 checkInDate筛选/格式语义待后端确认,已登记清单) -->
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
enable="@{viewModel.pageType != DetailsPageType.Details}"
hint='@{"请输入入库时间"}'
required="@{viewModel.pageType == DetailsPageType.Add}"
title='@{"入库时间"}'
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.DATE}"
value="@={viewModel.uldBean.checkInDate}" />
<!-- 备注 -->
<com.lukouguoji.module_base.ui.weight.phone.PhoneFormRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
enable="@{viewModel.pageType != DetailsPageType.Details}"
hint='@{"请输入备注"}'
inputHeight="@{80}"
title='@{"备注"}'
titleLength="@{7}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.uldBean.remark}' />
type="@{viewModel.pageType == DetailsPageType.Details ? PhoneFormRowType.TEXT : PhoneFormRowType.INPUT}"
value="@={viewModel.uldBean.remark}" />
</LinearLayout>
<!-- 底部操作按钮 -->
<LinearLayout
<!-- ==================== 保存按钮(详情态隐藏) ==================== -->
<TextView
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_height="48dp"
android:layout_marginTop="24dp"
android:background="@drawable/bg_phone_btn_primary"
android:gravity="center"
visible="@{viewModel.pageType != DetailsPageType.Details}">
<TextView
style="@style/tv_bottom_btn"
android:layout_width="120dp"
android:layout_marginEnd="20dp"
android:onClick="@{()-> viewModel.onCancelClick()}"
android:text="取消" />
<TextView
style="@style/tv_bottom_btn"
android:layout_width="120dp"
android:onClick="@{()-> viewModel.onSaveClick()}"
android:text="保存" />
</LinearLayout>
android:onClick="@{()-> viewModel.onSaveClick()}"
android:text="保存"
android:textColor="@color/white"
android:textSize="16sp"
android:textStyle="bold"
android:visibility="@{viewModel.pageType == DetailsPageType.Details ? View.GONE : View.VISIBLE}" />
</LinearLayout>
</ScrollView>
</LinearLayout>
</layout>