Compare commits

...

19 Commits

Author SHA1 Message Date
ea298ec322 feat: 开始计重新增托盘信息并自动计算运抵重量
国际出港开始计重页面新增托盘数量、托盘自重输入框(自重默认18可编辑),
运抵重量自动按“地磅称重 -(托盘数量 × 托盘自重)”计算;
分托计重与完成计重提交均携带 trayNumber、trayTotalWeight;
“托盘车号”“托盘车自重”标签改为“平板车”“平板车自重”。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-02 13:11:17 +08:00
b57a3cd133 fix: 计重明细托盘自重改取托盘重量并支持编辑联动
托盘自重原误取托盘车重(carWeight),改为托盘重量(trayTotalWeight)。
编辑模式下托盘自重可编辑,重量按编辑前后差值同步浮动,底部统计随之更新。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-02 11:59:13 +08:00
4e6e654558 feat: 国际出港运抵列表新增运抵状态筛选
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-02 11:34:46 +08:00
b65e61595b feat: 国际进港舱单编辑支持交接图片新增与删除
编辑/新增表单页增加交接图片区(选图、上传、长按删除),
保存时随舱单提交 pic/originalPic/picNumber 三字段,
编辑模式回填已有图片且不重复上传。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-02 11:23:43 +08:00
86f77353c0 feat: 国际出港板箱过磅通道号默认沿用上一次选择
称重提交成功后本地记住通道号,后续新增称重自动默认选中;
重置时不再清空通道号,编辑模式仍按记录自带通道号回填。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-02 10:44:31 +08:00
39b5cc3689 feat: 国际出港板箱过磅挂签支持多选批量打印
多选时逐张串行发送,张间节流留出出纸时间,写入失败即中止
并提示已打印张数与失败的 ULD 号;单选与详情页打印路径不变。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-02 10:44:25 +08:00
a1b55f656f feat: 航班管理列表新增增删改功能
- 列表页右上角新增加号入口,新增/编辑共用表单页(HbFlightEditActivity)
- 列表项支持侧滑编辑、删除,删除使用 ConfirmDialogModel 二次确认
- 接入 /flt/saveFlight、/flt/updateFlight、/flt/delete 接口
- 编辑回填增加枚举中文名转代码处理;FlightBean 地区类型兼容中文值显示

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-02 10:13:37 +08:00
13c9c6f5dc feat: 国际出港运抵计重状态改为海关放行
- 主单列表项第二行「计重状态」改为「海关放行」,取运抵分页接口
  返回的 cmdStatus,按普通文本显示,与查询详情页「海关指令」一致
- 展开的分单列表在「申报状态」与「品名(中)」之间新增「海关放行」列
- GjcMaWb 补充 cmdStatus 字段,此前仅 GjcHaWb 有该字段

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 17:27:31 +08:00
de62b903d4 feat: 国际出港板箱过磅新增耗材重量并计入货重
- 过磅表单新增只读的耗材重量,数据随列表项 Bean 带入,扫码新增时
  取 queryUsingUldByUld 返回的 consumeWeight
- 货重公式由「装机重 - ULD自重」改为「装机重 - ULD自重 - 耗材自重」
- queryUsingUldByUld 返回后补触发重量计算,此前该接口异步返回时
  耗材重量不会参与计算
- 表单保持每行三列:第三列自上而下为总重、装机重、耗材重量、货重,
  目的港单独占一行三分之一宽,备注换行整行撑满

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 17:12:21 +08:00
2d42ce9cc3 feat: 国际出港重量回填页改名并新增耗材重量
- 页面标题由「国际出港修改组装重量」改为「国际出港重量回填」
- ULD 信息卡片在货重之后新增耗材重量,取组装分页接口返回的
  consumeWeight 字段,数据随列表页传入的 Bean 一并带过来

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 16:46:01 +08:00
861ce8ca1e feat: 国际出港交接复磅状态改为 IMP 代码
列表项第二行第三列由「复磅状态」改为「IMP 代码」,取交接分页接口
返回的 dgrCode 字段;值非空且不等于 ELI、ELM 时以红色显示,
空值与 ELI、ELM 保持常规颜色。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 16:31:27 +08:00
f312ef866c feat: 国际进港舱单新增开始理货按钮
- 底部「货物发放」改名为「理货完成」,「分拣理货」改名为「装机单」
- 新增蓝色「开始理货」按钮,选中唯一一条运单后弹出修改库位对话框,
  提交 /IntImpManifest/modifyStorage
- 弹窗默认回填该运单已有的理货库位:舱单列表接口不返回 locationTally,
  改为先按 fid + wbNo 查一次装机单记录取出库位再回填
- GjjManifest 补充 locationTallyId 字段
- 装机单列表项运单号、品名列 completeSpace 调整为 5 以对齐

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 16:19:47 +08:00
6f27c15d9a fix: 修复国际进港出库运单号搜索不生效
运单号原本传给了 no 参数,但接口中 no 是不含前缀的主单号
(如 33362265),wbNo 才是完整 11 位运单号,导致条件被忽略。
同模块提取记录、进港查询用的均为 wbNo,此处保持一致。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 15:08:04 +08:00
ded57554fa feat: 国际出港查询新增日期类型与航班航次统计
- 合计栏在总重量后追加航班航次(取统计接口 flightNumber)
- 日期范围前新增日期类型下拉(入库/离港),对应接口 dateState 参数
- 航班号从筛选弹框移至列表上方,出库状态移入筛选弹框
- dateState、outState 按接口文档改为整型传参

原航班号查询无效的原因并非参数名有误(fno 与文档一致),
而是缺少 dateState 导致后端按默认日期口径过滤,补齐后已实测生效。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 14:49:46 +08:00
2f3ae2a814 feat: 国际进港查询统计新增航班航次并调整筛选条件布局
- 底部统计栏在总重量后新增航班航次显示
- 航班号从筛选面板移至页面上方搜索区,出库状态移入筛选面板
- 筛选红点提示与重置逻辑同步调整字段归属

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-08-27 17:08:47 +08:00
19d02700b8 feat: 国际出港仓库清仓弹窗增加备注输入框
清仓操作弹窗在「清仓正常」下拉基础上新增选填备注,提交时随 clearRemark 字段传给 updateClear 接口

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-08-27 16:41:49 +08:00
aa6cc43bfa feat: 国际事故签证新增支持运单号联想并自动带出舱单信息
- 运单号输入启用自动联想(1条自动填充、多条弹窗选择)
- 运单号满11位自动查询进港舱单,带出航班日期、航班号、始发/目的站、总件数、总重量、品名及交接图片
- 仅新增模式触发带出,避免编辑模式覆盖已保存数据和图片

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-08-27 16:31:16 +08:00
dcb335ecdf feat: ULD新增编辑表单增加来源、入库时间、所在港字段
- 编辑表单新增来源(空运/陆运)、入库时间、所在港(默认HFE)三个字段
- 列表项同步显示来源、所在港、位置、入库时间,去掉备注展示并收窄首列
- PadDataLayoutNew 新增 DATETIME 类型,支持年月日时分秒选择

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-08-27 15:30:23 +08:00
567b76014b fix: 国内进港卸机相关页面标题去掉"国内"二字
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-08-06 10:35:36 +08:00
62 changed files with 1798 additions and 190 deletions

View File

@@ -19,7 +19,7 @@ class GnjUnloadAddActivity :
override fun viewModelClass() = GnjUnloadAddViewModel::class.java override fun viewModelClass() = GnjUnloadAddViewModel::class.java
override fun initOnCreate(savedInstanceState: Bundle?) { override fun initOnCreate(savedInstanceState: Bundle?) {
setBackArrow("国内进港开始卸机") setBackArrow("进港开始卸机")
binding.viewModel = viewModel binding.viewModel = viewModel
viewModel.rv = binding.rv viewModel.rv = binding.rv

View File

@@ -24,7 +24,7 @@ class GnjUnloadListActivity :
} }
override fun initOnCreate(savedInstanceState: Bundle?) { override fun initOnCreate(savedInstanceState: Bundle?) {
setBackArrow("国内进港卸机") setBackArrow("进港卸机")
binding.viewModel = viewModel binding.viewModel = viewModel
viewModel.pageModel.bindSmartRefreshLayout( viewModel.pageModel.bindSmartRefreshLayout(
binding.srl, binding.srl,

View File

@@ -30,6 +30,14 @@ class UldEditViewModel : BaseViewModel() {
) )
) )
// 来源下拉列表
val sourceList = MutableLiveData<List<KeyValue>>(
listOf(
KeyValue("空运", "空运"),
KeyValue("陆运", "陆运"),
)
)
// 所属航司下拉列表数据源POST /typeCode/intCarrier // 所属航司下拉列表数据源POST /typeCode/intCarrier
val carrierList = MutableLiveData<List<KeyValue>>(emptyList()) val carrierList = MutableLiveData<List<KeyValue>>(emptyList())
@@ -40,7 +48,8 @@ class UldEditViewModel : BaseViewModel() {
else if (modify) DetailsPageType.Modify else DetailsPageType.Details else if (modify) DetailsPageType.Modify else DetailsPageType.Details
if (id.isEmpty()) { if (id.isEmpty()) {
// 新增:直接加载航司列表 // 新增:所在港默认 HFE直接加载航司列表
uldBean.value = ULDBean(nowPort = "HFE")
loadCarrierList(null) loadCarrierList(null)
} else { } else {
getData() getData()
@@ -79,7 +88,7 @@ class UldEditViewModel : BaseViewModel() {
}) { }) {
onSuccess = { onSuccess = {
showToast(it.msg.noNull(if (isAdd) "新增成功" else "修改成功")) showToast(it.msg.noNull(if (isAdd) "新增成功" else "修改成功"))
if (isAdd) uldBean.value = ULDBean() else getData() if (isAdd) uldBean.value = ULDBean(nowPort = "HFE") else getData()
} }
} }
} }

View File

@@ -121,6 +121,49 @@
</LinearLayout> </LinearLayout>
<!-- Row 3: 来源 / 入库时间 / 所在港 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{viewModel.pageType != DetailsPageType.Details}"
hint='@{"请选择来源"}'
list="@{viewModel.sourceList}"
title='@{"来源"}'
titleLength="@{7}"
type="@{DataLayoutType.SPINNER}"
value='@={viewModel.uldBean.source}' />
<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.DATETIME}"
value='@={viewModel.uldBean.inStoreTime}' />
<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.nowPort}' />
</LinearLayout>
<!-- 备注(全行,多行输入) --> <!-- 备注(全行,多行输入) -->
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew <com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@@ -55,7 +55,7 @@
<androidx.appcompat.widget.LinearLayoutCompat <androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1.5" android:layout_weight="1.0"
android:gravity="center_vertical"> android:gravity="center_vertical">
<TextView <TextView
@@ -109,7 +109,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="自重:" android:text="自重:"
android:textSize="15sp" android:textSize="15sp"
completeSpace="@{3}" /> completeSpace="@{4}" />
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
@@ -165,7 +165,7 @@
</androidx.appcompat.widget.LinearLayoutCompat> </androidx.appcompat.widget.LinearLayoutCompat>
<!-- 第二行:最大载重 | 备注 --> <!-- 第二行:最大载重 | 来源 | 所在港 | 位置 | 入库时间 -->
<androidx.appcompat.widget.LinearLayoutCompat <androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -175,7 +175,7 @@
<androidx.appcompat.widget.LinearLayoutCompat <androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1.5" android:layout_weight="1.0"
android:gravity="center_vertical"> android:gravity="center_vertical">
<TextView <TextView
@@ -193,24 +193,90 @@
</androidx.appcompat.widget.LinearLayoutCompat> </androidx.appcompat.widget.LinearLayoutCompat>
<!-- 备注 --> <!-- 来源 -->
<androidx.appcompat.widget.LinearLayoutCompat <androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="3.6" android:layout_weight="0.8"
android:gravity="center_vertical"> android:gravity="center_vertical">
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="备注" android:text="来源"
android:textSize="15sp" android:textSize="15sp"
completeSpace="@{3}" /> completeSpace="@{3}" />
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@{bean.remark}" android:text="@{bean.source}"
android:textSize="15sp" />
</androidx.appcompat.widget.LinearLayoutCompat>
<!-- 所在港 -->
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="所在港:"
android:textSize="15sp"
completeSpace="@{4}" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{bean.nowPort}"
android:textSize="15sp" />
</androidx.appcompat.widget.LinearLayoutCompat>
<!-- 位置 -->
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="位置:"
android:textSize="15sp"
completeSpace="@{5}" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{bean.nowPosition}"
android:textSize="15sp" />
</androidx.appcompat.widget.LinearLayoutCompat>
<!-- 入库时间 -->
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.2"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="入库时间:"
android:textSize="15sp"
completeSpace="@{7}" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{bean.inStoreTime}"
android:textSize="15sp" /> android:textSize="15sp" />
</androidx.appcompat.widget.LinearLayoutCompat> </androidx.appcompat.widget.LinearLayoutCompat>

View File

@@ -234,7 +234,10 @@ class FlightBean : ICheck {
return when (countryType) { return when (countryType) {
"0" -> "国内" "0" -> "国内"
"1" -> "国际" "1" -> "国际"
else -> "" "2" -> "地区"
"3" -> "混合"
// 部分接口直接返回中文名,原样显示
else -> countryType
} }
} }

View File

@@ -22,7 +22,9 @@ data class GjcCheckInRecord(
var weight: Double = 0.0, // 运抵重量 var weight: Double = 0.0, // 运抵重量
var volume: Double = 0.0, // 运抵体积 var volume: Double = 0.0, // 运抵体积
var whId: Long = 0, // GJC_WAREHOUSE.ID var whId: Long = 0, // GJC_WAREHOUSE.ID
var carWeight: String = "" // 托盘 var carWeight: String = "", // 托盘
var trayNumber: Int = 0, // 托盘数量
var trayTotalWeight: Double = 0.0 // 托盘重量(托盘自重)
) : BaseObservable() { ) : BaseObservable() {
// 数据变化回调 // 数据变化回调
@@ -53,4 +55,28 @@ data class GjcCheckInRecord(
onDataChanged?.invoke() onDataChanged?.invoke()
} }
} }
// 托盘自重编辑过程中的原始输入串(保持回显与输入一致,避免光标跳位)
// 不作为构造参数data class copy 备份/恢复时自动丢弃,回退到 trayTotalWeight 显示
// @Transient仅界面内部状态不参与 Gson 序列化提交
@Transient
private var trayTotalWeightInput: String? = null
// 托盘自重的字符串表示(用于双向绑定)
// 业务规则:重量包含托盘自重,托盘自重编辑后,重量同步增减相同差值
@get:Bindable
var trayTotalWeightStr: String
get() = trayTotalWeightInput
?: if (trayTotalWeight == 0.0) "" else trayTotalWeight.toString()
set(value) {
trayTotalWeightInput = value
val newTrayWeight = value.toDoubleOrNull() ?: 0.0
if (trayTotalWeight != newTrayWeight) {
weight = Math.round((weight + newTrayWeight - trayTotalWeight) * 100) / 100.0
trayTotalWeight = newTrayWeight
notifyPropertyChanged(BR.trayTotalWeightStr)
notifyPropertyChanged(BR.weightStr)
onDataChanged?.invoke()
}
}
} }

View File

@@ -57,6 +57,8 @@ data class GjcMaWb(
var arriveWeight: Double? = null, // 运抵重量 var arriveWeight: Double? = null, // 运抵重量
var arriveVolume: Double? = null, // 运抵体积 var arriveVolume: Double? = null, // 运抵体积
var arriveFlag: String? = null, // 运抵状态0正常运抵1提前运抵 var arriveFlag: String? = null, // 运抵状态0正常运抵1提前运抵
var trayNumber: Int? = null, // 托盘数量
var trayTotalWeight: Double? = null, // 托盘重量(托盘数量 × 托盘自重)
// ==================== 特码与收货人 ==================== // ==================== 特码与收货人 ====================
var spCode: String? = null, // 特码 var spCode: String? = null, // 特码
@@ -79,6 +81,7 @@ data class GjcMaWb(
// ==================== 状态信息 ==================== // ==================== 状态信息 ====================
var checkIn: String? = null, // 收运状态。0待收运1已收运2收运中 var checkIn: String? = null, // 收运状态。0待收运1已收运2收运中
var declareStatus: String? = null, // 申报状态 var declareStatus: String? = null, // 申报状态
var cmdStatus: String? = null, // 海关放行(命令状态)
var reviewStatus: String? = null, // 审核状态0未审核1通过2退回 var reviewStatus: String? = null, // 审核状态0未审核1通过2退回
var tranFlag: String? = null, // 转运标志 var tranFlag: String? = null, // 转运标志
var clearNormal: String? = null, // 清仓正常01 var clearNormal: String? = null, // 清仓正常01

View File

@@ -12,6 +12,8 @@ data class GjjManifest(
var no: String = "", // 编号 var no: String = "", // 编号
var prefix: String = "", // 前缀 var prefix: String = "", // 前缀
var wbNo: String = "", // 运单号 var wbNo: String = "", // 运单号
var fdate: String = "", // 航班日期
var fno: String = "", // 航班号
var origin: String = "", // 货源地(始发站) var origin: String = "", // 货源地(始发站)
var dest: String = "", // 目的站 var dest: String = "", // 目的站
var fdep: String = "", // 航班起始站 var fdep: String = "", // 航班起始站
@@ -58,6 +60,7 @@ data class GjjManifest(
var unNumber: String = "", // 危险品编号 var unNumber: String = "", // 危险品编号
var activeId: Long = 0, // 活动ID var activeId: Long = 0, // 活动ID
var locationTally: String = "", // 理货库位号 var locationTally: String = "", // 理货库位号
var locationTallyId: Long = 0, // 理货库位ID
var pic: String = "", // 交接图片缩略图路径 var pic: String = "", // 交接图片缩略图路径
var originalPic: String = "", // 交接图片原图地址 var originalPic: String = "", // 交接图片原图地址
var picNumber: String = "" // 交接图片数量 var picNumber: String = "" // 交接图片数量

View File

@@ -8,5 +8,6 @@ data class ManifestTotalDto(
var wbNumber: Int = 0, // 运单票数/总票数 var wbNumber: Int = 0, // 运单票数/总票数
var totalPc: Long = 0, // 总件数 var totalPc: Long = 0, // 总件数
var totalWeight: Double = 0.0, // 总重量 var totalWeight: Double = 0.0, // 总重量
var cargoWeight: Double = 0.0 // 总货重 var cargoWeight: Double = 0.0, // 总货重
var flightNumber: Int = 0 // 航班航次
) )

View File

@@ -19,6 +19,14 @@ data class ULDBean(
var status: String = "", var status: String = "",
// 备注 // 备注
var remark: String = "", var remark: String = "",
// 来源(空运、陆运)
var source: String = "",
// 入库时间 yyyy-MM-dd HH:mm:ss
var inStoreTime: String = "",
// 所在港
var nowPort: String = "",
// 位置信息
var nowPosition: String = "",
){ ){
val checked = ObservableBoolean(false) val checked = ObservableBoolean(false)

View File

@@ -1391,6 +1391,24 @@ interface Api {
@POST("flt/listFlightDest") @POST("flt/listFlightDest")
suspend fun listFlightDest(@Body data: RequestBody): BaseResultBean<List<String>> suspend fun listFlightDest(@Body data: RequestBody): BaseResultBean<List<String>>
/**
* 航班管理-新增航班
*/
@POST("flt/saveFlight")
suspend fun saveFlight(@Body data: RequestBody): BaseResultBean<String>
/**
* 航班管理-修改航班
*/
@POST("flt/updateFlight")
suspend fun updateFlight(@Body data: RequestBody): BaseResultBean<String>
/**
* 航班管理-删除航班(请求体为航班对象数组)
*/
@POST("flt/delete")
suspend fun deleteFlightList(@Body data: RequestBody): BaseResultBean<String>
/** /**
* 新增或修航司屏蔽 * 新增或修航司屏蔽
*/ */
@@ -1891,6 +1909,14 @@ interface Api {
@POST("IntImpManifest/pageQueryTotal") @POST("IntImpManifest/pageQueryTotal")
suspend fun getIntImpManifestTotal(@Body data: RequestBody): BaseResultBean<ManifestTotalDto> suspend fun getIntImpManifestTotal(@Body data: RequestBody): BaseResultBean<ManifestTotalDto>
/**
* 国际进港舱单-根据11位具体运单号查询运单信息
* 接口路径: /IntImpManifest/queryWbByNo
* @param wbNo 11位运单号
*/
@POST("IntImpManifest/queryWbByNo")
suspend fun getIntImpManifestByWbNo(@Query("wbNo") wbNo: String): BaseResultBean<GjjManifest>
/** /**
* 国际进港舱单-获取主单下分单 * 国际进港舱单-获取主单下分单
*/ */

View File

@@ -211,7 +211,7 @@ class PadDataLayout : FrameLayout {
setOnClickListener(null) setOnClickListener(null)
} }
DataLayoutType.DATE -> { DataLayoutType.DATE, DataLayoutType.DATETIME -> {
tv.visibility = VISIBLE tv.visibility = VISIBLE
et.visibility = GONE et.visibility = GONE
spinner.visibility = GONE spinner.visibility = GONE
@@ -258,4 +258,5 @@ enum class DataLayoutType {
INPUT, // 文本 INPUT, // 文本
SPINNER, // 下拉选择 SPINNER, // 下拉选择
DATE, // 日期 DATE, // 日期
DATETIME, // 日期时间yyyy-MM-dd HH:mm:ss
} }

View File

@@ -25,6 +25,7 @@ import com.lukouguoji.module_base.adapter.visible
import com.lukouguoji.module_base.interfaces.IOnFocusChangeListener import com.lukouguoji.module_base.interfaces.IOnFocusChangeListener
import com.lukouguoji.module_base.interfaces.IOnSpinnerSelected import com.lukouguoji.module_base.interfaces.IOnSpinnerSelected
import com.lukouguoji.module_base.ktx.formatDate import com.lukouguoji.module_base.ktx.formatDate
import com.lukouguoji.module_base.ktx.formatDateTime
import com.lukouguoji.module_base.ktx.getActivity import com.lukouguoji.module_base.ktx.getActivity
import com.lukouguoji.module_base.ktx.loge import com.lukouguoji.module_base.ktx.loge
import com.lukouguoji.module_base.util.Common import com.lukouguoji.module_base.util.Common
@@ -182,6 +183,18 @@ class PadDataLayoutNew : FrameLayout {
} }
} }
// 选择日期时间yyyy-MM-dd HH:mm:ss
private val dateTimeClick: (v: View) -> Unit = {
if (enable) {
Common.onYearMonthDayTime(context.getActivity(), value) { year, month, day, hour, minute, second ->
val calendar = Calendar.getInstance()
calendar.set(year, month - 1, day, hour, minute, second)
value = calendar.time.formatDateTime()
refreshCallBack?.invoke()
}
}
}
init { init {
initView() initView()
} }
@@ -252,7 +265,7 @@ class PadDataLayoutNew : FrameLayout {
setOnClickListener(null) setOnClickListener(null)
} }
DataLayoutType.DATE -> { DataLayoutType.DATE, DataLayoutType.DATETIME -> {
tv.visibility = VISIBLE tv.visibility = VISIBLE
et.visibility = GONE et.visibility = GONE
spinner.visibility = GONE spinner.visibility = GONE
@@ -263,7 +276,7 @@ class PadDataLayoutNew : FrameLayout {
iv.layoutParams.width = dp20 iv.layoutParams.width = dp20
iv.layoutParams.height = dp20 iv.layoutParams.height = dp20
setOnClickListener(dateClick) setOnClickListener(if (type == DataLayoutType.DATETIME) dateTimeClick else dateClick)
} }
} }
} }

View File

@@ -27,7 +27,12 @@ import com.lukouguoji.module_base.ktx.permission
import com.lukouguoji.module_base.ktx.showToast import com.lukouguoji.module_base.ktx.showToast
import com.lukouguoji.module_base.model.LoadingModel import com.lukouguoji.module_base.model.LoadingModel
import dev.DevUtils import dev.DevUtils
import dev.utils.app.HandlerUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
import okio.internal.commonToUtf8String import okio.internal.commonToUtf8String
import java.io.IOException
object PrinterUtils { object PrinterUtils {
@@ -315,6 +320,50 @@ object PrinterUtils {
* 打印国际出港板箱过磅挂签2列布局支持合并单元格 * 打印国际出港板箱过磅挂签2列布局支持合并单元格
*/ */
fun printGjcBoxWeighing(bean: GjcUldUseBean) { fun printGjcBoxWeighing(bean: GjcUldUseBean) {
printMergedGrid(buildGjcBoxWeighingRows(bean))
}
/**
* 批量打印国际出港板箱过磅挂签
* 逐张串行发送,张间节流,任一张发送失败即中止并提示已完成张数
*/
suspend fun printGjcBoxWeighingBatch(beans: List<GjcUldUseBean>) = withContext(Dispatchers.IO) {
var printed = 0
loading.showLoading()
try {
for ((index, bean) in beans.withIndex()) {
// 连接断开(含上一张写入异常后 SDK 置为断开)则不再继续发送
if (portManager?.connectStatus != true) break
HandlerUtils.postRunnable {
loading.setMessage("正在打印 ${index + 1}/${beans.size}")
}
val bytes = buildMergedGridBytes(buildGjcBoxWeighingRows(bean))
val ok = try {
portManager?.writeDataImmediately(bytes) == true
} catch (e: IOException) {
showLog("批量打印第 ${index + 1} 张写入异常 : ${e.message}")
false
}
if (!ok) break
printed++
// 张间留出出纸时间,避免连续灌入导致打印机缓冲溢出
if (index < beans.lastIndex) delay(800)
}
} finally {
loading.dismissLoading()
}
if (printed == beans.size) {
showToast("${beans.size} 张挂签打印完成")
} else {
val failBean = beans[printed]
showToast("已打印 $printed 张,第 ${printed + 1}ULD ${failBean.uld})发送失败,请检查打印机后重试")
}
}
/**
* 组装板箱过磅挂签的表格行数据
*/
private fun buildGjcBoxWeighingRows(bean: GjcUldUseBean): ArrayList<GridRow> {
val rows = arrayListOf<GridRow>() val rows = arrayListOf<GridRow>()
// 第1行日期 | 航班号 // 第1行日期 | 航班号
@@ -345,7 +394,7 @@ object PrinterUtils {
merged = CellData("备注:", "NOTES:", bean.remark) merged = CellData("备注:", "NOTES:", bean.remark)
)) ))
printMergedGrid(rows) return rows
} }
private fun printCommonGrid(rowItem: ArrayList<List<String>>) { private fun printCommonGrid(rowItem: ArrayList<List<String>>) {
@@ -456,6 +505,13 @@ object PrinterUtils {
* 打印支持合并单元格的表格 * 打印支持合并单元格的表格
*/ */
private fun printMergedGrid(rows: ArrayList<GridRow>) { private fun printMergedGrid(rows: ArrayList<GridRow>) {
portManager?.writeDataImmediately(buildMergedGridBytes(rows))
}
/**
* 生成支持合并单元格的表格标签字节流(自包含一张完整标签的 TSPL 指令)
*/
private fun buildMergedGridBytes(rows: ArrayList<GridRow>): ByteArray {
val gridStartX = 30 val gridStartX = 30
val titleTopMargin = 50 // 标题顶部间距 val titleTopMargin = 50 // 标题顶部间距
val titleFontSize = 130 // 标题字体大小 val titleFontSize = 130 // 标题字体大小
@@ -536,7 +592,7 @@ object PrinterUtils {
addPrint(1) addPrint(1)
}.bytes }.bytes
portManager?.writeDataImmediately(bytes) return bytes
} }
/** /**

View File

@@ -30,7 +30,7 @@ class GjcAssembleWeightEditActivity :
override fun viewModelClass() = GjcAssembleWeightEditViewModel::class.java override fun viewModelClass() = GjcAssembleWeightEditViewModel::class.java
override fun initOnCreate(savedInstanceState: Bundle?) { override fun initOnCreate(savedInstanceState: Bundle?) {
setBackArrow("国际出港修改组装重量") setBackArrow("国际出港重量回填")
binding.viewModel = viewModel binding.viewModel = viewModel

View File

@@ -54,7 +54,7 @@ class GjcQueryActivity :
} }
// 航班号:大写字母+数字 // 航班号:大写字母+数字
binding.filterPanel.filterFlightNo.et.setUpperCaseAlphanumericFilter() binding.flightNoSearch.et.setUpperCaseAlphanumericFilter()
// 目的港:仅大写字母 // 目的港:仅大写字母
binding.filterPanel.filterDest.et.setUpperCaseLetterFilter() binding.filterPanel.filterDest.et.setUpperCaseLetterFilter()

View File

@@ -79,7 +79,8 @@ class IntExpStorageUseActivity :
IntExpMoveClearDialogModel { dialog -> IntExpMoveClearDialogModel { dialog ->
// 用户点击保存后,执行清仓操作 // 用户点击保存后,执行清仓操作
val clearNormal = dialog.clearNormal.value ?: "" val clearNormal = dialog.clearNormal.value ?: ""
viewModel.performClear(clearNormal, maWbListForClear) val clearRemark = dialog.clearRemark.value ?: ""
viewModel.performClear(clearNormal, clearRemark, maWbListForClear)
}.show(this) }.show(this)
} }

View File

@@ -18,6 +18,9 @@ class IntExpMoveClearDialogModel(
// 清仓正常(存储的是 code"0" 或 "1" // 清仓正常(存储的是 code"0" 或 "1"
val clearNormal = MutableLiveData("") val clearNormal = MutableLiveData("")
// 清仓备注(选填)
val clearRemark = MutableLiveData("")
// 清仓正常选项列表 // 清仓正常选项列表
val clearNormalList = MutableLiveData<List<KeyValue>>().apply { val clearNormalList = MutableLiveData<List<KeyValue>>().apply {
value = listOf( value = listOf(

View File

@@ -38,6 +38,7 @@ class GjcAssembleWeightEditViewModel : BaseViewModel() {
val totalPc = MutableLiveData("") // 总件数 val totalPc = MutableLiveData("") // 总件数
val totalWeight = MutableLiveData("") // 总重量 val totalWeight = MutableLiveData("") // 总重量
val cargoWeight = MutableLiveData("") // 货重 val cargoWeight = MutableLiveData("") // 货重
val consumeWeight = MutableLiveData("") // 耗材重量
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// 底部统计字段 // 底部统计字段
@@ -74,6 +75,7 @@ class GjcAssembleWeightEditViewModel : BaseViewModel() {
totalPc.value = it.pc.toString() totalPc.value = it.pc.toString()
totalWeight.value = it.totalWeight.toString() totalWeight.value = it.totalWeight.toString()
cargoWeight.value = it.cargoWeight.toString() cargoWeight.value = it.cargoWeight.toString()
consumeWeight.value = it.consumeWeight.toString()
// 保存参数用于API调用 // 保存参数用于API调用
useId = it.useId useId = it.useId

View File

@@ -20,6 +20,7 @@ import com.lukouguoji.module_base.ktx.noNull
import com.lukouguoji.module_base.ktx.showToast import com.lukouguoji.module_base.ktx.showToast
import com.lukouguoji.module_base.ktx.toRequestBody import com.lukouguoji.module_base.ktx.toRequestBody
import com.lukouguoji.module_base.ktx.verifyNullOrEmpty import com.lukouguoji.module_base.ktx.verifyNullOrEmpty
import com.lukouguoji.module_base.db.perference.SharedPreferenceUtil
import com.lukouguoji.module_base.model.BluetoothDialogModel import com.lukouguoji.module_base.model.BluetoothDialogModel
import com.lukouguoji.module_base.model.ScanModel import com.lukouguoji.module_base.model.ScanModel
import com.lukouguoji.module_base.util.Common import com.lukouguoji.module_base.util.Common
@@ -34,6 +35,11 @@ import java.util.Date
*/ */
class GjcBoxWeighingAddViewModel : BaseViewModel() { class GjcBoxWeighingAddViewModel : BaseViewModel() {
companion object {
// 记录上一次称重完成时使用的通道号,后续称重默认选中
private const val KEY_LAST_PASSAGEWAY_ID = "gjc_box_weighing_last_passageway_id"
}
// 数据Bean // 数据Bean
val dataBean = MutableLiveData(GjcUldUseBean()) val dataBean = MutableLiveData(GjcUldUseBean())
@@ -51,6 +57,7 @@ class GjcBoxWeighingAddViewModel : BaseViewModel() {
val totalWeight = MutableLiveData("0") // 总重(红色) val totalWeight = MutableLiveData("0") // 总重(红色)
val netWeight = MutableLiveData("0") // 装机重(蓝色) val netWeight = MutableLiveData("0") // 装机重(蓝色)
val cargoWeight = MutableLiveData("0") // 货重(绿色) val cargoWeight = MutableLiveData("0") // 货重(绿色)
val consumeWeight = MutableLiveData("0") // 耗材重量(只读,随 ULD 记录带出)
// 需要自动查询的独立字段(用于监听输入变化) // 需要自动查询的独立字段(用于监听输入变化)
val carId = MutableLiveData("") // 架子车号 val carId = MutableLiveData("") // 架子车号
@@ -116,7 +123,9 @@ class GjcBoxWeighingAddViewModel : BaseViewModel() {
loadPassagewayList(editBean.passagewayId) loadPassagewayList(editBean.passagewayId)
loadPlCloseList(editBean.plClose) loadPlCloseList(editBean.plClose)
} else { } else {
loadPassagewayList(null) // 新增模式:默认选中上一次称重使用的通道号
val lastPassagewayId = SharedPreferenceUtil.getString(KEY_LAST_PASSAGEWAY_ID)
loadPassagewayList(lastPassagewayId.ifEmpty { null })
loadPlCloseList(null) loadPlCloseList(null)
} }
} }
@@ -138,6 +147,7 @@ class GjcBoxWeighingAddViewModel : BaseViewModel() {
totalWeight.value = bean.totalWeight.toString() totalWeight.value = bean.totalWeight.toString()
netWeight.value = bean.netWeight.toString() netWeight.value = bean.netWeight.toString()
cargoWeight.value = bean.cargoWeight.toString() cargoWeight.value = bean.cargoWeight.toString()
consumeWeight.value = bean.consumeWeight.toString()
diBangWeight.value = bean.totalWeight.toString() diBangWeight.value = bean.totalWeight.toString()
// 通道号 Spinner 绑定到 channelKeyValue.value 即 passagewayId // 通道号 Spinner 绑定到 channelKeyValue.value 即 passagewayId
@@ -273,15 +283,16 @@ class GjcBoxWeighingAddViewModel : BaseViewModel() {
/** /**
* 计算重量字段 * 计算重量字段
* 装机重 = 总重 - 架子车自重 * 装机重 = 总重 - 架子车自重
* 货重 = 装机重 - ULD自重 * 货重 = 装机重 - ULD自重 - 耗材自重
*/ */
private fun calculateWeights() { private fun calculateWeights() {
val total = totalWeight.value?.toDoubleOrNull() ?: 0.0 val total = totalWeight.value?.toDoubleOrNull() ?: 0.0
val carW = dataBean.value?.carWeight ?: 0.0 val carW = dataBean.value?.carWeight ?: 0.0
val uldW = dataBean.value?.uldWeight ?: 0.0 val uldW = dataBean.value?.uldWeight ?: 0.0
val consumeW = consumeWeight.value?.toDoubleOrNull() ?: 0.0
val net = total - carW val net = total - carW
val cargo = net - uldW val cargo = net - uldW - consumeW
netWeight.value = if (net > 0) net.toString() else "0" netWeight.value = if (net > 0) net.toString() else "0"
cargoWeight.value = if (cargo > 0) cargo.toString() else "0" cargoWeight.value = if (cargo > 0) cargo.toString() else "0"
@@ -334,7 +345,8 @@ class GjcBoxWeighingAddViewModel : BaseViewModel() {
totalWeight.value = "0" totalWeight.value = "0"
netWeight.value = "0" netWeight.value = "0"
cargoWeight.value = "0" cargoWeight.value = "0"
channel.value = "" consumeWeight.value = "0"
// 通道号不清空:保留当前选择,与 Spinner 显示保持一致,后续称重沿用上一次的通道号
printTag.value = false printTag.value = false
// 重置独立字段 // 重置独立字段
@@ -437,6 +449,11 @@ class GjcBoxWeighingAddViewModel : BaseViewModel() {
if (result.verifySuccess()) { if (result.verifySuccess()) {
showToast("完成复磅") showToast("完成复磅")
// 记住本次使用的通道号,后续称重默认选中
if (bean.passagewayId.isNotEmpty()) {
SharedPreferenceUtil.addString(KEY_LAST_PASSAGEWAY_ID, bean.passagewayId)
}
// 如果勾选了打印挂签,则执行打印 // 如果勾选了打印挂签,则执行打印
if (printTag.value == true) { if (printTag.value == true) {
executePrint() executePrint()
@@ -519,6 +536,9 @@ class GjcBoxWeighingAddViewModel : BaseViewModel() {
if (usingData != null && usingData.useId > 0) { if (usingData != null && usingData.useId > 0) {
// 保存返回的数据,用于提交时传递 // 保存返回的数据,用于提交时传递
usingUldData = usingData usingUldData = usingData
// 耗材重量随该记录带回,需要重新参与货重计算
consumeWeight.value = usingData.consumeWeight.toString()
calculateWeights()
} else { } else {
// 没有 useId说明未组装不可复磅 // 没有 useId说明未组装不可复磅
usingUldData = null usingUldData = null

View File

@@ -3,6 +3,7 @@ package com.lukouguoji.gjc.viewModel
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.lukouguoji.gjc.R import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.holder.GjcBoxWeighingViewHolder import com.lukouguoji.gjc.holder.GjcBoxWeighingViewHolder
import com.lukouguoji.module_base.base.BasePageViewModel import com.lukouguoji.module_base.base.BasePageViewModel
@@ -20,6 +21,7 @@ import com.lukouguoji.module_base.util.PrinterUtils
import dev.utils.app.info.KeyValue import dev.utils.app.info.KeyValue
import dev.utils.common.DateUtils import dev.utils.common.DateUtils
import com.lukouguoji.module_base.ktx.formatDate import com.lukouguoji.module_base.ktx.formatDate
import kotlinx.coroutines.launch
/** /**
* 国际出港板箱过磅 ViewModel * 国际出港板箱过磅 ViewModel
@@ -96,17 +98,20 @@ class GjcBoxWeighingViewModel : BasePageViewModel() {
return return
} }
// 校验多选 if (selectedItems.size == 1) {
if (selectedItems.size > 1) { // 单条:保持原有打印路径
showToast("只能选择一条记录进行打印")
return
}
// 执行打印
val bean = selectedItems.first() val bean = selectedItems.first()
BluetoothDialogModel().showCallBack { BluetoothDialogModel().showCallBack {
PrinterUtils.printGjcBoxWeighing(bean) PrinterUtils.printGjcBoxWeighing(bean)
} }
} else {
// 多条:逐张串行批量打印
BluetoothDialogModel().showCallBack {
viewModelScope.launch {
PrinterUtils.printGjcBoxWeighingBatch(selectedItems)
}
}
}
} }
/** /**

View File

@@ -25,13 +25,22 @@ import com.lukouguoji.module_base.ktx.formatDate
class GjcQueryViewModel : BasePageViewModel() { class GjcQueryViewModel : BasePageViewModel() {
// ==================== 搜索条件 ==================== // ==================== 搜索条件 ====================
val dateState = MutableLiveData("0") // 日期类型0入库1离港
val flightDateStart = MutableLiveData<String>(DateUtils.getCurrentTime().formatDate()) // 航班日期起 val flightDateStart = MutableLiveData<String>(DateUtils.getCurrentTime().formatDate()) // 航班日期起
val flightDateEnd = MutableLiveData("") // 航班日期止 val flightDateEnd = MutableLiveData("") // 航班日期止
val agentId = MutableLiveData("") // 代理ID val agentId = MutableLiveData("") // 代理ID
val outStatus = MutableLiveData("") // 出库状态 val flightNo = MutableLiveData("") // 航班号
val waybillNo = MutableLiveData("") // 运单号 val waybillNo = MutableLiveData("") // 运单号
// ==================== 下拉列表 ==================== // ==================== 下拉列表 ====================
// 日期类型下拉列表(对应接口 dateState
val dateStateList = MutableLiveData(
listOf(
KeyValue("入库", "0"),
KeyValue("离港", "1")
)
)
// 代理下拉列表从API获取 // 代理下拉列表从API获取
val agentList = MutableLiveData(listOf(KeyValue("全部", ""))) val agentList = MutableLiveData(listOf(KeyValue("全部", "")))
@@ -52,6 +61,7 @@ class GjcQueryViewModel : BasePageViewModel() {
val totalCount = MutableLiveData("0") // 合计票数 val totalCount = MutableLiveData("0") // 合计票数
val totalPc = MutableLiveData("0") // 总件数 val totalPc = MutableLiveData("0") // 总件数
val totalWeight = MutableLiveData("0") // 总重量 val totalWeight = MutableLiveData("0") // 总重量
val totalFlightNumber = MutableLiveData("0") // 航班航次
// ==================== 筛选面板 ==================== // ==================== 筛选面板 ====================
val filterVisible = MutableLiveData(false) val filterVisible = MutableLiveData(false)
@@ -70,7 +80,7 @@ class GjcQueryViewModel : BasePageViewModel() {
// ==================== 筛选条件 ==================== // ==================== 筛选条件 ====================
val spCode = MutableLiveData("") // 特码 val spCode = MutableLiveData("") // 特码
val flightNo = MutableLiveData("") // 航班号 val outStatus = MutableLiveData("") // 出库状态
val dest = MutableLiveData("") // 目的港 val dest = MutableLiveData("") // 目的港
val awbType = MutableLiveData("") // 运单类型 val awbType = MutableLiveData("") // 运单类型
val businessType = MutableLiveData("") // 业务类型 val businessType = MutableLiveData("") // 业务类型
@@ -79,11 +89,11 @@ class GjcQueryViewModel : BasePageViewModel() {
// 是否有筛选条件(任意一个非空则为 true用于筛选按钮红点 // 是否有筛选条件(任意一个非空则为 true用于筛选按钮红点
val hasFilter: MediatorLiveData<Boolean> = MediatorLiveData<Boolean>().apply { val hasFilter: MediatorLiveData<Boolean> = MediatorLiveData<Boolean>().apply {
val update = { _: Any? -> val update = { _: Any? ->
value = listOf(spCode, flightNo, dest, awbType, businessType, goodsCn) value = listOf(spCode, outStatus, dest, awbType, businessType, goodsCn)
.any { !it.value.isNullOrEmpty() } .any { !it.value.isNullOrEmpty() }
} }
addSource(spCode, update) addSource(spCode, update)
addSource(flightNo, update) addSource(outStatus, update)
addSource(dest, update) addSource(dest, update)
addSource(awbType, update) addSource(awbType, update)
addSource(businessType, update) addSource(businessType, update)
@@ -127,7 +137,7 @@ class GjcQueryViewModel : BasePageViewModel() {
*/ */
fun resetFilter() { fun resetFilter() {
spCode.value = "" spCode.value = ""
flightNo.value = "" outStatus.value = ""
dest.value = "" dest.value = ""
awbType.value = "" awbType.value = ""
businessType.value = "" businessType.value = ""
@@ -160,39 +170,32 @@ class GjcQueryViewModel : BasePageViewModel() {
* 核心方法调用API获取数据并转换PageInfo为BaseListBean * 核心方法调用API获取数据并转换PageInfo为BaseListBean
*/ */
override fun getData() { override fun getData() {
// 公共查询条件(列表与统计接口共用)
val commonParams = mapOf(
// 日期类型0入库1离港+ 日期范围
"dateState" to dateState.value?.ifEmpty { null }?.toIntOrNull(),
"beginDate" to flightDateStart.value?.ifEmpty { null },
"endDate" to flightDateEnd.value?.ifEmpty { null },
"agentCode" to agentId.value?.ifEmpty { null },
"fno" to flightNo.value?.ifEmpty { null },
"wbNo" to waybillNo.value?.ifEmpty { null },
// 筛选面板条件
"spCode" to spCode.value?.ifEmpty { null },
"outState" to outStatus.value?.ifEmpty { null }?.toIntOrNull(),
"dest" to dest.value?.ifEmpty { null },
"awbType" to awbType.value?.ifEmpty { null },
"businessType" to businessType.value?.ifEmpty { null },
"goodsCn" to goodsCn.value?.ifEmpty { null }
)
// 构建查询参数(列表接口) // 构建查询参数(列表接口)
val listParams = mapOf( val listParams = (commonParams + mapOf(
"pageNum" to pageModel.page, "pageNum" to pageModel.page,
"pageSize" to pageModel.limit, "pageSize" to pageModel.limit
"beginDate" to flightDateStart.value!!.ifEmpty { null }, )).toRequestBody()
"endDate" to flightDateEnd.value!!.ifEmpty { null },
"agentCode" to agentId.value!!.ifEmpty { null },
"outState" to outStatus.value!!.ifEmpty { null },
"wbNo" to waybillNo.value!!.ifEmpty { null },
// 筛选条件(暂未使用)
"spCode" to spCode.value!!.ifEmpty { null },
"fno" to flightNo.value!!.ifEmpty { null },
"dest" to dest.value!!.ifEmpty { null },
"awbType" to awbType.value!!.ifEmpty { null },
"businessType" to businessType.value!!.ifEmpty { null },
"goodsCn" to goodsCn.value!!.ifEmpty { null }
).toRequestBody()
// 构建查询参数(统计接口 - 使用相同的搜索条件) // 构建查询参数(统计接口 - 使用相同的搜索条件)
val totalParams = mapOf( val totalParams = commonParams.toRequestBody()
"beginDate" to flightDateStart.value!!.ifEmpty { null },
"endDate" to flightDateEnd.value!!.ifEmpty { null },
"agentCode" to agentId.value!!.ifEmpty { null },
"outState" to outStatus.value!!.ifEmpty { null },
"wbNo" to waybillNo.value!!.ifEmpty { null },
// 筛选条件
"spCode" to spCode.value!!.ifEmpty { null },
"fno" to flightNo.value!!.ifEmpty { null },
"dest" to dest.value!!.ifEmpty { null },
"awbType" to awbType.value!!.ifEmpty { null },
"businessType" to businessType.value!!.ifEmpty { null },
"goodsCn" to goodsCn.value!!.ifEmpty { null }
).toRequestBody()
// 获取列表数据显示loading // 获取列表数据显示loading
launchLoadingCollect({ launchLoadingCollect({
@@ -213,6 +216,7 @@ class GjcQueryViewModel : BasePageViewModel() {
totalCount.value = (data?.wbNumber ?: 0).toString() totalCount.value = (data?.wbNumber ?: 0).toString()
totalPc.value = (data?.totalPc ?: 0).toString() totalPc.value = (data?.totalPc ?: 0).toString()
totalWeight.value = (data?.totalWeight ?: 0.0).toString() totalWeight.value = (data?.totalWeight ?: 0.0).toString()
totalFlightNumber.value = (data?.flightNumber ?: 0).toString()
} }
} }
} }

View File

@@ -66,6 +66,10 @@ class GjcWeighingStartViewModel : BaseViewModel() {
val pageRemark = MutableLiveData("") // 备注 val pageRemark = MutableLiveData("") // 备注
// 托盘信息(运抵重量 = 地磅称重 - 托盘数量 × 托盘自重)
val trayNumber = MutableLiveData("") // 托盘数量
val trayWeight = MutableLiveData("18") // 托盘自重默认18可编辑
// 下拉选择数据源 // 下拉选择数据源
val channelList = MutableLiveData<List<KeyValue>>() // 通道号列表 val channelList = MutableLiveData<List<KeyValue>>() // 通道号列表
val agentList = MutableLiveData<List<KeyValue>>() // 代理人列表 val agentList = MutableLiveData<List<KeyValue>>() // 代理人列表
@@ -82,11 +86,10 @@ class GjcWeighingStartViewModel : BaseViewModel() {
// 获取传入的运单ID // 获取传入的运单ID
maWbId = intent.getLongExtra(Constant.Key.MAWB_ID, 0) maWbId = intent.getLongExtra(Constant.Key.MAWB_ID, 0)
// 监听地磅称重输入,单向同步到运抵重量 // 监听地磅称重、托盘数量、托盘自重输入,自动计算运抵重量
diBangWeight.observe(activity as LifecycleOwner) { weight -> diBangWeight.observe(activity as LifecycleOwner) { recalculateArriveWeight() }
// 同步到运抵重量(单向,不做反向同步) trayNumber.observe(activity as LifecycleOwner) { recalculateArriveWeight() }
arriveWeight.value = weight ?: "0" trayWeight.observe(activity as LifecycleOwner) { recalculateArriveWeight() }
}
// 监听运抵重量变化,自动计算运抵体积 // 监听运抵重量变化,自动计算运抵体积
arriveWeight.observe(activity as LifecycleOwner) { weightStr -> arriveWeight.observe(activity as LifecycleOwner) { weightStr ->
@@ -113,6 +116,32 @@ class GjcWeighingStartViewModel : BaseViewModel() {
} }
} }
/**
* 自动计算运抵重量:地磅称重 - (托盘数量 × 托盘自重)
*/
private fun recalculateArriveWeight() {
val gross = diBangWeight.value?.toDoubleOrNull() ?: 0.0
val trayTotal = getTrayTotalWeight()
val net = gross - trayTotal
arriveWeight.value = if (net > 0) formatWeight(net) else "0"
}
/**
* 托盘总重量 = 托盘数量 × 托盘自重
*/
private fun getTrayTotalWeight(): Double {
val num = trayNumber.value?.toIntOrNull() ?: 0
val weight = trayWeight.value?.toDoubleOrNull() ?: 0.0
return num * weight
}
/**
* 重量格式化最多保留两位小数去掉多余的0
*/
private fun formatWeight(value: Double): String {
return String.format("%.2f", value).trimEnd('0').trimEnd('.')
}
/** /**
* 加载通道号列表 (国际出港专用) * 加载通道号列表 (国际出港专用)
*/ */
@@ -391,6 +420,10 @@ class GjcWeighingStartViewModel : BaseViewModel() {
passageWay = this@GjcWeighingStartViewModel.channelList.value?.firstOrNull{ it.value == channel.value }?.key ?: "" passageWay = this@GjcWeighingStartViewModel.channelList.value?.firstOrNull{ it.value == channel.value }?.key ?: ""
passageWayId = this@GjcWeighingStartViewModel.channel.value passageWayId = this@GjcWeighingStartViewModel.channel.value
// 托盘信息
trayNumber = this@GjcWeighingStartViewModel.trayNumber.value?.toIntOrNull()
trayTotalWeight = getTrayTotalWeight()
remark = pageRemark.value remark = pageRemark.value
} }
@@ -417,6 +450,8 @@ class GjcWeighingStartViewModel : BaseViewModel() {
arrivePc.value = "" arrivePc.value = ""
arriveWeight.value = "" arriveWeight.value = ""
arriveVolume.value = "" arriveVolume.value = ""
trayNumber.value = ""
trayWeight.value = "18"
pageRemark.value = "" pageRemark.value = ""
@@ -499,6 +534,8 @@ class GjcWeighingStartViewModel : BaseViewModel() {
"goodsCn" to bean.goodsCn, "goodsCn" to bean.goodsCn,
"businessType" to bean.businessType, "businessType" to bean.businessType,
"carId" to bean.carId, "carId" to bean.carId,
"trayNumber" to trayNumber.value?.toIntOrNull(),
"trayTotalWeight" to getTrayTotalWeight(),
"remark" to pageRemark.value, "remark" to pageRemark.value,
"checkIn" to "1", // 收运状态设置为已收运 "checkIn" to "1", // 收运状态设置为已收运
"passageWayId" to channel.value, // 通道号参数 "passageWayId" to channel.value, // 通道号参数

View File

@@ -20,6 +20,7 @@ import com.lukouguoji.module_base.ktx.launchLoadingCollect
import com.lukouguoji.module_base.ktx.showToast import com.lukouguoji.module_base.ktx.showToast
import com.lukouguoji.module_base.ktx.toRequestBody import com.lukouguoji.module_base.ktx.toRequestBody
import com.lukouguoji.module_base.model.ScanModel import com.lukouguoji.module_base.model.ScanModel
import dev.utils.app.info.KeyValue
import dev.utils.common.DateUtils import dev.utils.common.DateUtils
import com.lukouguoji.module_base.ktx.formatDate import com.lukouguoji.module_base.ktx.formatDate
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -34,6 +35,16 @@ class IntExpArriveViewModel : BasePageViewModel() {
val flightNo = MutableLiveData("") // 航班号 val flightNo = MutableLiveData("") // 航班号
val waybillNo = MutableLiveData("") // 运单号 val waybillNo = MutableLiveData("") // 运单号
val hno = MutableLiveData("") // 分单号 val hno = MutableLiveData("") // 分单号
val arrivalStatus = MutableLiveData("") // 运抵状态0未运抵1已运抵
// 运抵状态下拉列表
val arrivalStatusList = MutableLiveData(
listOf(
KeyValue("全部", ""),
KeyValue("已运抵", "1"),
KeyValue("未运抵", "0")
)
)
// ========== 统计信息 ========== // ========== 统计信息 ==========
val totalCount = MutableLiveData("0") // 合计票数 val totalCount = MutableLiveData("0") // 合计票数
@@ -301,7 +312,8 @@ class IntExpArriveViewModel : BasePageViewModel() {
"fdate" to flightDate.value?.ifEmpty { null }, "fdate" to flightDate.value?.ifEmpty { null },
"fno" to flightNo.value?.ifEmpty { null }, "fno" to flightNo.value?.ifEmpty { null },
"wbNo" to waybillNo.value?.ifEmpty { null }, "wbNo" to waybillNo.value?.ifEmpty { null },
"hno" to hno.value?.ifEmpty { null } "hno" to hno.value?.ifEmpty { null },
"arrivalStatus" to arrivalStatus.value?.ifEmpty { null }
) )
// 列表参数 (含分页) // 列表参数 (含分页)

View File

@@ -140,9 +140,10 @@ class IntExpStorageUseViewModel : BasePageViewModel() {
/** /**
* 执行清仓操作 * 执行清仓操作
* @param clearNormal 清仓正常("0"或"1" * @param clearNormal 清仓正常("0"或"1"
* @param clearRemark 清仓备注(选填)
* @param maWbListForClear 包含选中子列表项的主列表数据 * @param maWbListForClear 包含选中子列表项的主列表数据
*/ */
fun performClear(clearNormal: String, maWbListForClear: List<GjcMaWb>) { fun performClear(clearNormal: String, clearRemark: String, maWbListForClear: List<GjcMaWb>) {
if (maWbListForClear.isEmpty()) { if (maWbListForClear.isEmpty()) {
showToast("请至少选择一个库位") showToast("请至少选择一个库位")
return return
@@ -151,6 +152,7 @@ class IntExpStorageUseViewModel : BasePageViewModel() {
// 构建请求参数:完整的主子列表结构 // 构建请求参数:完整的主子列表结构
val params = mapOf( val params = mapOf(
"clearNormal" to clearNormal, "clearNormal" to clearNormal,
"clearRemark" to clearRemark.ifEmpty { null },
"maWbList" to maWbListForClear "maWbList" to maWbListForClear
).toRequestBody() ).toRequestBody()

View File

@@ -139,6 +139,29 @@
android:textSize="16sp" /> android:textSize="16sp" />
</LinearLayout> </LinearLayout>
<!-- 耗材重量 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="耗材重量:"
android:textColor="@color/text_gray"
android:textSize="16sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewModel.consumeWeight}"
android:textColor="@color/text_normal"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View File

@@ -259,7 +259,7 @@
</LinearLayout> </LinearLayout>
<!-- 第5行架子车自重、ULD自重、货重(绿色只读) --> <!-- 第5行架子车自重、ULD自重、耗材重量(只读) -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -289,10 +289,10 @@
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew <com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
enable="@{false}" enable="@{false}"
title='@{"货重"}' title='@{"耗材重量"}'
titleLength="@{5}" titleLength="@{5}"
type="@{DataLayoutType.INPUT}" type="@{DataLayoutType.INPUT}"
value='@{viewModel.cargoWeight}' value='@{viewModel.consumeWeight}'
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="15dp" android:layout_marginStart="15dp"
@@ -300,7 +300,7 @@
</LinearLayout> </LinearLayout>
<!-- 第6行航班日期、航班号、目的港 --> <!-- 第6行航班日期、航班号、货重(绿色只读) -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -331,11 +331,11 @@
android:layout_weight="1" /> android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew <com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请输入目的港"}' enable="@{false}"
title='@{"目的港"}' title='@{"货重"}'
titleLength="@{5}" titleLength="@{5}"
type="@{DataLayoutType.INPUT}" type="@{DataLayoutType.INPUT}"
value='@={viewModel.dataBean.fdest}' value='@{viewModel.cargoWeight}'
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="15dp" android:layout_marginStart="15dp"
@@ -343,7 +343,32 @@
</LinearLayout> </LinearLayout>
<!-- 第7行备注 --> <!-- 第7行目的港(占 1/3 宽度) -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请输入目的港"}'
title='@{"目的港"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.dataBean.fdest}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<!-- 占位:保持目的港与上方各行第一列同宽 -->
<Space
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="2" />
</LinearLayout>
<!-- 第8行备注整行 -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@@ -42,6 +42,16 @@
android:gravity="center_vertical" android:gravity="center_vertical"
android:orientation="horizontal"> android:orientation="horizontal">
<!-- 日期类型(入库/离港) -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.7"
hint='@{"请选择日期类型"}'
list="@{viewModel.dateStateList}"
type="@{SearchLayoutType.SPINNER}"
value="@={viewModel.dateState}" />
<!-- 航班日期起 --> <!-- 航班日期起 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout <com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
android:layout_width="0dp" android:layout_width="0dp"
@@ -72,15 +82,15 @@
type="@{SearchLayoutType.SPINNER}" type="@{SearchLayoutType.SPINNER}"
value="@={viewModel.agentId}" /> value="@={viewModel.agentId}" />
<!-- 出库状态 --> <!-- 航班号 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout <com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
android:id="@+id/flight_no_search"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
hint='@{"请选择出库状态"}' hint='@{"请输入航班号"}'
list="@{viewModel.outStatusList}" type="@{SearchLayoutType.INPUT}"
type="@{SearchLayoutType.SPINNER}" value="@={viewModel.flightNo}" />
value="@={viewModel.outStatus}" />
<!-- 运单号 --> <!-- 运单号 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout <com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
@@ -204,6 +214,16 @@
android:textStyle="bold" android:textStyle="bold"
tools:text="总重量100" /> tools:text="总重量100" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text='@{`航班航次:` + viewModel.totalFlightNumber}'
android:textColor="@color/bottom_tool_tips_text_color"
android:textSize="16sp"
android:textStyle="bold"
tools:text="航班航次2" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View File

@@ -313,7 +313,45 @@
</LinearLayout> </LinearLayout>
<!-- 第6行运抵件数、运抵重量、运抵体积 --> <!-- 第6行托盘数量、托盘自重(用于自动计算运抵重量) -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请输入托盘数量"}'
inputType="@{android.text.InputType.TYPE_CLASS_NUMBER}"
title='@{"托盘数量"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.trayNumber}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请输入托盘自重"}'
inputType="@{android.text.InputType.TYPE_CLASS_NUMBER | android.text.InputType.TYPE_NUMBER_FLAG_DECIMAL}"
title='@{"托盘自重"}'
titleLength="@{5}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.trayWeight}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1" />
<View
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1" />
</LinearLayout>
<!-- 第7行运抵件数、运抵重量、运抵体积 -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -356,7 +394,7 @@
</LinearLayout> </LinearLayout>
<!--7行:托盘车号、托盘车自重、业务类型 --> <!--8行:平板车、平板车自重、业务类型 -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -364,9 +402,9 @@
android:orientation="horizontal"> android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew <com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请输入托盘车号"}' hint='@{"请输入平板车号"}'
setRefreshCallBack="@{viewModel::onCarIdInputComplete}" setRefreshCallBack="@{viewModel::onCarIdInputComplete}"
title='@{"托盘车号"}' title='@{"平 板 车"}'
titleLength="@{5}" titleLength="@{5}"
type="@{DataLayoutType.INPUT}" type="@{DataLayoutType.INPUT}"
value='@={viewModel.maWbBean.carId}' value='@={viewModel.maWbBean.carId}'
@@ -376,7 +414,7 @@
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew <com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
enable="@{false}" enable="@{false}"
title='@{"托盘车自重"}' title='@{"平板车自重"}'
titleLength="@{5}" titleLength="@{5}"
type="@{DataLayoutType.INPUT}" type="@{DataLayoutType.INPUT}"
value='@{viewModel.carWeight}' value='@{viewModel.carWeight}'
@@ -399,7 +437,7 @@
</LinearLayout> </LinearLayout>
<!--8行:备注 --> <!--9行:备注 -->
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew <com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请输入备注"}' hint='@{"请输入备注"}'
inputHeight="@{80}" inputHeight="@{80}"

View File

@@ -79,6 +79,16 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" /> android:layout_weight="1" />
<!-- 运抵状态 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
hint='@{"请选择运抵状态"}'
list="@{viewModel.arrivalStatusList}"
type="@{SearchLayoutType.SPINNER}"
value="@={viewModel.arrivalStatus}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<!-- 搜索按钮 --> <!-- 搜索按钮 -->
<LinearLayout <LinearLayout
android:layout_width="0dp" android:layout_width="0dp"

View File

@@ -61,6 +61,32 @@
</LinearLayout> </LinearLayout>
<!-- 备注 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
completeSpace="@{5}"
android:text="备注:"
android:textColor="@color/text_normal"
android:textSize="16sp" />
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
hint='@{"请输入备注"}'
type="@{SearchLayoutType.INPUT}"
value="@={model.clearRemark}" />
</LinearLayout>
</LinearLayout> </LinearLayout>
<!-- 底部按钮 --> <!-- 底部按钮 -->

View File

@@ -67,17 +67,19 @@
type="@{DataLayoutType.INPUT}" type="@{DataLayoutType.INPUT}"
value="@={record.weightStr}" /> value="@={record.weightStr}" />
<!-- 托盘自重字段(只读 --> <!-- 托盘自重字段(取托盘重量 trayTotalWeight可编辑 -->
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew <com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="10dp" android:layout_marginStart="10dp"
android:layout_weight="1" android:layout_weight="1"
enable="@{false}" enable="@{isEditMode}"
hint="@{`托盘自重`}"
inputType="@{android.text.InputType.TYPE_CLASS_NUMBER | android.text.InputType.TYPE_NUMBER_FLAG_DECIMAL}"
title="@{`托盘自重`}" title="@{`托盘自重`}"
titleLength="@{4}" titleLength="@{4}"
type="@{DataLayoutType.INPUT}" type="@{DataLayoutType.INPUT}"
value="@{record.carWeight}" /> value="@={record.trayTotalWeightStr}" />
<!-- 计重时间字段(只读) --> <!-- 计重时间字段(只读) -->
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew <com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew

View File

@@ -198,7 +198,7 @@
</LinearLayout> </LinearLayout>
<!-- 第二行:航程、计重状态、运抵状态、运单类型、分单数 --> <!-- 第二行:航程、海关放行、运抵状态、运单类型、分单数 -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -231,7 +231,7 @@
</LinearLayout> </LinearLayout>
<!-- 计重状态 --> <!-- 海关放行 -->
<LinearLayout <LinearLayout
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -243,20 +243,16 @@
completeSpace="@{5}" completeSpace="@{5}"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="计重状态" android:text="海关放行"
android:textColor="@color/text_normal" android:textColor="@color/text_normal"
android:textSize="15sp" /> android:textSize="15sp" />
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@{`1`.equals(bean.checkIn) ? @drawable/tag_status_green : (`2`.equals(bean.checkIn) ? @drawable/tag_status_blue : @drawable/tag_status_gray)}" android:text="@{bean.cmdStatus}"
android:paddingHorizontal="8dp" android:textColor="@color/text_normal"
android:paddingVertical="2dp" android:textSize="15sp" />
android:text="@{bean.checkInText}"
android:textColor="@{`1`.equals(bean.checkIn) ? @color/text_green : (`2`.equals(bean.checkIn) ? @color/colorPrimary : @color/text_gray)}"
android:textSize="14sp"
android:visibility="@{bean.checkIn != null &amp;&amp; !bean.checkIn.isEmpty() ? View.VISIBLE : View.GONE}" />
</LinearLayout> </LinearLayout>
@@ -439,6 +435,16 @@
android:textSize="14sp" android:textSize="14sp"
android:textStyle="bold" /> android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.9"
android:gravity="center"
android:text="海关放行"
android:textColor="@color/text_normal"
android:textSize="14sp"
android:textStyle="bold" />
<TextView <TextView
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@@ -90,6 +90,16 @@
</LinearLayout> </LinearLayout>
<!-- 海关放行 -->
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.9"
android:gravity="center"
android:text="@{bean.cmdStatus ?? ``}"
android:textColor="@color/text_normal"
android:textSize="14sp" />
<!-- 品名(中) --> <!-- 品名(中) -->
<TextView <TextView
android:layout_width="0dp" android:layout_width="0dp"

View File

@@ -167,7 +167,7 @@
</LinearLayout> </LinearLayout>
<!-- 第二行:目的港、库位号、复磅状态、交接人、交接时间 --> <!-- 第二行:目的港、库位号、IMP代码、交接人、交接时间 -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -221,7 +221,7 @@
</LinearLayout> </LinearLayout>
<!-- 复磅状态 --> <!-- IMP代码非空且不是 ELI/ELM 时标红) -->
<LinearLayout <LinearLayout
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -233,14 +233,14 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
completeSpace="@{5}" completeSpace="@{5}"
android:text="复磅状态" android:text="IMP代码"
android:textSize="15sp" /> android:textSize="15sp" />
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@{bean.wtDate != null &amp;&amp; !bean.wtDate.isEmpty() ? `已复磅` : `未复磅`}" android:text="@{bean.dgrCode}"
android:textColor="@{bean.wtDate != null &amp;&amp; !bean.wtDate.isEmpty() ? @color/text_green : @color/text_normal}" android:textColor="@{bean.dgrCode != null &amp;&amp; !bean.dgrCode.isEmpty() &amp;&amp; !bean.dgrCode.equals(`ELI`) &amp;&amp; !bean.dgrCode.equals(`ELM`) ? @color/text_red : @color/text_normal}"
android:textSize="15sp" /> android:textSize="15sp" />
</LinearLayout> </LinearLayout>

View File

@@ -67,17 +67,17 @@
type="@{DataLayoutType.INPUT}" type="@{DataLayoutType.INPUT}"
value='@={viewModel.spCode}' /> value='@={viewModel.spCode}' />
<!-- 航班号 --> <!-- 出库状态 -->
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew <com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:id="@+id/filter_flight_no"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="10dp" android:layout_marginBottom="10dp"
hint='@{"请输入航班号"}' hint='@{"请选择出库状态"}'
title='@{"航班号"}' list="@{viewModel.outStatusList}"
title='@{"出库状态"}'
titleLength="@{4}" titleLength="@{4}"
type="@{DataLayoutType.INPUT}" type="@{DataLayoutType.SPINNER}"
value='@={viewModel.flightNo}' /> value='@={viewModel.outStatus}' />
<!-- 目的港 --> <!-- 目的港 -->
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew <com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew

View File

@@ -10,6 +10,7 @@ import com.lukouguoji.gjj.viewModel.GjjManifestAddViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.common.Constant import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.common.DetailsPageType import com.lukouguoji.module_base.common.DetailsPageType
import com.lukouguoji.module_base.ktx.addOnItemClickListener
import com.lukouguoji.module_base.ktx.noNull import com.lukouguoji.module_base.ktx.noNull
import com.lukouguoji.module_base.ktx.setUpperCaseAlphanumericFilter import com.lukouguoji.module_base.ktx.setUpperCaseAlphanumericFilter
@@ -31,6 +32,10 @@ class GjjManifestAddActivity :
binding.actualWeightInput.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL binding.actualWeightInput.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL
binding.billingWeightInput.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL binding.billingWeightInput.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL
// 交接图片列表
viewModel.rv = binding.rvPic
binding.rvPic.addOnItemClickListener(viewModel)
viewModel.initOnCreated(intent) viewModel.initOnCreated(intent)
// 动态设置标题(必须在 initOnCreated 之后pageType 已从 Intent 解析) // 动态设置标题(必须在 initOnCreated 之后pageType 已从 Intent 解析)

View File

@@ -4,6 +4,7 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.text.InputType import android.text.InputType
import androidx.core.widget.doOnTextChanged
import com.lukouguoji.gjj.R import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.ActivityIntImpAccidentVisaEditBinding import com.lukouguoji.gjj.databinding.ActivityIntImpAccidentVisaEditBinding
import com.lukouguoji.gjj.viewModel.IntImpAccidentVisaEditViewModel import com.lukouguoji.gjj.viewModel.IntImpAccidentVisaEditViewModel
@@ -29,6 +30,10 @@ class IntImpAccidentVisaEditActivity :
binding.fnoInput.et.setUpperCaseAlphanumericFilter() binding.fnoInput.et.setUpperCaseAlphanumericFilter()
// 运单号纯数字11位 // 运单号纯数字11位
binding.wbNoInput.et.inputType = InputType.TYPE_CLASS_NUMBER binding.wbNoInput.et.inputType = InputType.TYPE_CLASS_NUMBER
// 运单号满11位后自动查询舱单信息带出表单数据覆盖手输、联想填充、弹窗选择
binding.wbNoInput.et.doOnTextChanged { text, _, _, _ ->
viewModel.onWbNoChanged(text?.toString()?.trim() ?: "")
}
viewModel.rv = binding.rv viewModel.rv = binding.rv
binding.rv.addOnItemClickListener(viewModel) binding.rv.addOnItemClickListener(viewModel)

View File

@@ -55,8 +55,8 @@ class IntImpQueryActivity :
if (visible) showFilterPanel() else hideFilterPanel() if (visible) showFilterPanel() else hideFilterPanel()
} }
// 航班号:大写字母+数字 // 航班号(顶部搜索区):大写字母+数字
binding.filterPanel.filterFlightNo.et.setUpperCaseAlphanumericFilter() binding.flightNoSearch.et.setUpperCaseAlphanumericFilter()
// 始发港:仅大写字母 // 始发港:仅大写字母
binding.filterPanel.filterOrigin.et.setUpperCaseLetterFilter() binding.filterPanel.filterOrigin.et.setUpperCaseLetterFilter()

View File

@@ -5,26 +5,45 @@ import android.view.View
import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.recyclerview.widget.RecyclerView
import com.lukouguoji.gjj.R
import com.lukouguoji.module_base.base.BaseViewModel import com.lukouguoji.module_base.base.BaseViewModel
import com.lukouguoji.module_base.bean.FileBean
import com.lukouguoji.module_base.common.Constant import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.common.ConstantEvent import com.lukouguoji.module_base.common.ConstantEvent
import com.lukouguoji.module_base.common.DetailsPageType import com.lukouguoji.module_base.common.DetailsPageType
import com.lukouguoji.module_base.http.net.NetApply import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.impl.FlowBus import com.lukouguoji.module_base.impl.FlowBus
import com.lukouguoji.module_base.impl.ImageSelectNewViewHolder
import com.lukouguoji.module_base.interfaces.IOnItemClickListener
import com.lukouguoji.module_base.ktx.commonAdapter
import com.lukouguoji.module_base.ktx.finish import com.lukouguoji.module_base.ktx.finish
import com.lukouguoji.module_base.ktx.formatDate import com.lukouguoji.module_base.ktx.formatDate
import com.lukouguoji.module_base.ktx.launchCollect import com.lukouguoji.module_base.ktx.launchCollect
import com.lukouguoji.module_base.ktx.launchLoadingCollect import com.lukouguoji.module_base.ktx.launchLoadingCollect
import com.lukouguoji.module_base.ktx.loadMore
import com.lukouguoji.module_base.ktx.noNull import com.lukouguoji.module_base.ktx.noNull
import com.lukouguoji.module_base.ktx.showToast import com.lukouguoji.module_base.ktx.showToast
import com.lukouguoji.module_base.ktx.toRequestBody import com.lukouguoji.module_base.ktx.toRequestBody
import com.lukouguoji.module_base.ktx.verifyNullOrEmpty import com.lukouguoji.module_base.ktx.verifyNullOrEmpty
import com.lukouguoji.module_base.util.DictUtils import com.lukouguoji.module_base.util.DictUtils
import com.lukouguoji.module_base.util.MediaUtil
import com.lukouguoji.module_base.util.UploadUtil
import dev.utils.app.info.KeyValue import dev.utils.app.info.KeyValue
import dev.utils.common.DateUtils import dev.utils.common.DateUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class GjjManifestAddViewModel : BaseViewModel() { class GjjManifestAddViewModel : BaseViewModel(), IOnItemClickListener {
// 页面类型必须用LiveData // 页面类型必须用LiveData
val pageType = MutableLiveData(DetailsPageType.Add) val pageType = MutableLiveData(DetailsPageType.Add)
@@ -167,6 +186,11 @@ class GjjManifestAddViewModel : BaseViewModel() {
val waybillTypeList = MutableLiveData<List<KeyValue>>() val waybillTypeList = MutableLiveData<List<KeyValue>>()
val waybillType = MutableLiveData("") val waybillType = MutableLiveData("")
// ========== 交接图片 ==========
val itemLayoutId = R.layout.item_image_select_new
val itemViewHolder = ImageSelectNewViewHolder::class.java
var rv: RecyclerView? = null
/** /**
* 初始化从Intent获取参数 * 初始化从Intent获取参数
*/ */
@@ -205,6 +229,9 @@ class GjjManifestAddViewModel : BaseViewModel() {
} }
} }
// 交接图片:末尾追加空白占位项作为添加按钮
rv?.post { rv?.commonAdapter()?.addItem(FileBean()) }
// 加载下拉列表(在编辑数据加载之后,以便使用 checkedValue 将选中项置顶) // 加载下拉列表(在编辑数据加载之后,以便使用 checkedValue 将选中项置顶)
loadDictLists() loadDictLists()
} }
@@ -302,6 +329,21 @@ class GjjManifestAddViewModel : BaseViewModel() {
businessType.value = manifest.businessType businessType.value = manifest.businessType
goodsType.value = manifest.cargoType goodsType.value = manifest.cargoType
waybillType.value = manifest.awbType waybillType.value = manifest.awbType
// 回填交接图片path 取原图 URL 确保预览清晰url 取缩略图用于提交
val picList = manifest.pic.noNull().split(",").filter { it.isNotEmpty() }
val originalList = manifest.originalPic.noNull().split(",").filter { it.isNotEmpty() }
if (picList.isNotEmpty()) {
val images = picList.mapIndexed { index, picUrl ->
val originalUrl = originalList.getOrElse(index) { picUrl }
FileBean(
path = MediaUtil.fillUrl(originalUrl),
url = picUrl,
originalPic = originalUrl
)
}
rv?.loadMore(images)
}
} }
/** /**
@@ -411,6 +453,38 @@ class GjjManifestAddViewModel : BaseViewModel() {
paramsMap["prefix"] = prefix paramsMap["prefix"] = prefix
} }
// 先上传本地新增的交接图片,全部完成后再组装三字段提交表单
var uploadFailed = false
(rv?.commonAdapter()?.items ?: emptyList())
.asFlow()
.map { it as FileBean }
.filter { it.path.isNotEmpty() && it.url.isEmpty() }
.onEach {
val data = UploadUtil.upload(it.path).data
// UploadUtil 返回newName=原图(较大)zipFileName=缩略图(较小)
// FileBean.url 用作缩略图标识FileBean.originalPic 用作原图标识
it.url = data?.zipFileName ?: ""
it.originalPic = data?.newName ?: ""
}
.flowOn(Dispatchers.IO)
.onStart { showLoading() }
.catch {
uploadFailed = true
showToast(it.message.noNull("上传图片失败"))
dismissLoading()
}
.onCompletion {
if (uploadFailed) return@onCompletion
// 交接图片三字段pic=缩略图、originalPic=原图、picNumber=数量
val picBeans = (rv?.commonAdapter()?.items ?: emptyList())
.filterIsInstance<FileBean>()
.filter { it.path.isNotEmpty() }
paramsMap["picNumber"] = picBeans.size.toString()
paramsMap["pic"] = picBeans.joinToString(",") { MediaUtil.removeUrl(it.url) }
paramsMap["originalPic"] =
picBeans.joinToString(",") { MediaUtil.removeUrl(it.originalPic) }
val params = paramsMap.toRequestBody() val params = paramsMap.toRequestBody()
launchLoadingCollect({ launchLoadingCollect({
@@ -437,6 +511,26 @@ class GjjManifestAddViewModel : BaseViewModel() {
} }
} }
} }
.launchIn(viewModelScope)
}
/**
* 交接图片列表点击回调
* 长按图片R.id.rl切换删除按钮显隐点击删除按钮R.id.iv_delete移除该图片
*/
override fun onItemClick(position: Int, type: Int) {
val adapter = rv?.commonAdapter() ?: return
val bean = adapter.getItem(position) as? FileBean ?: return
when (type) {
R.id.rl -> {
bean.canDelete.set(!bean.canDelete.get())
}
R.id.iv_delete -> {
adapter.removeItem(position)
}
else -> {}
}
}
/** /**
* 取消点击 * 取消点击

View File

@@ -233,6 +233,65 @@ class IntImpAccidentVisaEditViewModel : BaseViewModel(), IOnItemClickListener {
} }
} }
///////////////////////////////////////////////////////////////////////////
// 运单号带出国际进港舱单信息
///////////////////////////////////////////////////////////////////////////
private var lastQueriedWbNo = ""
/**
* 运单号文本变化回调Activity 中监听输入框)
* 满11位且与上次查询不同时查询进港舱单信息并回填表单
* 仅新增模式生效:编辑模式下 loadDetail 回显运单号会触发本回调,
* 若不拦截会用舱单数据覆盖已保存的表单和图片列表
*/
fun onWbNoChanged(wbNo: String) {
if (pageType.value != DetailsPageType.Add) return
if (wbNo.length != 11) return
if (wbNo == lastQueriedWbNo) return
lastQueriedWbNo = wbNo
queryWbInfo(wbNo)
}
private fun queryWbInfo(wbNo: String) {
launchLoadingCollect({ NetApply.api.getIntImpManifestByWbNo(wbNo) }) {
onSuccess = {
val data = it.data
if (it.verifySuccess() && data != null) {
// 接口可能返回 null 字段Gson 反射注入会绕过 Kotlin 非空默认值),统一 noNull 防护
val b = dataBean.value ?: GjAccidentVisaEditBean()
b.fdate = data.fdate.noNull().take(10)
b.fno = data.fno.noNull()
b.dep = data.origin.noNull()
b.dest = data.dest.noNull()
b.pc = (if (data.totalPc > 0) data.totalPc else data.pc).toString()
b.weight = (if (data.totalWeight > 0.0) data.totalWeight else data.weight).toString()
b.goods = data.goods.noNull().ifEmpty { data.goodsCn.noNull() }
dataBean.value = b
// 与航班级联查询判重键同步,避免航班输入框失焦后重复查询覆盖带出的始发/目的站
lastQueriedFlight = "${b.fdate}-${b.fno}"
// 回填交接图片path 取原图完整 URL 用于预览url 取缩略图相对路径用于提交
val picList = data.pic.noNull().split(",").filter { p -> p.isNotEmpty() }
val originalList = data.originalPic.noNull().split(",").filter { p -> p.isNotEmpty() }
val images = picList.mapIndexed { index, picUrl ->
val originalUrl = originalList.getOrElse(index) { picUrl }
FileBean(
path = MediaUtil.fillUrl(originalUrl),
url = picUrl,
originalPic = originalUrl
)
}
// 重置图片区:舱单图片 + 末尾空白添加占位
rv?.commonAdapter()?.refresh(images + FileBean())
} else {
showToast(it.msg.noNull("未查询到该运单的进港舱单信息"))
}
}
}
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// 保存 // 保存
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////

View File

@@ -481,6 +481,77 @@ class IntImpManifestViewModel : BasePageViewModel() {
.navigation() .navigation()
} }
/**
* 开始理货(弹出修改库位对话框,提交理货库位)
*/
fun startTallyClick() {
val list = pageModel.rv?.commonAdapter()?.items as? List<GjjManifest> ?: return
val selectedItems = list.filter { it.isSelected }
if (selectedItems.isEmpty()) {
showToast("请选择要理货的运单")
return
}
if (selectedItems.size > 1) {
showToast("只能选择一个运单")
return
}
// 舱单列表接口不返回理货库位,需先查装机单记录取出该运单已有的库位再弹窗回填
val selectedItem = selectedItems.first()
val queryParams = mapOf(
"fid" to fid.ifEmpty { null },
"fdep" to fdep.ifEmpty { null },
"wbNo" to selectedItem.wbNo.ifEmpty { null },
"pageNum" to 1,
"pageSize" to 1
).toRequestBody()
launchLoadingCollect({ NetApply.api.getIntImpLoadingList(queryParams) }) {
onSuccess = { result ->
val tallyRecord = result.list?.firstOrNull()
showModifyStorageDialog(
selectedItems = selectedItems,
currentLocationId = tallyRecord?.locationTallyId?.takeIf { it > 0 }?.toString() ?: "",
currentLocationName = tallyRecord?.locationTally ?: ""
)
}
// 查询失败不阻断操作,直接弹出空白库位的对话框
onFailed = { _, _ -> showModifyStorageDialog(selectedItems, "", "") }
}
}
/**
* 弹出修改库位对话框并提交currentLocation* 用于回填该运单已有的理货库位)
*/
private fun showModifyStorageDialog(
selectedItems: List<GjjManifest>,
currentLocationId: String,
currentLocationName: String
) {
IntImpModifyStorageDialogModel(
currentLocationId = currentLocationId,
currentLocationName = currentLocationName
) { dialog ->
val params = mapOf(
"location" to dialog.locationName,
"locationId" to dialog.locationId.toLongOrNull(),
"manifestList" to selectedItems
).toRequestBody()
launchLoadingCollect({ NetApply.api.modifyIntImpLoadingStorage(params) }) {
onSuccess = {
if (it.verifySuccess()) {
showToast(it.msg.noNull("修改库位成功"))
refresh()
} else {
showToast(it.msg.noNull("修改库位失败"))
}
}
}
}.show()
}
/** /**
* 货物发放 * 货物发放
*/ */

View File

@@ -143,7 +143,7 @@ class IntImpPickUpDLVViewModel : BasePageViewModel() {
"beginDate" to paymentDateStart.value?.ifEmpty { null }, "beginDate" to paymentDateStart.value?.ifEmpty { null },
"endDate" to paymentDateEnd.value?.ifEmpty { null }, "endDate" to paymentDateEnd.value?.ifEmpty { null },
"agentCode" to agentCode.value?.ifEmpty { null }, "agentCode" to agentCode.value?.ifEmpty { null },
"no" to wbNo.value?.ifEmpty { null }, "wbNo" to wbNo.value?.ifEmpty { null },
"spCode" to spCode.value?.ifEmpty { null } "spCode" to spCode.value?.ifEmpty { null }
) )

View File

@@ -33,7 +33,7 @@ class IntImpQueryViewModel : BasePageViewModel(), IOnItemClickListener {
val flightDateStart = MutableLiveData<String>(DateUtils.getCurrentTime().formatDate()) val flightDateStart = MutableLiveData<String>(DateUtils.getCurrentTime().formatDate())
val flightDateEnd = MutableLiveData("") val flightDateEnd = MutableLiveData("")
val agentId = MutableLiveData("") val agentId = MutableLiveData("")
val outStatus = MutableLiveData("") val flightNo = MutableLiveData("")
val waybillNo = MutableLiveData("") val waybillNo = MutableLiveData("")
// ==================== 下拉列表 ==================== // ==================== 下拉列表 ====================
@@ -55,6 +55,7 @@ class IntImpQueryViewModel : BasePageViewModel(), IOnItemClickListener {
val totalCount = MutableLiveData("0") val totalCount = MutableLiveData("0")
val totalPc = MutableLiveData("0") val totalPc = MutableLiveData("0")
val totalWeight = MutableLiveData("0") val totalWeight = MutableLiveData("0")
val totalFlightNumber = MutableLiveData("0")
// ==================== 特码下拉 ==================== // ==================== 特码下拉 ====================
val spCodeList = MutableLiveData<List<KeyValue>>(emptyList()) val spCodeList = MutableLiveData<List<KeyValue>>(emptyList())
@@ -66,7 +67,7 @@ class IntImpQueryViewModel : BasePageViewModel(), IOnItemClickListener {
// ==================== 筛选条件 ==================== // ==================== 筛选条件 ====================
val spCode = MutableLiveData("") val spCode = MutableLiveData("")
val flightNo = MutableLiveData("") val outStatus = MutableLiveData("")
val origin = MutableLiveData("") val origin = MutableLiveData("")
val awbType = MutableLiveData("") val awbType = MutableLiveData("")
val businessType = MutableLiveData("") val businessType = MutableLiveData("")
@@ -75,11 +76,11 @@ class IntImpQueryViewModel : BasePageViewModel(), IOnItemClickListener {
// 是否有筛选条件(任意一个非空则为 true // 是否有筛选条件(任意一个非空则为 true
val hasFilter: MediatorLiveData<Boolean> = MediatorLiveData<Boolean>().apply { val hasFilter: MediatorLiveData<Boolean> = MediatorLiveData<Boolean>().apply {
val update = { _: Any? -> val update = { _: Any? ->
value = listOf(spCode, flightNo, origin, awbType, businessType, goodsCn) value = listOf(spCode, outStatus, origin, awbType, businessType, goodsCn)
.any { !it.value.isNullOrEmpty() } .any { !it.value.isNullOrEmpty() }
} }
addSource(spCode, update) addSource(spCode, update)
addSource(flightNo, update) addSource(outStatus, update)
addSource(origin, update) addSource(origin, update)
addSource(awbType, update) addSource(awbType, update)
addSource(businessType, update) addSource(businessType, update)
@@ -108,7 +109,7 @@ class IntImpQueryViewModel : BasePageViewModel(), IOnItemClickListener {
fun resetFilter() { fun resetFilter() {
spCode.value = "" spCode.value = ""
flightNo.value = "" outStatus.value = ""
origin.value = "" origin.value = ""
awbType.value = "" awbType.value = ""
businessType.value = "" businessType.value = ""
@@ -176,6 +177,7 @@ class IntImpQueryViewModel : BasePageViewModel(), IOnItemClickListener {
totalCount.value = (data?.wbNumber ?: 0).toString() totalCount.value = (data?.wbNumber ?: 0).toString()
totalPc.value = (data?.totalPc ?: 0).toString() totalPc.value = (data?.totalPc ?: 0).toString()
totalWeight.value = (data?.totalWeight ?: 0.0).toString() totalWeight.value = (data?.totalWeight ?: 0.0).toString()
totalFlightNumber.value = (data?.flightNumber ?: 0).toString()
} }
} }
} }

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android" <layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<data> <data>
@@ -356,7 +357,37 @@
android:layout_weight="0.605" /> android:layout_weight="0.605" />
</LinearLayout> </LinearLayout>
<!-- -->
<!-- 第8行交接图片 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginTop="15dp"
android:orientation="horizontal">
<TextView
completeSpace="@{5}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="交接图片"
android:textColor="@color/text_gray" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_pic"
itemLayoutId="@{viewModel.itemLayoutId}"
viewHolder="@{viewModel.itemViewHolder}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="9"
tools:listitem="@layout/item_image_select_new" />
</LinearLayout>
</LinearLayout> </LinearLayout>

View File

@@ -118,6 +118,12 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
autoQueryEnabled="@{true}"
autoQueryMaxLength="@{8}"
autoQueryMinLength="@{8}"
autoQueryParamKey="@{`wbNo`}"
autoQueryTitle="@{`选择运单号`}"
autoQueryUrl="@{`/IntImpManifest/pageQueryWbNoList`}"
enable="@{!viewModel.isDetailMode}" enable="@{!viewModel.isDetailMode}"
hint='@{"请输入运单号"}' hint='@{"请输入运单号"}'
title='@{"运单号"}' title='@{"运单号"}'

View File

@@ -274,9 +274,15 @@
style="@style/tv_bottom_btn" style="@style/tv_bottom_btn"
android:layout_marginEnd="15dp" android:layout_marginEnd="15dp"
android:onClick="@{()-> viewModel.sortingTallyClick()}" android:onClick="@{()-> viewModel.sortingTallyClick()}"
android:text="分拣理货" /> android:text="装机单" />
<!-- 货物发放按钮 (红色) --> <TextView
style="@style/tv_bottom_btn"
android:layout_marginEnd="15dp"
android:onClick="@{()-> viewModel.startTallyClick()}"
android:text="开始理货" />
<!-- 理货完成按钮 (红色) -->
<TextView <TextView
android:layout_width="100dp" android:layout_width="100dp"
android:layout_height="40dp" android:layout_height="40dp"
@@ -284,7 +290,7 @@
android:background="@drawable/bg_red_btn_bottom" android:background="@drawable/bg_red_btn_bottom"
android:gravity="center" android:gravity="center"
android:onClick="@{()-> viewModel.cargoReleaseClick()}" android:onClick="@{()-> viewModel.cargoReleaseClick()}"
android:text="货物发放" android:text="理货完成"
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="18sp" /> android:textSize="18sp" />

View File

@@ -72,15 +72,15 @@
type="@{SearchLayoutType.SPINNER}" type="@{SearchLayoutType.SPINNER}"
value="@={viewModel.agentId}" /> value="@={viewModel.agentId}" />
<!-- 出库状态 --> <!-- 航班号 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout <com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
android:id="@+id/flight_no_search"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
hint='@{"请选择出库状态"}' hint='@{"请输入航班号"}'
list="@{viewModel.outStatusList}" type="@{SearchLayoutType.INPUT}"
type="@{SearchLayoutType.SPINNER}" value="@={viewModel.flightNo}" />
value="@={viewModel.outStatus}" />
<!-- 运单号 --> <!-- 运单号 -->
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout <com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
@@ -201,6 +201,16 @@
android:textStyle="bold" android:textStyle="bold"
tools:text="总重量100" /> tools:text="总重量100" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text='@{`航班航次:` + viewModel.totalFlightNumber}'
android:textColor="@color/bottom_tool_tips_text_color"
android:textSize="16sp"
android:textStyle="bold"
tools:text="航班航次2" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View File

@@ -67,7 +67,7 @@
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
completeSpace="@{4}" completeSpace="@{5}"
android:text="运单号:" android:text="运单号:"
android:textSize="15sp" /> android:textSize="15sp" />
@@ -194,7 +194,7 @@
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
completeSpace="@{4}" completeSpace="@{5}"
android:text="品名(中)" android:text="品名(中)"
android:textSize="15sp" /> android:textSize="15sp" />

View File

@@ -68,17 +68,17 @@
type="@{DataLayoutType.SPINNER}" type="@{DataLayoutType.SPINNER}"
value='@={viewModel.spCode}' /> value='@={viewModel.spCode}' />
<!-- 航班号 --> <!-- 出库状态 -->
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew <com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:id="@+id/filter_flight_no"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="10dp" android:layout_marginBottom="10dp"
hint='@{"请输入航班号"}' hint='@{"请选择出库状态"}'
title='@{"航班号"}' list="@{viewModel.outStatusList}"
title='@{"出库状态"}'
titleLength="@{4}" titleLength="@{4}"
type="@{DataLayoutType.INPUT}" type="@{DataLayoutType.SPINNER}"
value='@={viewModel.flightNo}' /> value='@={viewModel.outStatus}' />
<!-- 始发港 --> <!-- 始发港 -->
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew <com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew

View File

@@ -0,0 +1,53 @@
package com.lukouguoji.hangban.page.edit
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.lukouguoji.hangban.R
import com.lukouguoji.hangban.databinding.ActivityHbFlightEditBinding
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.common.DetailsPageType
import com.lukouguoji.module_base.ktx.setUpperCaseAlphanumericFilter
class HbFlightEditActivity :
BaseBindingActivity<ActivityHbFlightEditBinding, HbFlightEditViewModel>() {
override fun layoutId() = R.layout.activity_hb_flight_edit
override fun viewModelClass() = HbFlightEditViewModel::class.java
override fun initOnCreate(savedInstanceState: Bundle?) {
binding.viewModel = viewModel
binding.flightNoInput.et.setUpperCaseAlphanumericFilter()
binding.fdepInput.et.setUpperCaseAlphanumericFilter()
binding.fdestInput.et.setUpperCaseAlphanumericFilter()
binding.registrationInput.et.setUpperCaseAlphanumericFilter()
viewModel.initOnCreated(intent)
// 动态设置标题(必须在 initOnCreated 之后pageType 已从 Intent 解析)
val title = when (viewModel.pageType.value) {
DetailsPageType.Modify -> "编辑航班"
else -> "新增航班"
}
setBackArrow(title)
}
companion object {
/**
* fid 为空表示新增,非空表示编辑
*/
@JvmStatic
fun start(context: Context, fid: String = "") {
val pageType =
if (fid.isEmpty()) DetailsPageType.Add.name else DetailsPageType.Modify.name
context.startActivity(
Intent(context, HbFlightEditActivity::class.java)
.putExtra(Constant.Key.PAGE_TYPE, pageType)
.putExtra(Constant.Key.ID, fid)
)
}
}
}

View File

@@ -0,0 +1,280 @@
package com.lukouguoji.hangban.page.edit
import android.content.Intent
import android.view.View
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.lukouguoji.module_base.base.BaseViewModel
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.common.ConstantEvent
import com.lukouguoji.module_base.common.DetailsPageType
import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.impl.FlowBus
import com.lukouguoji.module_base.ktx.formatDate
import com.lukouguoji.module_base.ktx.launchLoadingCollect
import com.lukouguoji.module_base.ktx.noNull
import com.lukouguoji.module_base.ktx.showToast
import com.lukouguoji.module_base.ktx.toRequestBody
import com.lukouguoji.module_base.ktx.verifyNullOrEmpty
import com.lukouguoji.module_base.util.DictUtils
import dev.DevUtils
import dev.utils.app.info.KeyValue
import dev.utils.common.DateUtils
import kotlinx.coroutines.launch
class HbFlightEditViewModel : BaseViewModel() {
val pageType = MutableLiveData(DetailsPageType.Add)
// 航班主键(编辑模式)
private var fid = ""
///////////////////////////////////////////////////////////////////////////
// 表单字段
///////////////////////////////////////////////////////////////////////////
val flightDate = MutableLiveData("")
val flightNo = MutableLiveData("")
val aircraftCode = MutableLiveData("")
val fdep = MutableLiveData("")
val jtz = MutableLiveData("")
val fdest = MutableLiveData("")
val countryType = MutableLiveData("")
val serviceType = MutableLiveData("")
val status = MutableLiveData("")
val scheduledTackOff = MutableLiveData("")
val estimatedTakeOff = MutableLiveData("")
val actualTakeOff = MutableLiveData("")
val scheduledArrival = MutableLiveData("")
val estimatedArrival = MutableLiveData("")
val actualArrival = MutableLiveData("")
val standId = MutableLiveData("")
val registration = MutableLiveData("")
val prefix = MutableLiveData("")
val flightStatus = MutableLiveData("")
val cmFlag = MutableLiveData("")
val delayFreeText = MutableLiveData("")
///////////////////////////////////////////////////////////////////////////
// 下拉列表
///////////////////////////////////////////////////////////////////////////
val countryTypeList = MutableLiveData<List<KeyValue>>(emptyList())
val serviceTypeList = MutableLiveData<List<KeyValue>>(emptyList())
val statusList = MutableLiveData<List<KeyValue>>(emptyList())
val flightStatusList = MutableLiveData<List<KeyValue>>(emptyList())
val cmFlagList = MutableLiveData<List<KeyValue>>(emptyList())
///////////////////////////////////////////////////////////////////////////
// 选项定义(服务端入库/过滤用 code详情接口返回中文名回填时需反查
///////////////////////////////////////////////////////////////////////////
private val countryTypeOptions = listOf(
KeyValue("国内", "0"),
KeyValue("国际", "1"),
KeyValue("地区", "2"),
KeyValue("混合", "3"),
)
private val serviceTypeOptions = listOf(
KeyValue("客机", "0"),
KeyValue("货机", "1"),
KeyValue("卡车", "2"),
)
private val statusOptions = listOf(
KeyValue("出港", "0"),
KeyValue("进港", "1"),
)
private val flightStatusOptions = listOf(
KeyValue("正常", "0"),
KeyValue("登机", "1"),
KeyValue("登机结束", "2"),
KeyValue("起飞", "3"),
KeyValue("到达", "4"),
KeyValue("取消", "5"),
KeyValue("备降", "6"),
KeyValue("删除发布", "7"),
KeyValue("延误", "8"),
KeyValue("未知", "9"),
)
private val cmFlagOptions = listOf(
KeyValue("有货邮", "0"),
KeyValue("无货邮", "1"),
)
///////////////////////////////////////////////////////////////////////////
// 方法区
///////////////////////////////////////////////////////////////////////////
fun initOnCreated(intent: Intent) {
pageType.value =
if (intent.getStringExtra(Constant.Key.PAGE_TYPE) == DetailsPageType.Modify.name)
DetailsPageType.Modify else DetailsPageType.Add
fid = intent.getStringExtra(Constant.Key.ID) ?: ""
if (pageType.value == DetailsPageType.Modify && fid.isNotEmpty()) {
loadDetails()
} else {
flightDate.value = DateUtils.getCurrentTime().formatDate()
loadDictLists()
}
}
/**
* 编辑模式:加载航班详情
*/
private fun loadDetails() {
launchLoadingCollect({
NetApply.api.getFlightDetails(fid)
}) {
onSuccess = {
it.data?.let { bean ->
flightDate.value = bean.fdate
flightNo.value = bean.fno
aircraftCode.value = bean.aircraftCode
fdep.value = bean.fdep
jtz.value = bean.jtz
fdest.value = bean.fdest
countryType.value = toCode(countryTypeOptions, bean.countryType)
serviceType.value = toCode(serviceTypeOptions, bean.serviceType)
status.value = toCode(statusOptions, bean.status)
scheduledTackOff.value = bean.scheduledTackOff
estimatedTakeOff.value = bean.estimatedTakeOff
actualTakeOff.value = bean.actualTakeOff
scheduledArrival.value = bean.scheduledArrival
estimatedArrival.value = bean.estimatedArrival
actualArrival.value = bean.actualArrival
standId.value = bean.standId
registration.value = bean.registration
prefix.value = bean.prefix
flightStatus.value = toCode(flightStatusOptions, bean.flightStatus)
cmFlag.value = toCode(cmFlagOptions, bean.cmFlag)
delayFreeText.value = bean.delayFreeText
}
// 字典加载必须在编辑数据回填之后,保证 checkedValue 可用
loadDictLists()
}
}
}
/**
* 加载下拉列表(编辑模式传 checkedValue 置顶选中项)
*/
private fun loadDictLists() {
val isModify = pageType.value == DetailsPageType.Modify
DictUtils.getCountryTypeList(
addAll = false,
checkedValue = if (isModify) countryType.value else null
) {
countryTypeList.postValue(if (isModify) it else listOf(KeyValue("", "")) + it)
}
serviceTypeList.value =
buildStaticList(serviceTypeOptions, if (isModify) serviceType.value else null)
statusList.value =
buildStaticList(statusOptions, if (isModify) status.value else null)
flightStatusList.value =
buildStaticList(flightStatusOptions, if (isModify) flightStatus.value else null)
cmFlagList.value =
buildStaticList(cmFlagOptions, if (isModify) cmFlag.value else null)
}
/**
* 值转 code详情接口可能返回中文名如“国际”“客机”统一转为 code 用于回填与提交
*/
private fun toCode(options: List<KeyValue>, raw: String?): String {
if (raw.isNullOrEmpty()) return ""
return options.firstOrNull { it.value == raw }?.value
?: options.firstOrNull { it.key == raw }?.value
?: raw
}
/**
* 静态下拉列表:新增模式首位置空项;编辑模式将选中项置顶
*/
private fun buildStaticList(list: List<KeyValue>, checkedValue: String?): List<KeyValue> {
if (checkedValue.isNullOrEmpty()) {
return listOf(KeyValue("", "")) + list
}
return list.filter { it.value == checkedValue } + list.filter { it.value != checkedValue }
}
/**
* 保存 点击
*/
fun onSaveClick(view: View) {
if (flightDate.value.verifyNullOrEmpty("请选择航班日期")) return
if (flightNo.value.verifyNullOrEmpty("请输入航班号")) return
if (fdep.value.verifyNullOrEmpty("请输入始发港")) return
if (fdest.value.verifyNullOrEmpty("请输入目的港")) return
val isModify = pageType.value == DetailsPageType.Modify
val dep = fdep.value?.trim().noNull()
val dest = fdest.value?.trim().noNull()
val params = mutableMapOf<String, Any?>(
"fdate" to flightDate.value,
"fno" to flightNo.value?.trim(),
"aircraftCode" to aircraftCode.value?.trim(),
"fdep" to dep,
"jtz" to jtz.value?.trim(),
"fdest" to dest,
"range" to "$dep-$dest",
"countryType" to countryType.value,
"countryName" to countryTypeList.value
?.firstOrNull { it.value == countryType.value }?.key,
"serviceType" to serviceType.value,
"status" to status.value,
"scheduledTackOff" to scheduledTackOff.value,
"estimatedTakeOff" to estimatedTakeOff.value,
"actualTakeOff" to actualTakeOff.value,
"scheduledArrival" to scheduledArrival.value,
"estimatedArrival" to estimatedArrival.value,
"actualArrival" to actualArrival.value,
"standId" to standId.value?.trim(),
"registration" to registration.value?.trim(),
"prefix" to prefix.value?.trim(),
"flightStatus" to flightStatus.value,
"cmFlag" to cmFlag.value,
"delayFreeText" to delayFreeText.value?.trim(),
)
if (isModify) {
params["fid"] = fid.toLongOrNull() ?: fid
}
launchLoadingCollect({
if (isModify) {
NetApply.api.updateFlight(params.toRequestBody())
} else {
NetApply.api.saveFlight(params.toRequestBody())
}
}) {
onSuccess = {
if (it.verifySuccess()) {
showToast(if (isModify) "修改成功" else "新增成功")
viewModelScope.launch {
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
}
DevUtils.getTopActivity().finish()
} else {
showToast(it.msg.noNull("保存失败"))
}
}
}
}
/**
* 取消 点击
*/
fun onCancelClick(view: View) {
DevUtils.getTopActivity().finish()
}
}

View File

@@ -5,6 +5,9 @@ import com.alibaba.android.arouter.facade.annotation.Route
import com.lukouguoji.hangban.R import com.lukouguoji.hangban.R
import com.lukouguoji.hangban.databinding.ActivityHbQueryListBinding import com.lukouguoji.hangban.databinding.ActivityHbQueryListBinding
import com.lukouguoji.module_base.base.BaseBindingActivity import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.common.ConstantEvent
import com.lukouguoji.module_base.impl.FlowBus
import com.lukouguoji.module_base.impl.observe
import com.lukouguoji.module_base.ktx.addOnItemClickListener import com.lukouguoji.module_base.ktx.addOnItemClickListener
import com.lukouguoji.module_base.ktx.getLifecycleOwner import com.lukouguoji.module_base.ktx.getLifecycleOwner
import com.lukouguoji.module_base.router.ARouterConstants import com.lukouguoji.module_base.router.ARouterConstants
@@ -26,6 +29,11 @@ class HbQueryListActivity :
binding.rv.addOnItemClickListener(viewModel) binding.rv.addOnItemClickListener(viewModel)
// 新增、编辑保存后刷新列表
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).observe(this) {
viewModel.refresh()
}
viewModel.refresh() viewModel.refresh()
} }

View File

@@ -28,6 +28,8 @@ class HbQueryListViewHolder(view: View) :
} }
notifyItemClick(position, binding.ll) notifyItemClick(position, binding.ll)
notifyItemClick(position, binding.tvModify)
notifyItemClick(position, binding.tvDelete)
} }
private fun setTextColorRecursive(view: View, color: Int) { private fun setTextColorRecursive(view: View, color: Int) {

View File

@@ -3,6 +3,7 @@ package com.lukouguoji.hangban.page.query.list
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.alibaba.android.arouter.launcher.ARouter import com.alibaba.android.arouter.launcher.ARouter
import com.lukouguoji.hangban.R import com.lukouguoji.hangban.R
import com.lukouguoji.hangban.page.edit.HbFlightEditActivity
import com.lukouguoji.module_base.base.BasePageViewModel import com.lukouguoji.module_base.base.BasePageViewModel
import com.lukouguoji.module_base.bean.FlightBean import com.lukouguoji.module_base.bean.FlightBean
import com.lukouguoji.module_base.common.Constant import com.lukouguoji.module_base.common.Constant
@@ -10,9 +11,13 @@ import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.ktx.commonAdapter import com.lukouguoji.module_base.ktx.commonAdapter
import com.lukouguoji.module_base.ktx.formatDate import com.lukouguoji.module_base.ktx.formatDate
import com.lukouguoji.module_base.ktx.launchLoadingCollect import com.lukouguoji.module_base.ktx.launchLoadingCollect
import com.lukouguoji.module_base.ktx.noNull
import com.lukouguoji.module_base.ktx.showToast
import com.lukouguoji.module_base.ktx.toRequestBody import com.lukouguoji.module_base.ktx.toRequestBody
import com.lukouguoji.module_base.model.ConfirmDialogModel
import com.lukouguoji.module_base.router.ARouterConstants import com.lukouguoji.module_base.router.ARouterConstants
import com.lukouguoji.module_base.util.DictUtils import com.lukouguoji.module_base.util.DictUtils
import dev.DevUtils
import dev.utils.app.info.KeyValue import dev.utils.app.info.KeyValue
import dev.utils.common.DateUtils import dev.utils.common.DateUtils
@@ -80,11 +85,55 @@ class HbQueryListViewModel : BasePageViewModel() {
return "${d ?: ""}-${a ?: ""}" return "${d ?: ""}-${a ?: ""}"
} }
/**
* 新增 点击
*/
fun addClick() {
HbFlightEditActivity.start(DevUtils.getTopActivity())
}
override fun onItemClick(position: Int, type: Int) { override fun onItemClick(position: Int, type: Int) {
val bean = pageModel.rv!!.commonAdapter()!!.getItem(position) as FlightBean val bean = pageModel.rv!!.commonAdapter()!!.getItem(position) as FlightBean
when (type) {
R.id.tv_modify -> {
HbFlightEditActivity.start(DevUtils.getTopActivity(), bean.fid)
}
R.id.tv_delete -> {
ConfirmDialogModel(
message = "是否确认删除航班【${bean.fno}】?",
) {
onDelete(bean)
}.show(DevUtils.getTopActivity())
}
else -> {
ARouter.getInstance().build(ARouterConstants.ACTIVITY_URL_FLIGHT_QUERY_DETAILS) ARouter.getInstance().build(ARouterConstants.ACTIVITY_URL_FLIGHT_QUERY_DETAILS)
.withString(Constant.Key.ID, bean.fid) .withString(Constant.Key.ID, bean.fid)
.navigation() .navigation()
} }
}
}
/**
* 删除航班
*/
private fun onDelete(bean: FlightBean) {
launchLoadingCollect({
NetApply.api.deleteFlightList(
listOf(mapOf("fid" to bean.fid)).toRequestBody()
)
}) {
onSuccess = {
if (it.verifySuccess()) {
// 服务端删除接口的 msg 为“修改成功”,此处固定提示删除成功
showToast("删除成功")
refresh()
} else {
showToast(it.msg.noNull("删除失败"))
}
}
}
}
} }

View File

@@ -18,6 +18,11 @@
android:configChanges="orientation|keyboardHidden" android:configChanges="orientation|keyboardHidden"
android:screenOrientation="userLandscape" android:screenOrientation="userLandscape"
android:exported="false" /> android:exported="false" />
<activity
android:name=".page.edit.HbFlightEditActivity"
android:configChanges="orientation|keyboardHidden"
android:screenOrientation="userLandscape"
android:exported="false" />
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden" android:configChanges="orientation|keyboardHidden"

View File

@@ -0,0 +1,377 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="com.lukouguoji.module_base.ui.weight.data.layout.DataLayoutType" />
<variable
name="viewModel"
type="com.lukouguoji.hangban.page.edit.HbFlightEditViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_f2"
android:orientation="vertical">
<include layout="@layout/title_tool_bar" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="15dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_white_radius_8"
android:orientation="vertical"
android:padding="8dp">
<!-- 第1行航班日期、航班号、机型 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请选择航班日期"}'
required="@{true}"
title='@{"航班日期"}'
titleLength="@{4}"
type="@{DataLayoutType.DATE}"
value='@={viewModel.flightDate}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:id="@+id/flightNoInput"
hint='@{"请输入航班号"}'
required="@{true}"
title='@{"航班号"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.flightNo}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请输入机型"}'
title='@{"机型"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.aircraftCode}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1" />
</LinearLayout>
<!-- 第2行始发港、经停港、目的港 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:id="@+id/fdepInput"
hint='@{"请输入始发港"}'
required="@{true}"
title='@{"始发港"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.fdep}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"多个用英文逗号分隔"}'
title='@{"经停港"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.jtz}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:id="@+id/fdestInput"
hint='@{"请输入目的港"}'
required="@{true}"
title='@{"目的港"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.fdest}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1" />
</LinearLayout>
<!-- 第3行地区类型、服务类型、进出港 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请选择地区类型"}'
list="@{viewModel.countryTypeList}"
title='@{"地区类型"}'
titleLength="@{4}"
type="@{DataLayoutType.SPINNER}"
value='@={viewModel.countryType}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请选择服务类型"}'
list="@{viewModel.serviceTypeList}"
title='@{"服务类型"}'
titleLength="@{4}"
type="@{DataLayoutType.SPINNER}"
value='@={viewModel.serviceType}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请选择进出港"}'
list="@{viewModel.statusList}"
title='@{"进出港"}'
titleLength="@{4}"
type="@{DataLayoutType.SPINNER}"
value='@={viewModel.status}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1" />
</LinearLayout>
<!-- 第4行计划起飞、预计起飞、实际起飞 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请选择计划起飞时间"}'
title='@{"计划起飞"}'
titleLength="@{4}"
type="@{DataLayoutType.DATETIME}"
value='@={viewModel.scheduledTackOff}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请选择预计起飞时间"}'
title='@{"预计起飞"}'
titleLength="@{4}"
type="@{DataLayoutType.DATETIME}"
value='@={viewModel.estimatedTakeOff}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请选择实际起飞时间"}'
title='@{"实际起飞"}'
titleLength="@{4}"
type="@{DataLayoutType.DATETIME}"
value='@={viewModel.actualTakeOff}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1" />
</LinearLayout>
<!-- 第5行计划降落、预计降落、实际降落 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请选择计划降落时间"}'
title='@{"计划降落"}'
titleLength="@{4}"
type="@{DataLayoutType.DATETIME}"
value='@={viewModel.scheduledArrival}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请选择预计降落时间"}'
title='@{"预计降落"}'
titleLength="@{4}"
type="@{DataLayoutType.DATETIME}"
value='@={viewModel.estimatedArrival}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请选择实际降落时间"}'
title='@{"实际降落"}'
titleLength="@{4}"
type="@{DataLayoutType.DATETIME}"
value='@={viewModel.actualArrival}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1" />
</LinearLayout>
<!-- 第6行机位、机号、运单前缀 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请输入机位"}'
title='@{"机位"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.standId}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:id="@+id/registrationInput"
hint='@{"请输入机号"}'
title='@{"机号"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.registration}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请输入运单前缀"}'
title='@{"运单前缀"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.prefix}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1" />
</LinearLayout>
<!-- 第7行航班状态、货邮状态、延误原因 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请选择航班状态"}'
list="@{viewModel.flightStatusList}"
title='@{"航班状态"}'
titleLength="@{4}"
type="@{DataLayoutType.SPINNER}"
value='@={viewModel.flightStatus}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请选择货邮状态"}'
list="@{viewModel.cmFlagList}"
title='@{"货邮状态"}'
titleLength="@{4}"
type="@{DataLayoutType.SPINNER}"
value='@={viewModel.cmFlag}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1" />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请输入延误原因"}'
title='@{"延误原因"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@={viewModel.delayFreeText}'
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>
<!-- 底部操作栏 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:padding="15dp">
<TextView
android:layout_width="150dp"
android:layout_height="50dp"
android:layout_marginEnd="30dp"
android:background="@drawable/bg_primary_radius_4"
android:gravity="center"
android:onClick="@{viewModel::onCancelClick}"
android:text="取消"
android:textColor="@color/white"
android:textSize="18sp" />
<TextView
android:layout_width="150dp"
android:layout_height="50dp"
android:background="@drawable/bg_primary_radius_4"
android:gravity="center"
android:onClick="@{viewModel::onSaveClick}"
android:text="保存"
android:textColor="@color/white"
android:textSize="18sp" />
</LinearLayout>
</LinearLayout>
</ScrollView>
</LinearLayout>
</layout>

View File

@@ -104,6 +104,14 @@
android:padding="2dp" android:padding="2dp"
android:src="@drawable/img_search" /> android:src="@drawable/img_search" />
<!-- 新增按钮 -->
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="16dp"
android:onClick="@{()-> viewModel.addClick()}"
android:src="@drawable/img_add" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View File

@@ -10,12 +10,22 @@
type="com.lukouguoji.module_base.bean.FlightBean" /> type="com.lukouguoji.module_base.bean.FlightBean" />
</data> </data>
<androidx.appcompat.widget.LinearLayoutCompat <!-- 外层容器承载间距,使侧滑按钮紧贴卡片(参考 item_int_imp_pick_up_record -->
android:id="@+id/ll" <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="15dp" android:layout_marginHorizontal="15dp"
android:layout_marginVertical="5dp" android:layout_marginVertical="5dp"
android:orientation="vertical">
<com.mcxtzhang.swipemenulib.SwipeMenuLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/ll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_item" android:background="@drawable/bg_item"
android:gravity="center_vertical" android:gravity="center_vertical"
android:orientation="horizontal" android:orientation="horizontal"
@@ -318,4 +328,27 @@
android:src="@drawable/img_pda_right" /> android:src="@drawable/img_pda_right" />
</androidx.appcompat.widget.LinearLayoutCompat> </androidx.appcompat.widget.LinearLayoutCompat>
<!-- 侧滑操作按钮 -->
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="wrap_content"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_modify"
style="@style/tv_item_action"
android:background="@color/colorPrimary"
android:text="编辑" />
<TextView
android:id="@+id/tv_delete"
style="@style/tv_item_action"
android:background="#df253c"
android:text="删除" />
</androidx.appcompat.widget.LinearLayoutCompat>
</com.mcxtzhang.swipemenulib.SwipeMenuLayout>
</LinearLayout>
</layout> </layout>

View File

@@ -23,7 +23,7 @@ class PdaGnjXieJiAddActivity :
} }
override fun initOnCreate(savedInstanceState: Bundle?) { override fun initOnCreate(savedInstanceState: Bundle?) {
setBackArrow("国内进港开始卸机") setBackArrow("进港开始卸机")
viewModel.rv = binding.rv viewModel.rv = binding.rv
binding.viewModel = viewModel binding.viewModel = viewModel
binding.rv.addOnItemClickListener(viewModel) binding.rv.addOnItemClickListener(viewModel)

View File

@@ -27,7 +27,7 @@ class PdaGnjXieJiListActivity :
} }
override fun initOnCreate(savedInstanceState: Bundle?) { override fun initOnCreate(savedInstanceState: Bundle?) {
setBackArrow("国内进港卸机") setBackArrow("进港卸机")
binding.viewModel = viewModel binding.viewModel = viewModel
viewModel.pageModel.bindSmartRefreshLayout( viewModel.pageModel.bindSmartRefreshLayout(