feat(activity): SubmitFoodActivity 支持制作中菜品调料历史数据加载与新增叠加

- SeasoningWeightAdapter 改继承 BaseQuickAdapter
- item_seasoning_weight 左右间距改为 32dp
- isCooking=true 时从数据库查询 goodsList 并预填充调料历史数据
- refreshAdapterByName 叠加历史用量,修复新增用量覆盖历史数据问题
- 返回键拦截,弹窗提示保存数据

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-22 11:47:13 +08:00
co-authored by Claude Sonnet 4.6
parent f25108360b
commit bce9675b0f
4 changed files with 107 additions and 53 deletions
@@ -1,8 +1,10 @@
package com.shuwei.dish.match.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.chad.library.adapter4.BaseQuickAdapter
import com.chad.library.adapter4.viewholder.QuickViewHolder
import com.shuwei.dish.match.databinding.ItemSeasoningWeightBinding
/**
@@ -10,7 +12,7 @@ import com.shuwei.dish.match.databinding.ItemSeasoningWeightBinding
* 用于 SubmitFoodActivity 展示各调料槽位的实时用量
* 同名调料已在外部聚合,adapter 按 goodsName 作为唯一标识
*/
class SeasoningWeightAdapter : RecyclerView.Adapter<SeasoningWeightAdapter.VH>() {
class SeasoningWeightAdapter : BaseQuickAdapter<SeasoningWeightAdapter.Item, SeasoningWeightAdapter.VH>() {
/** 调料展示数据项,key = goodsName(同名调料已聚合) */
data class Item(
@@ -20,19 +22,15 @@ class SeasoningWeightAdapter : RecyclerView.Adapter<SeasoningWeightAdapter.VH>()
val useWeight: Double
)
val items = mutableListOf<Item>()
/**
* 更新单个 item,按 goodsName 匹配;不存在则追加
*/
fun updateItem(item: Item) {
val idx = items.indexOfFirst { it.goodsName == item.goodsName }
if (idx >= 0) {
items[idx] = item
notifyItemChanged(idx)
set(idx, item)
} else {
items.add(item)
notifyItemInserted(items.lastIndex)
add(item)
}
}
@@ -41,29 +39,20 @@ class SeasoningWeightAdapter : RecyclerView.Adapter<SeasoningWeightAdapter.VH>()
*/
fun removeItem(goodsName: String) {
val idx = items.indexOfFirst { it.goodsName == goodsName }
if (idx >= 0) {
items.removeAt(idx)
notifyItemRemoved(idx)
}
if (idx >= 0) removeAt(idx)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
val binding = ItemSeasoningWeightBinding.inflate(
LayoutInflater.from(parent.context), parent, false
)
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
val binding = ItemSeasoningWeightBinding.inflate(LayoutInflater.from(context), parent, false)
return VH(binding)
}
override fun onBindViewHolder(holder: VH, position: Int) {
holder.bind(items[position])
override fun onBindViewHolder(holder: VH, position: Int, item: Item?) {
item ?: return
holder.binding.tvSeasoningName.text = item.goodsName
holder.binding.tvSeasoningWeight.text = "${item.useWeight}g"
}
override fun getItemCount() = items.size
inner class VH(var binding: ItemSeasoningWeightBinding) : QuickViewHolder(binding.root)
class VH(private val b: ItemSeasoningWeightBinding) : RecyclerView.ViewHolder(b.root) {
fun bind(item: Item) {
b.tvSeasoningName.text = item.goodsName
b.tvSeasoningWeight.text = "${item.useWeight}g"
}
}
}
@@ -3,6 +3,7 @@ package com.shuwei.dish.match.ui
import android.annotation.SuppressLint
import android.os.Bundle
import android.util.Log
import androidx.activity.addCallback
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
@@ -13,6 +14,7 @@ import com.shuwei.dish.match.base.BaseActivity
import com.shuwei.dish.match.base.BaseApp
import com.shuwei.dish.match.databinding.ActivitySubmitFoodBinding
import com.shuwei.dish.match.db.AppRepository
import com.shuwei.dish.match.dialog.CommonDialog
import com.shuwei.dish.match.entity.CookFoodEntity
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
import com.shuwei.dish.match.entity.FoodRecord
@@ -23,6 +25,7 @@ import com.shuwei.dish.match.utils.AddressUtil
import com.shuwei.dish.match.utils.WeightUtil
import com.shuwei.dish.match.utils.ext.clickWithDebounce
import com.shuwei.dish.match.utils.ext.gone
import com.shuwei.dish.match.utils.ext.roundedDecimalPlace
import com.shuwei.dish.match.utils.ext.roundedOneDecimalPlace
import com.shuwei.dish.match.utils.ext.startActivity
import com.shuwei.dish.match.utils.ext.toJsonString
@@ -83,6 +86,12 @@ class SubmitFoodActivity : BaseActivity() {
*/
private val rawWeightMap = mutableMapOf<String, Triple<String, String, Double>>()
/**
* isCooking=true 时从 goodsList 预填充的历史用量,key = goodsNamevalue = goodsId to useWeight
* 用于 refreshAdapterByName 时叠加到秤新增用量上
*/
private val baseSeasoningMap = mutableMapOf<String, Pair<String, Double>>()
@Suppress("unchecked_cast", "DEPRECATION")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -93,8 +102,11 @@ class SubmitFoodActivity : BaseActivity() {
intent.extras?.apply {
food = getSerializable(FOOD_ITEM) as FoodRecord?
Log.d(TAG, "onCreate: cookMode=${food?.cookMode}")
// 非烹饪中,从菜品主辅材配置页面带入数据
goodsList = getSerializable(GOODS_LIST) as MutableList<CookFoodGoodsEntity>?
// isCooking=false:从前一页面带入主辅材数据;isCooking=true:从数据库查询
if (food?.isCooking == false) {
goodsList = getSerializable(GOODS_LIST) as MutableList<CookFoodGoodsEntity>?
Log.d(TAG, "onCreate: goodsList=${goodsList.toJsonString()}")
}
}
setTitleBar(titleBarAction = {
it.visible()
@@ -102,11 +114,17 @@ class SubmitFoodActivity : BaseActivity() {
it.text = food?.foodName
}, rightIconActon = {
it.gone()
it.setImageResource(R.drawable.ic_setting)
}, backAction = {
it.setOnClickListener {
remindSaveDataDialog()
}
})
setupRecyclerView()
addViewListener()
loadSlotsThenObserveScales()
onBackPressedDispatcher.addCallback(this) {
remindSaveDataDialog()
}
}
/** 初始化 RecyclerView2列 GridLayoutManager */
@@ -118,7 +136,7 @@ class SubmitFoodActivity : BaseActivity() {
/**
* 从 Room 加载槽位配置后,开始订阅子设备秤数据
* 确保 slotMap 就绪后再处理秤数据,避免名称为空
* isCooking=true 时先从数据库查询 goodsList,筛选调料预填充 adapter,再开始观测
*/
private fun loadSlotsThenObserveScales() {
lifecycleScope.launch(Dispatchers.IO) {
@@ -127,7 +145,29 @@ class SubmitFoodActivity : BaseActivity() {
slots.forEach { slot ->
slotMap["${slot.deviceId}#${slot.address}"] = slot.goodsId to slot.goodsName
}
observeScaleData()
if (food?.isCooking == true) {
// 制作中:从数据库查询 goodsList,筛选调料数据预填充 adapter
val foodId = food?.foodId ?: return@withContext
val cookMode = food?.cookMode ?: return@withContext
appViewModel.getCookFoodGoodsList(foodId, cookMode) { list ->
goodsList = list
list.filter { it.materialType == 3 }.forEach { item ->
val name = item.goodsName ?: ""
val weight = item.useWeight ?: 0.0
baseSeasoningMap[name] = (item.goodsId) to weight
seasoningAdapter.updateItem(
SeasoningWeightAdapter.Item(
goodsId = item.goodsId,
goodsName = name,
useWeight = weight
)
)
}
observeScaleData()
}
} else {
observeScaleData()
}
}
}
}
@@ -174,33 +214,34 @@ class SubmitFoodActivity : BaseActivity() {
}
/**
* 按 goodsName 聚合 rawWeightMap将同名调料的用量累加后推给 adapter
* 聚合后总量 < 0.5g 则从 adapter 移除
* 按 goodsName 聚合 rawWeightMap叠加历史用量后推给 adapter
* isCooking=true 时只新增,不移除(历史调料数据不可减少)
*/
private fun refreshAdapterByName(goodsName: String) {
val grouped = rawWeightMap.values.filter { it.second == goodsName }
if (grouped.isEmpty()) {
seasoningAdapter.removeItem(goodsName)
val newWeight = grouped.sumOf { it.third }.roundedOneDecimalPlace()
val (baseGoodsId, baseWeight) = baseSeasoningMap[goodsName] ?: ("" to 0.0)
val totalWeight = (newWeight + baseWeight).roundedOneDecimalPlace()
if (totalWeight < 0.5) {
// 制作中模式:已有历史数据,不允许移除
if (food?.isCooking != true) {
seasoningAdapter.removeItem(goodsName)
}
return
}
val totalWeight = grouped.sumOf { it.third }.roundedOneDecimalPlace()
if (totalWeight < 0.5) {
seasoningAdapter.removeItem(goodsName)
} else {
seasoningAdapter.updateItem(
SeasoningWeightAdapter.Item(
goodsId = grouped.first().first,
goodsName = goodsName,
useWeight = totalWeight
)
val goodsId = grouped.firstOrNull()?.first?.takeIf { it.isNotEmpty() } ?: baseGoodsId
seasoningAdapter.updateItem(
SeasoningWeightAdapter.Item(
goodsId = goodsId,
goodsName = goodsName,
useWeight = totalWeight
)
}
)
}
private fun addViewListener() {
binding.btnCook.clickWithDebounce { cook() }
binding.btnWeightClear.clickWithDebounce { WeightUtil.tareTwo(2) }
binding.btnSubmit.clickWithDebounce {
if (cookFoodEntity.foodWeight <= 0.toDouble()) {
toast("未识别到菜品熟重")
@@ -212,8 +253,14 @@ class SubmitFoodActivity : BaseActivity() {
// 监听主设备 2格秤的熟重
WeightUtil.addWeightListener(TAG) { address, _, weight ->
if (address == AddressUtil.TWO) {
cookFoodEntity.foodWeight = weight.toDouble()
binding.tvTotalWeight.text = "${weight / 1000f}"
cookFoodEntity.foodWeight = weight
if (weight > 1000) {
binding.tvTotalWeight.text = "${(weight / 1000f).roundedDecimalPlace(3)}"
binding.tvWeightUnit.text = "千克"
} else {
binding.tvTotalWeight.text = "$weight"
binding.tvWeightUnit.text = ""
}
}
}
}
@@ -231,7 +278,7 @@ class SubmitFoodActivity : BaseActivity() {
showLoading()
// 将调料数据转为 CookFoodGoodsEntity 追加到 goodsList
val typeToken = object : TypeToken<List<CookFoodGoodsEntity>>() {}
// val typeToken = object : TypeToken<List<CookFoodGoodsEntity>>() {}
val tempSeasoningList = seasoningData.map { item ->
CookFoodGoodsEntity().also { entity ->
entity.goodsId = item.goodsId
@@ -356,4 +403,18 @@ class SubmitFoodActivity : BaseActivity() {
WeightUtil.removeWeightListener(TAG)
super.onDestroy()
}
/**
* 未保存数据提醒dialog
*/
private fun remindSaveDataDialog() {
CommonDialog(this)
.setTitle("温馨提示")
.setContent("请确认是否存在未保存的数据?")
.setNegativeButton("取消,留在页面")
.setNeutralButton("返回上页,不保存") { finish() }
.setPositiveButton("保存为烹饪中菜品") { cook() }
.show()
}
}
@@ -32,6 +32,8 @@
android:layout_width="match_parent"
android:layout_height="660dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_marginHorizontal="12dp"
android:overScrollMode="never" />
</LinearLayout>
@@ -98,7 +100,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:includeFontPadding="false"
android:text="千克"
tools:text="千克"
android:textColor="@color/black999"
android:textSize="32sp" />
</LinearLayout>
@@ -4,8 +4,10 @@
android:layout_height="60dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingEnd="16dp">
android:background="@drawable/shape_scale_cell"
android:paddingHorizontal="16dp"
android:layout_marginHorizontal="4dp"
android:layout_marginVertical="4dp">
<TextView
android:id="@+id/tvSeasoningName"