From 38847389111bf028151f6ff8e07642c1b0e82d2e Mon Sep 17 00:00:00 2001 From: lvmeng <848755140@qq.com> Date: Mon, 1 Jun 2026 20:05:00 +0800 Subject: [PATCH] =?UTF-8?q?feat(form):=20=E5=AE=9E=E7=8E=B0=E9=A4=90?= =?UTF-8?q?=E5=93=81=E9=80=89=E6=8B=A9=E5=90=8E=E8=87=AA=E5=8A=A8=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=E9=A3=9F=E6=9D=90=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 NutFoodOptionVO 模型导入并增加 foodOptionsData 缓存列表 - 新增 ingredientsField 表单字段用于包含食材动态加载 - 将食材名称字段类型从 DROPDOWN 改为 FIXED 类型并移除固定选项 - 实现餐品选中后根据 position 从 compositions 加载包含食材逻辑 - 在 DictType 中新增 position 属性用于索引定位 - 在 FormField 中新增 onDropdownSelected 回调函数属性 - 更新 FormFieldAdapter 中触发选中回调并在日期字段注释中调整说明 - 修改 IngredientRowAdapter 中根据字段类型区分 FIXED 和其他类型处理 - 添加 extraApiKeys 到 extraValues 映射逻辑并更新下拉选中回调 - 调整 list_item_ingredient_row.xml 中食材名称布局去除右侧边距和下拉箭头 - 注释掉 NetViewModelV2 中的 getFoodOptions 方法(暂未使用) --- .../dish/match/adapter/FormFieldAdapter.kt | 6 +- .../match/adapter/IngredientRowAdapter.kt | 27 +++++-- .../com/shuwei/dish/match/model/DictType.kt | 3 +- .../com/shuwei/dish/match/model/FormField.kt | 3 +- .../shuwei/dish/match/net/NetViewModelV2.kt | 12 +-- .../shuwei/dish/match/ui/CleanPackActivity.kt | 80 +++++++++++++++---- .../res/layout/list_item_ingredient_row.xml | 16 ++-- 7 files changed, 106 insertions(+), 41 deletions(-) diff --git a/app/src/main/java/com/shuwei/dish/match/adapter/FormFieldAdapter.kt b/app/src/main/java/com/shuwei/dish/match/adapter/FormFieldAdapter.kt index e720d3f..a513332 100644 --- a/app/src/main/java/com/shuwei/dish/match/adapter/FormFieldAdapter.kt +++ b/app/src/main/java/com/shuwei/dish/match/adapter/FormFieldAdapter.kt @@ -143,6 +143,8 @@ class FormFieldAdapter( item.extraApiKeys.forEach { (apiKey, dictField) -> item.extraValues[apiKey] = dictType[dictField] } + // 触发选中回调 + item.onDropdownSelected?.invoke(dictType) }.also { it.bgLayout = b.flDropdown it.showAsDropDown(v) @@ -166,7 +168,7 @@ class FormFieldAdapter( set(year, month, dayOfMonth, 0, 0, 0) set(Calendar.MILLISECOND, 0) } - // value 存显示格式,valueId 存 ISO 格式供提交使用 + // value 存日期显示格式,供提交使用 item.value = displayDateFormat.format(selected.time) b.tvDateValue.text = item.value }, @@ -215,7 +217,7 @@ class FormFieldAdapter( extraApiKeys = field.extraApiKeys, required = field.required, hint = field.hint, - options = field.options, + options = field.options ) }.toMutableList() item.childrenRows.add(newRow) diff --git a/app/src/main/java/com/shuwei/dish/match/adapter/IngredientRowAdapter.kt b/app/src/main/java/com/shuwei/dish/match/adapter/IngredientRowAdapter.kt index 7045843..62b62fd 100644 --- a/app/src/main/java/com/shuwei/dish/match/adapter/IngredientRowAdapter.kt +++ b/app/src/main/java/com/shuwei/dish/match/adapter/IngredientRowAdapter.kt @@ -62,13 +62,22 @@ class IngredientRowAdapter( b.etTraceCode.tag = watcher } - // 食材名称 - DROPDOWN + // 食材名称 materNameField?.let { field -> - b.tvMaterName.hint = field.hint.ifBlank { "请选择${field.label}" } - b.tvMaterName.text = field.value.ifBlank { null } - b.flMaterName.setOnClickListener { v -> - v.hideKeyboard() - showDropdown(b.flMaterName, field, b.tvMaterName, holder.getAdapterPosition(), 1) + when (field.type) { + com.shuwei.dish.match.model.FieldType.FIXED -> { + b.flMaterName.setOnClickListener { v -> v.hideKeyboard() } + b.flMaterName.isClickable = false + b.tvMaterName.text = field.value + } + else -> { + b.tvMaterName.hint = field.hint.ifBlank { "请选择${field.label}" } + b.tvMaterName.text = field.value.ifBlank { null } + b.flMaterName.setOnClickListener { v -> + v.hideKeyboard() + showDropdown(b.flMaterName, field, b.tvMaterName, holder.getAdapterPosition(), 1) + } + } } } @@ -123,6 +132,12 @@ class IngredientRowAdapter( ) { dictType -> field.value = dictType.value ?: "" valueView.text = field.value + // 将 extraApiKeys 映射值写入 extraValues + field.extraValues.clear() + field.extraApiKeys.forEach { (apiKey, dictField) -> + field.extraValues[apiKey] = dictType[dictField] + } + field.onDropdownSelected?.invoke(dictType) // 回调通知外部更新 onChildClick(rowPosition, childIndex, field) }.also { diff --git a/app/src/main/java/com/shuwei/dish/match/model/DictType.kt b/app/src/main/java/com/shuwei/dish/match/model/DictType.kt index 5bfcb66..f21e8d1 100644 --- a/app/src/main/java/com/shuwei/dish/match/model/DictType.kt +++ b/app/src/main/java/com/shuwei/dish/match/model/DictType.kt @@ -10,7 +10,8 @@ import kotlinx.parcelize.Parcelize data class DictType( val id: String? = null, val value: String? = null, - val type: String = "" + val type: String = "", + var position: Int = 0 ) : Parcelable { /** diff --git a/app/src/main/java/com/shuwei/dish/match/model/FormField.kt b/app/src/main/java/com/shuwei/dish/match/model/FormField.kt index 4c18eb0..c6c1c21 100644 --- a/app/src/main/java/com/shuwei/dish/match/model/FormField.kt +++ b/app/src/main/java/com/shuwei/dish/match/model/FormField.kt @@ -47,5 +47,6 @@ data class FormField( val extraValues: MutableMap = mutableMapOf(), val children: List? = null, val childAddLabel: String? = null, - val childrenRows: MutableList> = mutableListOf() + val childrenRows: MutableList> = mutableListOf(), + var onDropdownSelected: ((DictType) -> Unit)? = null ) diff --git a/app/src/main/java/com/shuwei/dish/match/net/NetViewModelV2.kt b/app/src/main/java/com/shuwei/dish/match/net/NetViewModelV2.kt index df5a4c2..179d3a2 100644 --- a/app/src/main/java/com/shuwei/dish/match/net/NetViewModelV2.kt +++ b/app/src/main/java/com/shuwei/dish/match/net/NetViewModelV2.kt @@ -72,12 +72,12 @@ class NetViewModelV2( private val _foodOptionsState = MutableStateFlow?>>(UiState.Idle) val foodOptionsState: StateFlow?>> = _foodOptionsState.asStateFlow() - fun getFoodOptions(keyword: String? = null, pageNum: Int = 1, pageSize: Int = 10) { - viewModelScope.launch { - _foodOptionsState.value = UiState.Loading - _foodOptionsState.value = repository.getFoodOptions(keyword, pageNum, pageSize) - } - } +// fun getFoodOptions(keyword: String? = null, pageNum: Int = 1, pageSize: Int = 10) { +// viewModelScope.launch { +// _foodOptionsState.value = UiState.Loading +// _foodOptionsState.value = repository.getFoodOptions(keyword, pageNum, pageSize) +// } +// } /** * 字典项下拉(回调版本),不依赖 StateFlow,适合多次不同 dictType 的场景 diff --git a/app/src/main/java/com/shuwei/dish/match/ui/CleanPackActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/CleanPackActivity.kt index ab45f4e..cc5b3d8 100644 --- a/app/src/main/java/com/shuwei/dish/match/ui/CleanPackActivity.kt +++ b/app/src/main/java/com/shuwei/dish/match/ui/CleanPackActivity.kt @@ -10,6 +10,7 @@ import com.shuwei.dish.match.databinding.ActivityCleanPackBinding import com.shuwei.dish.match.model.DictType import com.shuwei.dish.match.model.FieldType import com.shuwei.dish.match.model.FormField +import com.shuwei.dish.match.model.NutFoodOptionVO import com.shuwei.dish.match.net.NetViewModelV2 import com.shuwei.dish.match.net.UiState import com.shuwei.dish.match.utils.ext.gone @@ -47,8 +48,12 @@ class CleanPackActivity : BaseActivity() { private var deviceField: FormField? = null private var foodOptionsField: FormField? = null private var packagingSpecField: FormField? = null + private var ingredientsField: FormField? = null private var traceCodeJob: Job? = null + // 缓存餐品选项完整数据,用于选择后获取 compositions + private val foodOptionsData = mutableListOf() + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) statusBarDarkFont(enable = true) @@ -266,14 +271,10 @@ class CleanPackActivity : BaseActivity() { hint = "溯源码" ), FormField( - label = "食材名称", type = FieldType.DROPDOWN, + label = "食材名称", + type = FieldType.FIXED, extraApiKeys = mapOf("materId" to "id", "ingredientName" to "value"), - required = true, - options = mutableListOf( - DictType(id = "1", value = "土豆", type = "土豆"), - DictType(id = "2", value = "鸡肉", type = "鸡肉"), - DictType(id = "3", value = "青椒", type = "青椒"), - ) + required = true ), FormField( label = "分类", type = FieldType.DROPDOWN, @@ -293,14 +294,54 @@ class CleanPackActivity : BaseActivity() { hint = "如 120g" ), ) - fields.add( - FormField( - label = "包含食材", type = FieldType.CHILDREN, - required = true, - children = ingredientTemplate, - childAddLabel = "+ 添加食材" - ) + ingredientsField = FormField( + label = "包含食材", type = FieldType.CHILDREN, + required = true, + children = ingredientTemplate, + childAddLabel = "+ 添加食材" ) + fields.add(ingredientsField!!) + + // 餐品选中后,根据 position 从 compositions 加载包含食材 + foodOptionsField!!.onDropdownSelected = { dictType -> + val position = dictType.position + if (position >= 0 && position < foodOptionsData.size) { + val compositions = foodOptionsData[position].compositions ?: emptyList() + val ingredients = ingredientsField!! + ingredients.childrenRows.clear() + for (comp in compositions) { + // 每行复制模板的4个字段,将 composition 数据填充进去 + val newRow = ingredients.children?.map { template -> + // 根据 extraApiKeys 判断是否为食材名称字段 + val hasMaterId = template.extraApiKeys.containsKey("materId") + val hasIngredientName = template.extraApiKeys.containsKey("ingredientName") + val fieldValue = if (hasIngredientName) comp.ingredientName ?: "" else "" + val fieldExtraValues = mutableMapOf() + template.extraApiKeys.forEach { (apiKey, dictField) -> + fieldExtraValues[apiKey] = when (dictField) { + "id" -> comp.materId?.toString() ?: "" + "value" -> comp.ingredientName ?: "" + else -> "" + } + } + FormField( + label = template.label, + type = template.type, + apiKey = template.apiKey, + extraApiKeys = template.extraApiKeys, + required = template.required, + hint = template.hint, + options = template.options, + value = fieldValue, + extraValues = fieldExtraValues + ) + }?.toMutableList() ?: mutableListOf() + ingredients.childrenRows.add(newRow) + } + val idx = fields.indexOf(ingredients) + if (idx >= 0) formAdapter.notifyItemChanged(idx) + } + } // 包装日期 fields.add( @@ -422,12 +463,17 @@ class CleanPackActivity : BaseActivity() { onResult = { state -> when (state) { is UiState.Success -> { - val options = state.data?.records?.map { vo -> + val records = state.data?.records ?: emptyList() + foodOptionsData.clear() + foodOptionsData.addAll(records) + val options = records.mapIndexed { index, vo -> DictType( id = vo.foodId?.toString() ?: "", - value = vo.foodName ?: "" + value = vo.foodName ?: "", + type = vo.foodCode ?: "", + position = index ) - } ?: emptyList() + } field.options.clear() field.options.addAll(options) val index = fields.indexOf(field) diff --git a/app/src/main/res/layout/list_item_ingredient_row.xml b/app/src/main/res/layout/list_item_ingredient_row.xml index 3734bf4..3c1e8aa 100644 --- a/app/src/main/res/layout/list_item_ingredient_row.xml +++ b/app/src/main/res/layout/list_item_ingredient_row.xml @@ -36,7 +36,6 @@ android:id="@+id/tvMaterName" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_marginEnd="24dp" android:layout_marginStart="10dp" android:ellipsize="end" android:gravity="center_vertical" @@ -44,14 +43,15 @@ android:textColor="#FF141428" android:textColorHint="#FF96A0AA" android:textSize="16sp" /> + - + + + + + + +