Compare commits

..

3 Commits

Author SHA1 Message Date
75bfe85f62 feat: 航班表单三个枚举下拉对接字典接口并补全字段
新增页补上飞行状态输入项;飞行状态、航班服务种类、航班状态三个
下拉改为调用 typeCode 字典接口,替换原有的硬编码选项(旧的航班
状态码值与服务端实际码值完全不同)。详情页加载同一批字典,按值
反查并显示 label。新增页与详情页字段对齐为同一套。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-17 12:21:01 +08:00
f39127436a feat: 国际出港开始组装板型下拉改为控件下方展开
板型由底部弹框选择改为锚定在输入框正下方的 ListPopupWindow,
复用相邻 BUP Spinner 的弹层背景与列表项布局,外观保持一致,
且不影响手动输入。

板型数据源的承运人参数改由 ULD 编号触发:选中运单不再重载,
改为 ULD 信息查询成功后取 ULD 编号后两位作为 carrier 重新加载。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 11:49:06 +08:00
6b02f71e8a fix: 国际进港仓库清仓入参改为 body 传递
清仓原先把 clearNormal/clearRemark 放在 URL query 上,与接口文档不符。
改为与国际出港一致的单对象 body:clearNormal、clearRemark 在顶层,
选中数据放 warehouseList(出港侧对应字段为 maWbList)。
同时移除逐条写入主单 clearRemark 的兼容写法。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 11:24:58 +08:00
11 changed files with 400 additions and 193 deletions

View File

@@ -7,6 +7,8 @@ import com.lukouguoji.module_base.bean.FlightBean
import com.lukouguoji.module_base.common.Constant import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.http.net.NetApply import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.ktx.launchLoadingCollect import com.lukouguoji.module_base.ktx.launchLoadingCollect
import com.lukouguoji.module_base.util.DictUtils
import dev.utils.app.info.KeyValue
class FlightQueryDetailsViewModel : BaseViewModel() { class FlightQueryDetailsViewModel : BaseViewModel() {
@@ -14,9 +16,24 @@ class FlightQueryDetailsViewModel : BaseViewModel() {
var dataBean = MutableLiveData<FlightBean>() var dataBean = MutableLiveData<FlightBean>()
///////////////////////////////////////////////////////////////////////////
// 枚举字段展示文案接口已返回名称时原样显示只返回值code时按字典反查名称
///////////////////////////////////////////////////////////////////////////
val countryTypeText = MutableLiveData("")
val serviceTypeText = MutableLiveData("")
val portCodeText = MutableLiveData("")
val flightStatusText = MutableLiveData("")
private var countryTypeDict = emptyList<KeyValue>()
private var serviceTypeDict = emptyList<KeyValue>()
private var portCodeDict = emptyList<KeyValue>()
private var flightStatusDict = emptyList<KeyValue>()
fun initOnCreated(intent: Intent) { fun initOnCreated(intent: Intent) {
id = intent.getStringExtra(Constant.Key.ID) ?: "" id = intent.getStringExtra(Constant.Key.ID) ?: ""
loadDictLists()
getData() getData()
} }
@@ -27,8 +44,52 @@ class FlightQueryDetailsViewModel : BaseViewModel() {
onSuccess = { onSuccess = {
it.data?.let { data -> it.data?.let { data ->
dataBean.value = data dataBean.value = data
refreshEnumText()
} }
} }
} }
} }
/**
* 加载四个枚举字典(与新增/编辑页同源),用于把 code 反查成 label
*/
private fun loadDictLists() {
DictUtils.getCountryTypeList(addAll = false) {
countryTypeDict = it
refreshEnumText()
}
DictUtils.getFlightServiceTypeList(addAll = false) {
serviceTypeDict = it
refreshEnumText()
}
DictUtils.getFlightPortCodeList(addAll = false) {
portCodeDict = it
refreshEnumText()
}
DictUtils.getFlightStatusList(addAll = false) {
flightStatusDict = it
refreshEnumText()
}
}
/**
* 数据或字典任一就绪都重算一次,避免两者返回先后顺序影响展示
*/
private fun refreshEnumText() {
val bean = dataBean.value ?: return
countryTypeText.value = toLabel(countryTypeDict, bean.countryType)
serviceTypeText.value = toLabel(serviceTypeDict, bean.serviceType)
portCodeText.value = toLabel(portCodeDict, bean.portCode)
flightStatusText.value = toLabel(flightStatusDict, bean.flightStatus)
}
/**
* 值转 label先按 code 反查,命中不了再判断是否本身就是 label仍不命中则原样返回
*/
private fun toLabel(dict: List<KeyValue>, raw: String?): String {
if (raw.isNullOrEmpty()) return ""
dict.firstOrNull { it.value == raw }?.let { return it.key }
dict.firstOrNull { it.key == raw }?.let { return it.key }
return raw
}
} }

View File

@@ -37,7 +37,7 @@
android:orientation="vertical" android:orientation="vertical"
android:padding="15dp"> android:padding="15dp">
<!-- 第1行航班日期、航班号、航程 --> <!-- 第1行航班日期、航班号、机型 -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -68,20 +68,69 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
enable="@{false}" enable="@{false}"
title='@{"航程"}' title='@{"机型"}'
titleLength="@{4}" titleLength="@{4}"
type="@{DataLayoutType.INPUT}" type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.range}' /> value='@{viewModel.dataBean.aircraftCode}' />
</LinearLayout> </LinearLayout>
<!-- 第2行地区类型、服务类型、经停站 --> <!-- 第2行始发港、经停港、目的港 -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:orientation="horizontal"> 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="@{false}"
title='@{"始发港"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.fdep}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{false}"
title='@{"经停港"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.jtz}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{false}"
title='@{"目的港"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.fdest}' />
</LinearLayout>
<!-- 第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="@{false}"
title='@{"航程"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.range}' />
<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"
@@ -90,7 +139,7 @@
title='@{"地区类型"}' title='@{"地区类型"}'
titleLength="@{4}" titleLength="@{4}"
type="@{DataLayoutType.INPUT}" type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.countryType}' /> value='@{viewModel.countryTypeText}' />
<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"
@@ -100,21 +149,50 @@
title='@{"服务类型"}' title='@{"服务类型"}'
titleLength="@{4}" titleLength="@{4}"
type="@{DataLayoutType.INPUT}" type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.serviceType}' /> value='@{viewModel.serviceTypeText}' />
</LinearLayout>
<!-- 第4行飞行状态、航班状态、延误原因 -->
<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 <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_weight="1" android:layout_weight="1"
enable="@{false}" enable="@{false}"
title='@{"经停站"}' title='@{"飞行状态"}'
titleLength="@{4}" titleLength="@{4}"
type="@{DataLayoutType.INPUT}" type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.jtz}' /> value='@{viewModel.portCodeText}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{false}"
title='@{"航班状态"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.flightStatusText}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{false}"
title='@{"延误原因"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.delayFreeText}' />
</LinearLayout> </LinearLayout>
<!--3行:计划起飞、预计起飞、实际起飞 --> <!--5行:计划起飞、预计起飞、实际起飞 -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -153,7 +231,7 @@
</LinearLayout> </LinearLayout>
<!--4行:计划降落、预计降落、实际降落 --> <!--6行:计划降落、预计降落、实际降落 -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -192,72 +270,13 @@
</LinearLayout> </LinearLayout>
<!--5行:飞行状态、航班状态、延误原因 --> <!--7行:机位、机号 -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:orientation="horizontal"> 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="@{false}"
title='@{"飞行状态"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.portCode}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{false}"
title='@{"航班状态"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.flightStatus}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{false}"
title='@{"延误原因"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.delayFreeText}' />
</LinearLayout>
<!-- 第6行机号、机型、机位 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_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="@{false}"
title='@{"机号"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.registration}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{false}"
title='@{"机型"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.aircraftCode}' />
<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"
@@ -268,6 +287,21 @@
type="@{DataLayoutType.INPUT}" type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.standId}' /> value='@{viewModel.dataBean.standId}' />
<com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
enable="@{false}"
title='@{"机号"}'
titleLength="@{4}"
type="@{DataLayoutType.INPUT}"
value='@{viewModel.dataBean.registration}' />
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View File

@@ -312,6 +312,24 @@ interface Api {
@POST("typeCode/countryType") @POST("typeCode/countryType")
suspend fun getCountryTypeList(): DictListBean suspend fun getCountryTypeList(): DictListBean
/**
* 获取飞行状态
*/
@POST("typeCode/flightPortCode")
suspend fun getFlightPortCodeList(): DictListBean
/**
* 获取航班服务种类
*/
@POST("typeCode/flightServiceType")
suspend fun getFlightServiceTypeList(): DictListBean
/**
* 获取航班状态
*/
@POST("typeCode/flightStatus")
suspend fun getFlightStatusList(): DictListBean
/** /**
* 获取国家代码 * 获取国家代码
*/ */
@@ -991,11 +1009,7 @@ interface Api {
* 接口路径: /IntImpStorage/updateClear * 接口路径: /IntImpStorage/updateClear
*/ */
@POST("IntImpStorage/updateClear") @POST("IntImpStorage/updateClear")
suspend fun clearIntImpStorage( suspend fun clearIntImpStorage(@Body data: RequestBody): BaseResultBean<Boolean>
@Query("clearNormal") clearNormal: String,
@Query("clearRemark") clearRemark: String?,
@Body data: RequestBody
): BaseResultBean<Boolean>
/** /**
* 国际进港库位操作-修改库位 * 国际进港库位操作-修改库位

View File

@@ -490,6 +490,60 @@ object DictUtils {
} }
} }
/**
* 飞行状态0:前方起飞 1:过站登机 2:登机结束 6:到达 7:登机 9:正在值机 …)
*/
fun getFlightPortCodeList(
addAll: Boolean = true,
checkedValue: String? = null,
callBack: (List<KeyValue>) -> Unit
) {
launchCollect({
NetApply.api
.getFlightPortCodeList()
}) {
onSuccess = {
handleCallBack(it, checkedValue, addAll, callBack)
}
}
}
/**
* 航班服务种类0:客机 1:货机 2:卡车)
*/
fun getFlightServiceTypeList(
addAll: Boolean = true,
checkedValue: String? = null,
callBack: (List<KeyValue>) -> Unit
) {
launchCollect({
NetApply.api
.getFlightServiceTypeList()
}) {
onSuccess = {
handleCallBack(it, checkedValue, addAll, callBack)
}
}
}
/**
* 航班状态3:返航 4:地面滑回 5:备降 8:取消 12:延误 15:删除 16:未知)
*/
fun getFlightStatusList(
addAll: Boolean = true,
checkedValue: String? = null,
callBack: (List<KeyValue>) -> Unit
) {
launchCollect({
NetApply.api
.getFlightStatusList()
}) {
onSuccess = {
handleCallBack(it, checkedValue, addAll, callBack)
}
}
}
/** /**
* 获取角色列表 * 获取角色列表
*/ */

View File

@@ -5,6 +5,10 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.ArrayAdapter
import androidx.appcompat.widget.AppCompatSpinner
import androidx.appcompat.widget.ListPopupWindow
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.alibaba.android.arouter.facade.annotation.Route import com.alibaba.android.arouter.facade.annotation.Route
import com.lukouguoji.gjc.R import com.lukouguoji.gjc.R
@@ -19,6 +23,7 @@ import com.lukouguoji.module_base.impl.observe
import com.lukouguoji.module_base.interfaces.IOnItemClickListener import com.lukouguoji.module_base.interfaces.IOnItemClickListener
import com.lukouguoji.module_base.ktx.addOnItemClickListener import com.lukouguoji.module_base.ktx.addOnItemClickListener
import com.lukouguoji.module_base.ktx.setUpperCaseAlphanumericFilter import com.lukouguoji.module_base.ktx.setUpperCaseAlphanumericFilter
import com.lukouguoji.module_base.ktx.showToast
import com.lukouguoji.module_base.router.ARouterConstants import com.lukouguoji.module_base.router.ARouterConstants
/** /**
@@ -29,6 +34,7 @@ class IntExpAssembleStartActivity :
BaseBindingActivity<ActivityIntExpAssembleStartBinding, IntExpAssembleStartViewModel>(), BaseBindingActivity<ActivityIntExpAssembleStartBinding, IntExpAssembleStartViewModel>(),
IOnItemClickListener { IOnItemClickListener {
private var boardTypePopup: ListPopupWindow? = null
private var assembleInfoAdapter: CommonAdapter? = null private var assembleInfoAdapter: CommonAdapter? = null
private var assemblePositionAdapter: CommonAdapter? = null private var assemblePositionAdapter: CommonAdapter? = null
private var waybillAdapter: CommonAdapter? = null private var waybillAdapter: CommonAdapter? = null
@@ -72,11 +78,12 @@ class IntExpAssembleStartActivity :
binding.impCodeInput.et.setUpperCaseAlphanumericFilter() binding.impCodeInput.et.setUpperCaseAlphanumericFilter()
// 板型:手动输入 + 下拉选择组合框。箭头复用 Spinner 同款背景绘制(同资源、同尺寸、同边距), // 板型:手动输入 + 下拉选择组合框。箭头复用 Spinner 同款背景绘制(同资源、同尺寸、同边距),
// 图标位不放图片,仅作为覆盖在箭头上的透明点击区域(点击事件由布局 setOnIconClickListener 绑定) // 图标位不放图片,仅作为覆盖在箭头上的透明点击区域
binding.boardTypeInput.apply { binding.boardTypeInput.apply {
ll.setBackgroundResource(com.lukouguoji.module_base.R.drawable.bg_data_layout_new_dropdown) ll.setBackgroundResource(com.lukouguoji.module_base.R.drawable.bg_data_layout_new_dropdown)
iv.setImageDrawable(null) iv.setImageDrawable(null)
iv.visibility = View.VISIBLE iv.visibility = View.VISIBLE
iv.setOnClickListener { showBoardTypeDropdown() }
} }
// 初始化列表 // 初始化列表
@@ -106,6 +113,51 @@ class IntExpAssembleStartActivity :
handleEditModeIntent() handleEditModeIntent()
} }
/**
* 板型下拉:锚定在板型输入框正下方展开(外观与相邻 BUP 的 Spinner 下拉一致),选中后回填,仍可手动输入
*/
private fun showBoardTypeDropdown() {
val list = viewModel.boardTypeList.value ?: emptyList()
if (list.isEmpty()) {
showToast("暂无板型选项,请手动输入")
return
}
val anchor = binding.boardTypeInput.ll
// 先收起软键盘,避免下拉被输入法遮挡
(getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager)
?.hideSoftInputFromWindow(anchor.windowToken, 0)
boardTypePopup?.dismiss()
boardTypePopup = ListPopupWindow(this).apply {
anchorView = anchor
width = anchor.width
isModal = true
// 复用 BUP Spinner 的弹窗背景,保证两者下拉外观完全一致
(binding.bupFlagInput.spinner as? AppCompatSpinner)?.popupBackground
?.constantState?.newDrawable()?.mutate()
?.let { setBackgroundDrawable(it) }
setAdapter(
ArrayAdapter(
this@IntExpAssembleStartActivity,
com.lukouguoji.module_base.R.layout.item_spinner_list,
list.map { it.key }
)
)
setOnItemClickListener { _, _, position, _ ->
viewModel.onBoardTypeSelected(position)
dismiss()
}
show()
}
}
override fun onDestroy() {
boardTypePopup?.dismiss()
boardTypePopup = null
super.onDestroy()
}
/** /**
* 处理修改模式的 Intent 参数 * 处理修改模式的 Intent 参数
*/ */

View File

@@ -2,7 +2,6 @@ package com.lukouguoji.gjc.viewModel
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.alibaba.fastjson.JSONArray
import com.lukouguoji.gjc.R import com.lukouguoji.gjc.R
import com.lukouguoji.gjc.holder.AssembleInfoViewHolder import com.lukouguoji.gjc.holder.AssembleInfoViewHolder
import com.lukouguoji.gjc.holder.AssemblePositionViewHolder import com.lukouguoji.gjc.holder.AssemblePositionViewHolder
@@ -17,10 +16,8 @@ import com.lukouguoji.module_base.impl.FlowBus
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.showToast import com.lukouguoji.module_base.ktx.showToast
import com.lukouguoji.module_base.ktx.toJson
import com.lukouguoji.module_base.ktx.toRequestBody import com.lukouguoji.module_base.ktx.toRequestBody
import com.lukouguoji.module_base.model.ScanModel import com.lukouguoji.module_base.model.ScanModel
import com.lukouguoji.module_base.util.Common
import com.lukouguoji.module_base.util.DictUtils import com.lukouguoji.module_base.util.DictUtils
import dev.utils.app.info.KeyValue import dev.utils.app.info.KeyValue
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -271,9 +268,6 @@ class IntExpAssembleStartViewModel : BaseViewModel() {
assembleWeight = previousAssembleWeight assembleWeight = previousAssembleWeight
operator = previousOperator // 从operator LiveData获取的值 operator = previousOperator // 从operator LiveData获取的值
} }
// 按该运单航班号前两位(承运人)重新加载板型选项,覆盖下拉数据源
loadBoardTypeList(selectedWaybill.fno.trim().take(2))
} }
// 刷新列表 // 刷新列表
@@ -419,35 +413,22 @@ class IntExpAssembleStartViewModel : BaseViewModel() {
/** /**
* 加载板型选项列表 * 加载板型选项列表
* @param carrier 承运人二字码(待组装运单航班号前两位);进入页面时不传,选中运单后按承运人重新加载并覆盖数据源 * @param carrier 承运人二字码(ULD 编号后两位);进入页面时不传取全量ULD 信息查询成功后按承运人重新加载并覆盖数据源
*/ */
fun loadBoardTypeList(carrier: String? = null) { fun loadBoardTypeList(carrier: String? = null) {
DictUtils.getBoardTypeList(carrier) { boardTypeList.value = it } DictUtils.getBoardTypeList(carrier) { boardTypeList.value = it }
} }
/** /**
* 板型下拉图标点击:弹出选项列表,选中后回填到板型输入框(回填后仍可手动修改) * 板型下拉选中回调:回填到板型输入框(回填后仍可手动修改)
* 下拉列表由 Activity 以锚定在输入框下方的 ListPopupWindow 弹出(外观与 BUP 的 Spinner 一致)
*/ */
fun onBoardTypeSelectClick() { fun onBoardTypeSelected(position: Int) {
val list = boardTypeList.value ?: emptyList() val list = boardTypeList.value ?: emptyList()
if (list.isEmpty()) {
showToast("暂无板型选项,请手动输入")
return
}
val jsonArray = JSONArray.parseArray(
list.map { mapOf("name" to it.key, "code" to it.value) }.toJson(false)
)
Common.singleSelect(
getTopActivity(),
"选择板型",
jsonArray,
uldInfo.value?.boardType
) { position, _ ->
uldInfo.value = uldInfo.value?.apply { uldInfo.value = uldInfo.value?.apply {
boardType = list.getOrNull(position)?.value ?: "" boardType = list.getOrNull(position)?.value ?: ""
} }
} }
}
/** /**
* ULD编号输入完成时调用 * ULD编号输入完成时调用
@@ -489,6 +470,10 @@ class IntExpAssembleStartViewModel : BaseViewModel() {
if (!uldBean.bupFlag.isNullOrEmpty()) bupFlag = uldBean.bupFlag if (!uldBean.bupFlag.isNullOrEmpty()) bupFlag = uldBean.bupFlag
} }
// 按 ULD 编号后两位(承运人二字码)重新加载板型选项,覆盖下拉数据源
val carrier = uldNo.trim().takeLast(2)
if (carrier.length == 2) loadBoardTypeList(carrier)
// 【新增】从ULD信息提取航班信息 // 【新增】从ULD信息提取航班信息
if (uldBean.fno.isNotEmpty() && uldBean.fdate.isNotEmpty()) { if (uldBean.fno.isNotEmpty() && uldBean.fdate.isNotEmpty()) {
assembleFlightNo.value = uldBean.fno assembleFlightNo.value = uldBean.fno

View File

@@ -319,7 +319,6 @@
enable="@{true}" enable="@{true}"
hint='@{"请输入或选择"}' hint='@{"请输入或选择"}'
required="@{false}" required="@{false}"
setOnIconClickListener="@{(v) -> viewModel.onBoardTypeSelectClick()}"
setTextAllCaps="@{true}" setTextAllCaps="@{true}"
title='@{"板型:"}' title='@{"板型:"}'
titleLength="@{5}" titleLength="@{5}"
@@ -330,6 +329,7 @@
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
android:id="@+id/bupFlagInput"
enable="@{true}" enable="@{true}"
list="@{viewModel.bupFlagList}" list="@{viewModel.bupFlagList}"
required="@{false}" required="@{false}"

View File

@@ -56,7 +56,7 @@ class IntImpStorageUseActivity :
val list = viewModel.pageModel.rv?.commonAdapter()?.items as? List<*> ?: return val list = viewModel.pageModel.rv?.commonAdapter()?.items as? List<*> ?: return
val allItems = list.filterIsInstance<com.lukouguoji.module_base.bean.GjcMaWb>() val allItems = list.filterIsInstance<com.lukouguoji.module_base.bean.GjcMaWb>()
val maWbListForClear = allItems.mapNotNull { maWb -> val warehouseListForClear = allItems.mapNotNull { maWb ->
if (maWb.isSelected) { if (maWb.isSelected) {
// 勾选运单号 → 默认全选该运单号下的所有库位 // 勾选运单号 → 默认全选该运单号下的所有库位
maWb.copy(storageUseList = maWb.storageUseList ?: emptyList()) maWb.copy(storageUseList = maWb.storageUseList ?: emptyList())
@@ -71,7 +71,7 @@ class IntImpStorageUseActivity :
} }
} }
if (maWbListForClear.isEmpty()) { if (warehouseListForClear.isEmpty()) {
showToast("请至少选择一个库位") showToast("请至少选择一个库位")
return return
} }
@@ -79,7 +79,7 @@ class IntImpStorageUseActivity :
IntImpMoveClearDialogModel { dialog -> IntImpMoveClearDialogModel { dialog ->
val clearNormal = dialog.clearNormal.value ?: "" val clearNormal = dialog.clearNormal.value ?: ""
val clearRemark = dialog.clearRemark.value ?: "" val clearRemark = dialog.clearRemark.value ?: ""
viewModel.performClear(clearNormal, clearRemark, maWbListForClear) viewModel.performClear(clearNormal, clearRemark, warehouseListForClear)
}.show(this) }.show(this)
} }

View File

@@ -119,20 +119,22 @@ class IntImpStorageUseViewModel : BasePageViewModel() {
* 执行清仓操作 * 执行清仓操作
* @param clearNormal 清仓正常("0"或"1" * @param clearNormal 清仓正常("0"或"1"
* @param clearRemark 清仓备注(选填) * @param clearRemark 清仓备注(选填)
* @param maWbListForClear 包含选中子列表项的主列表数据 * @param warehouseListForClear 包含选中子列表项的主列表数据
*/ */
fun performClear(clearNormal: String, clearRemark: String, maWbListForClear: List<GjcMaWb>) { fun performClear(clearNormal: String, clearRemark: String, warehouseListForClear: List<GjcMaWb>) {
if (maWbListForClear.isEmpty()) { if (warehouseListForClear.isEmpty()) {
showToast("请至少选择一个库位") showToast("请至少选择一个库位")
return return
} }
// 备注同时通过 query 参数和主单字段传递,兼容服务端两种取值方式 // 构建请求参数:清仓标志与备注在顶层,选中数据放 warehouseList
val remark = clearRemark.ifEmpty { null } val params = mapOf(
maWbListForClear.forEach { it.clearRemark = remark } "clearNormal" to clearNormal,
val body = maWbListForClear.toRequestBody() "clearRemark" to clearRemark.ifEmpty { null },
"warehouseList" to warehouseListForClear
).toRequestBody()
launchLoadingCollect({ NetApply.api.clearIntImpStorage(clearNormal, remark, body) }) { launchLoadingCollect({ NetApply.api.clearIntImpStorage(params) }) {
onSuccess = { onSuccess = {
showToast("清仓成功") showToast("清仓成功")
viewModelScope.launch { viewModelScope.launch {

View File

@@ -41,6 +41,7 @@ class HbFlightEditViewModel : BaseViewModel() {
val fdest = MutableLiveData("") val fdest = MutableLiveData("")
val countryType = MutableLiveData("") val countryType = MutableLiveData("")
val serviceType = MutableLiveData("") val serviceType = MutableLiveData("")
val portCode = MutableLiveData("")
val scheduledTackOff = MutableLiveData("") val scheduledTackOff = MutableLiveData("")
val estimatedTakeOff = MutableLiveData("") val estimatedTakeOff = MutableLiveData("")
val actualTakeOff = MutableLiveData("") val actualTakeOff = MutableLiveData("")
@@ -64,42 +65,17 @@ class HbFlightEditViewModel : BaseViewModel() {
val countryTypeList = MutableLiveData<List<KeyValue>>(emptyList()) val countryTypeList = MutableLiveData<List<KeyValue>>(emptyList())
val serviceTypeList = MutableLiveData<List<KeyValue>>(emptyList()) val serviceTypeList = MutableLiveData<List<KeyValue>>(emptyList())
val flightStatusList = MutableLiveData<List<KeyValue>>(emptyList()) val flightStatusList = MutableLiveData<List<KeyValue>>(emptyList())
val portCodeList = MutableLiveData<List<KeyValue>>(emptyList())
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// 选项定义(服务端入库/过滤用 code详情接口返回中文名回填时需反查 // 选项定义(服务端入库/过滤用 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( private val statusOptions = listOf(
KeyValue("出港", "0"), KeyValue("出港", "0"),
KeyValue("进港", "1"), 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( private val cmFlagOptions = listOf(
KeyValue("有货邮", "0"), KeyValue("有货邮", "0"),
KeyValue("无货邮", "1"), KeyValue("无货邮", "1"),
@@ -138,8 +114,12 @@ class HbFlightEditViewModel : BaseViewModel() {
fdep.value = bean.fdep fdep.value = bean.fdep
jtz.value = bean.jtz jtz.value = bean.jtz
fdest.value = bean.fdest fdest.value = bean.fdest
countryType.value = toCode(countryTypeOptions, bean.countryType) // 枚举字段(地区类型/服务类型/航班状态/飞行状态)由详情接口返回中文名,
serviceType.value = toCode(serviceTypeOptions, bean.serviceType) // 统一在字典加载回调里转 code此处先原样存放
countryType.value = bean.countryType
serviceType.value = bean.serviceType
flightStatus.value = bean.flightStatus
portCode.value = bean.portCode
status = toCode(statusOptions, bean.status) status = toCode(statusOptions, bean.status)
scheduledTackOff.value = bean.scheduledTackOff scheduledTackOff.value = bean.scheduledTackOff
estimatedTakeOff.value = bean.estimatedTakeOff estimatedTakeOff.value = bean.estimatedTakeOff
@@ -150,7 +130,6 @@ class HbFlightEditViewModel : BaseViewModel() {
standId.value = bean.standId standId.value = bean.standId
registration.value = bean.registration registration.value = bean.registration
prefix = bean.prefix.noNull() prefix = bean.prefix.noNull()
flightStatus.value = toCode(flightStatusOptions, bean.flightStatus)
cmFlag = toCode(cmFlagOptions, bean.cmFlag) cmFlag = toCode(cmFlagOptions, bean.cmFlag)
delayFreeText.value = bean.delayFreeText delayFreeText.value = bean.delayFreeText
} }
@@ -161,27 +140,36 @@ class HbFlightEditViewModel : BaseViewModel() {
} }
/** /**
* 加载下拉列表(编辑模式传 checkedValue 置顶选中项 * 加载下拉列表(四个数据源均来自 typeCode 字典接口
*/ */
private fun loadDictLists() { private fun loadDictLists() {
val isModify = pageType.value == DetailsPageType.Modify val isModify = pageType.value == DetailsPageType.Modify
DictUtils.getCountryTypeList( DictUtils.getCountryTypeList(addAll = false) { applyDict(it, countryType, countryTypeList, isModify) }
addAll = false, DictUtils.getFlightServiceTypeList(addAll = false) { applyDict(it, serviceType, serviceTypeList, isModify) }
checkedValue = if (isModify) countryType.value else null DictUtils.getFlightStatusList(addAll = false) { applyDict(it, flightStatus, flightStatusList, isModify) }
) { DictUtils.getFlightPortCodeList(addAll = false) { applyDict(it, portCode, portCodeList, isModify) }
countryTypeList.postValue(if (isModify) it else listOf(KeyValue("", "")) + it)
}
serviceTypeList.value =
buildStaticList(serviceTypeOptions, if (isModify) serviceType.value else null)
flightStatusList.value =
buildStaticList(flightStatusOptions, if (isModify) flightStatus.value else null)
} }
/** /**
* 值转 code详情接口可能返回中文名(如“国际”“客机”),统一转 code 用于回填与提交 * 字典就绪后:编辑模式把详情返回中文名统一转 code,再把列表交给下拉框
*
* 下拉框带 hintvalue 为空时自动停在 hint 项,因此新增模式无需补空项
*/
private fun applyDict(
list: List<KeyValue>,
field: MutableLiveData<String>,
listField: MutableLiveData<List<KeyValue>>,
isModify: Boolean,
) {
if (isModify) {
field.value = toCode(list, field.value)
}
listField.value = list
}
/**
* 值转 code详情接口返回的是中文名如“国际”“客机”“延误”统一转为 code 用于回填与提交
*/ */
private fun toCode(options: List<KeyValue>, raw: String?): String { private fun toCode(options: List<KeyValue>, raw: String?): String {
if (raw.isNullOrEmpty()) return "" if (raw.isNullOrEmpty()) return ""
@@ -190,16 +178,6 @@ class HbFlightEditViewModel : BaseViewModel() {
?: raw ?: 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 }
}
/** /**
* 保存 点击 * 保存 点击
*/ */
@@ -239,6 +217,7 @@ class HbFlightEditViewModel : BaseViewModel() {
"actualArrival" to actualArrival.value, "actualArrival" to actualArrival.value,
"standId" to standId.value?.trim(), "standId" to standId.value?.trim(),
"registration" to registration.value?.trim(), "registration" to registration.value?.trim(),
"portCode" to portCode.value,
"flightStatus" to flightStatus.value, "flightStatus" to flightStatus.value,
"delayFreeText" to delayFreeText.value?.trim(), "delayFreeText" to delayFreeText.value?.trim(),
) )

View File

@@ -171,7 +171,50 @@
</LinearLayout> </LinearLayout>
<!-- 第4行计划起飞、预计起飞、实际起飞 --> <!-- 第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='@{"请选择飞行状态"}'
list="@{viewModel.portCodeList}"
title='@{"飞行状态"}'
titleLength="@{4}"
type="@{DataLayoutType.SPINNER}"
value='@={viewModel.portCode}'
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.standId}'
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/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" />
</LinearLayout>
<!-- 第5行计划起飞、预计起飞、实际起飞 -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -214,7 +257,7 @@
</LinearLayout> </LinearLayout>
<!--5行:计划降落、预计降落、实际降落 --> <!--6行:计划降落、预计降落、实际降落 -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -257,35 +300,13 @@
</LinearLayout> </LinearLayout>
<!--6行:机位、机号、延误原因 --> <!--7行:延误原因 -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:orientation="horizontal"> 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 <com.lukouguoji.module_base.ui.weight.data.layout.PadDataLayoutNew
hint='@{"请输入延误原因"}' hint='@{"请输入延误原因"}'
title='@{"延误原因"}' title='@{"延误原因"}'
@@ -294,9 +315,14 @@
value='@={viewModel.delayFreeText}' value='@={viewModel.delayFreeText}'
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1" /> android:layout_weight="1" />
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="2" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>