fix: 国际进港舱单编辑页下拉框回填及移除404接口
- 使用 DictUtils checkedValue 机制回填编辑模式下拉框选中项 - 移除已404的 searchCargoType 接口调用 - PadDataLayoutNew 增加 updateSpinnerSilently 防止 adapter 重建覆盖值 - CLAUDE.md 补充编辑表单 SPINNER 回填规范 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
53
CLAUDE.md
53
CLAUDE.md
@@ -861,6 +861,59 @@ adb logcat | grep "com.lukouguoji.aerologic" # 日志
|
||||
|
||||
---
|
||||
|
||||
## 编辑表单下拉框(SPINNER)回填规范
|
||||
|
||||
编辑页面(DetailsPageType.Modify)中,下拉框需要根据已有数据自动选中对应项。**必须使用 `DictUtils` 的 `checkedValue` 参数**,禁止依赖组件自动匹配 value。
|
||||
|
||||
### 原理
|
||||
|
||||
`DictUtils` 的 `handleCallBack` 会将 `checkedValue` 匹配的 `KeyValue` 置于列表首位。`PadDataLayoutNew` 的 SPINNER 默认显示列表第 0 项,因此匹配项自动成为选中项,无需额外设置 selectedIndex。
|
||||
|
||||
### 标准做法(参考 `GjjManifestDetailsViewModel`、`GjjManifestAddViewModel`)
|
||||
|
||||
1. **字典加载必须在编辑数据加载之后**(不能放在 `init` 中),确保 `checkedValue` 可用
|
||||
2. **编辑模式传入 `checkedValue`**,新增模式传 `null`
|
||||
3. **编辑模式不预置空 `KeyValue("", "")`**(否则空项会占据首位,覆盖 checkedValue 排序)
|
||||
|
||||
```kotlin
|
||||
fun initOnCreated(intent: Intent) {
|
||||
// 1. 先解析页面类型和编辑数据
|
||||
if (pageType.value == DetailsPageType.Modify) {
|
||||
loadManifestFromBean(bean) // 设置 agent.value、specialCode.value 等
|
||||
}
|
||||
// 2. 再加载字典列表(此时 checkedValue 已可用)
|
||||
loadDictLists()
|
||||
}
|
||||
|
||||
private fun loadDictLists() {
|
||||
val isModify = pageType.value == DetailsPageType.Modify
|
||||
|
||||
DictUtils.getXxxList(
|
||||
addAll = false,
|
||||
checkedValue = if (isModify) field.value else null // 编辑模式传值,新增传 null
|
||||
) {
|
||||
xxxList.postValue(if (isModify) it else listOf(KeyValue("", "")) + it)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### checkedValue 取值规则
|
||||
|
||||
提交时用的哪个字段值,`checkedValue` 就传哪个。对照 `toKeyValue()` 的 `value` 字段确认匹配:
|
||||
|
||||
| DictUtils 方法 | KeyValue.value 来源 | checkedValue 示例 |
|
||||
|---|---|---|
|
||||
| 通用(`handleCallBack`) | `DictBean.code` | `manifest.agentCode`(如 "SFINT") |
|
||||
| `getShouYunPackageTypeList` | `PackageBean.name` | `manifest.packageType`(如 "木框") |
|
||||
|
||||
### 禁止做法
|
||||
|
||||
- ❌ 在 `init` 中加载字典(编辑数据尚未可用,无法传 `checkedValue`)
|
||||
- ❌ 依赖 `PadDataLayoutNew` 的 `value` 属性自动匹配列表(Spinner adapter 重建时 `onItemSelected` 回调会覆盖已有值)
|
||||
- ❌ 编辑模式下在列表前添加 `KeyValue("", "")`(会干扰 `checkedValue` 置顶排序)
|
||||
|
||||
---
|
||||
|
||||
## 开发检查清单
|
||||
|
||||
### 新页面开发必做
|
||||
|
||||
@@ -97,7 +97,7 @@ class PadDataLayoutNew : FrameLayout {
|
||||
|
||||
et.hint = value
|
||||
tv.hint = value
|
||||
bindAdapter(spinner, list, hint)
|
||||
updateSpinnerSilently { bindAdapter(spinner, list, hint) }
|
||||
}
|
||||
|
||||
var required = false
|
||||
@@ -106,11 +106,29 @@ class PadDataLayoutNew : FrameLayout {
|
||||
tvM.visibility = if (value) VISIBLE else INVISIBLE
|
||||
}
|
||||
|
||||
private val spinnerCallback = object : IOnSpinnerSelected {
|
||||
override fun onSelected(position: Int) {
|
||||
value = list.getOrNull(position)?.value ?: ""
|
||||
refreshCallBack?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
private val restoreListenerRunnable = Runnable {
|
||||
bindOnSelected(spinner, spinnerCallback)
|
||||
}
|
||||
|
||||
private fun updateSpinnerSilently(block: () -> Unit) {
|
||||
spinner.onItemSelectedListener = null
|
||||
spinner.removeCallbacks(restoreListenerRunnable)
|
||||
block()
|
||||
onValueSet()
|
||||
spinner.post(restoreListenerRunnable)
|
||||
}
|
||||
|
||||
var list = emptyList<KeyValue>()
|
||||
set(value) {
|
||||
field = value
|
||||
bindAdapter(spinner, value, hint)
|
||||
onValueSet()
|
||||
updateSpinnerSilently { bindAdapter(spinner, value, hint) }
|
||||
}
|
||||
|
||||
var icon: Any? = null
|
||||
@@ -183,12 +201,7 @@ class PadDataLayoutNew : FrameLayout {
|
||||
et.doOnTextChanged { text, _, _, _ ->
|
||||
value = text.toString()
|
||||
}
|
||||
bindOnSelected(spinner, object : IOnSpinnerSelected {
|
||||
override fun onSelected(position: Int) {
|
||||
value = list.getOrNull(position)?.value ?: ""
|
||||
refreshCallBack?.invoke()
|
||||
}
|
||||
})
|
||||
bindOnSelected(spinner, spinnerCallback)
|
||||
// 监听输入框焦点变化
|
||||
com.lukouguoji.module_base.adapter.setOnFocusChangeListener(
|
||||
et, object : IOnFocusChangeListener {
|
||||
|
||||
@@ -153,51 +153,13 @@ class GjjManifestAddViewModel : BaseViewModel() {
|
||||
val specialCodeList = MutableLiveData<List<KeyValue>>()
|
||||
val specialCode = MutableLiveData("")
|
||||
|
||||
// 货物类型
|
||||
val goodsTypeList = MutableLiveData<List<KeyValue>>()
|
||||
// 货物类型(无下拉列表,仅用于编辑模式回传)
|
||||
val goodsType = MutableLiveData("")
|
||||
|
||||
// 运单类型
|
||||
val waybillTypeList = MutableLiveData<List<KeyValue>>()
|
||||
val waybillType = MutableLiveData("")
|
||||
|
||||
init {
|
||||
DictUtils.getIntImpAgentList(addAll = false) {
|
||||
agentList.postValue(listOf(KeyValue("", "")) + it)
|
||||
}
|
||||
DictUtils.getSpecialCodeList(addAll = false, flag = 1, ieFlag = "") {
|
||||
val list = arrayListOf<KeyValue>()
|
||||
it.find { b -> b.key.contains("普通货物") }?.let { b ->
|
||||
list.add(b)
|
||||
}
|
||||
list.addAll(it.filter { b -> !b.key.contains("普通货物") })
|
||||
specialCodeList.postValue(list)
|
||||
}
|
||||
DictUtils.getBusinessTypeList(addAll = false) {
|
||||
businessTypeList.postValue(it)
|
||||
// 新增模式下默认选中"普通货物运输"
|
||||
if (pageType.value == DetailsPageType.Add && businessType.value.isNullOrEmpty()) {
|
||||
it.find { b -> b.key.contains("普通货物运输") }?.let { b ->
|
||||
businessType.postValue(b.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
DictUtils.getShouYunPackageTypeList {
|
||||
packageTypeList.postValue(listOf(KeyValue("", "")) + it)
|
||||
}
|
||||
DictUtils.getGjjGoodsTypeList(addAll = false) {
|
||||
goodsTypeList.postValue(it)
|
||||
}
|
||||
DictUtils.getWaybillTypeList(type = "II", addAll = false) {
|
||||
val list = arrayListOf<KeyValue>()
|
||||
it.find { b -> b.key.contains("干线") }?.let { b ->
|
||||
list.add(b)
|
||||
}
|
||||
list.addAll(it.filter { b -> !b.key.contains("干线") })
|
||||
waybillTypeList.postValue(list)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化(从Intent获取参数)
|
||||
*/
|
||||
@@ -235,6 +197,71 @@ class GjjManifestAddViewModel : BaseViewModel() {
|
||||
loadManifestFromImportBean(bean)
|
||||
}
|
||||
}
|
||||
|
||||
// 加载下拉列表(在编辑数据加载之后,以便使用 checkedValue 将选中项置顶)
|
||||
loadDictLists()
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载下拉列表数据
|
||||
* 编辑模式下传入 checkedValue,handleCallBack 会将匹配项置于列表首位,
|
||||
* Spinner 默认显示首项即完成回填
|
||||
*/
|
||||
private fun loadDictLists() {
|
||||
val isModify = pageType.value == DetailsPageType.Modify
|
||||
|
||||
DictUtils.getIntImpAgentList(
|
||||
addAll = false,
|
||||
checkedValue = if (isModify) agent.value else null
|
||||
) {
|
||||
agentList.postValue(if (isModify) it else listOf(KeyValue("", "")) + it)
|
||||
}
|
||||
|
||||
DictUtils.getSpecialCodeList(
|
||||
addAll = false, flag = 1, ieFlag = "",
|
||||
checkedValue = if (isModify) specialCode.value else null
|
||||
) {
|
||||
if (isModify) {
|
||||
specialCodeList.postValue(it)
|
||||
} else {
|
||||
val list = arrayListOf<KeyValue>()
|
||||
it.find { b -> b.key.contains("普通货物") }?.let { b -> list.add(b) }
|
||||
list.addAll(it.filter { b -> !b.key.contains("普通货物") })
|
||||
specialCodeList.postValue(list)
|
||||
}
|
||||
}
|
||||
|
||||
DictUtils.getBusinessTypeList(
|
||||
addAll = false,
|
||||
checkedValue = if (isModify) businessType.value else null
|
||||
) {
|
||||
businessTypeList.postValue(it)
|
||||
if (!isModify && businessType.value.isNullOrEmpty()) {
|
||||
it.find { b -> b.key.contains("普通货物运输") }?.let { b ->
|
||||
businessType.postValue(b.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DictUtils.getShouYunPackageTypeList(
|
||||
checkedValue = if (isModify) packageType.value else null
|
||||
) {
|
||||
packageTypeList.postValue(if (isModify) it else listOf(KeyValue("", "")) + it)
|
||||
}
|
||||
|
||||
DictUtils.getWaybillTypeList(
|
||||
type = "II", addAll = false,
|
||||
checkedValue = if (isModify) waybillType.value else null
|
||||
) {
|
||||
if (isModify) {
|
||||
waybillTypeList.postValue(it)
|
||||
} else {
|
||||
val list = arrayListOf<KeyValue>()
|
||||
it.find { b -> b.key.contains("干线") }?.let { b -> list.add(b) }
|
||||
list.addAll(it.filter { b -> !b.key.contains("干线") })
|
||||
waybillTypeList.postValue(list)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user