feat(form): 实现餐品选择后自动加载食材功能
- 添加 NutFoodOptionVO 模型导入并增加 foodOptionsData 缓存列表 - 新增 ingredientsField 表单字段用于包含食材动态加载 - 将食材名称字段类型从 DROPDOWN 改为 FIXED 类型并移除固定选项 - 实现餐品选中后根据 position 从 compositions 加载包含食材逻辑 - 在 DictType 中新增 position 属性用于索引定位 - 在 FormField 中新增 onDropdownSelected 回调函数属性 - 更新 FormFieldAdapter 中触发选中回调并在日期字段注释中调整说明 - 修改 IngredientRowAdapter 中根据字段类型区分 FIXED 和其他类型处理 - 添加 extraApiKeys 到 extraValues 映射逻辑并更新下拉选中回调 - 调整 list_item_ingredient_row.xml 中食材名称布局去除右侧边距和下拉箭头 - 注释掉 NetViewModelV2 中的 getFoodOptions 方法(暂未使用)
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
/**
|
||||
|
||||
@@ -47,5 +47,6 @@ data class FormField(
|
||||
val extraValues: MutableMap<String, String> = mutableMapOf(),
|
||||
val children: List<FormField>? = null,
|
||||
val childAddLabel: String? = null,
|
||||
val childrenRows: MutableList<MutableList<FormField>> = mutableListOf()
|
||||
val childrenRows: MutableList<MutableList<FormField>> = mutableListOf(),
|
||||
var onDropdownSelected: ((DictType) -> Unit)? = null
|
||||
)
|
||||
|
||||
@@ -72,12 +72,12 @@ class NetViewModelV2(
|
||||
private val _foodOptionsState = MutableStateFlow<UiState<Page<NutFoodOptionVO>?>>(UiState.Idle)
|
||||
val foodOptionsState: StateFlow<UiState<Page<NutFoodOptionVO>?>> = _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 的场景
|
||||
|
||||
@@ -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<NutFoodOptionVO>()
|
||||
|
||||
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<String, String>()
|
||||
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)
|
||||
|
||||
@@ -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" />
|
||||
<!-- android:layout_marginEnd="24dp"-->
|
||||
|
||||
<ImageView
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:src="@mipmap/ic_triangle_down"
|
||||
tools:ignore="ContentDescription" />
|
||||
<!-- <ImageView-->
|
||||
<!-- android:layout_width="18dp"-->
|
||||
<!-- android:layout_height="wrap_content"-->
|
||||
<!-- android:layout_gravity="end|center_vertical"-->
|
||||
<!-- android:layout_marginEnd="6dp"-->
|
||||
<!-- android:src="@mipmap/ic_triangle_down"-->
|
||||
<!-- tools:ignore="ContentDescription" />-->
|
||||
</FrameLayout>
|
||||
|
||||
<!-- 分类 -->
|
||||
|
||||
Reference in New Issue
Block a user