refactor(viewmodel): 封装调料槽位读写至 AppViewModel,消除页面直接调用 DAO 的情况

This commit is contained in:
2026-04-23 10:54:59 +08:00
parent 441cffe4da
commit debc7a0740
11 changed files with 220 additions and 155 deletions
@@ -6,6 +6,7 @@ import com.shuwei.dish.match.db.dao.SeasoningSlotDao
import com.shuwei.dish.match.entity.CookFoodEntity
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
import com.shuwei.dish.match.entity.SeasoningEntity
import com.shuwei.dish.match.entity.SeasoningSlotEntity
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@@ -122,6 +123,28 @@ class AppRepository(val appDao: AppDao, val seasoningSlotDao: SeasoningSlotDao)
suspend fun getAllSeasoningSlots() = withContext(Dispatchers.IO) {
seasoningSlotDao.queryAll()
}
/**
* 查询指定设备的调料槽位配置
* @param deviceId 目标设备 ID
*/
suspend fun getSeasoningSlotsByDeviceId(deviceId: String) = withContext(Dispatchers.IO) {
seasoningSlotDao.queryByDeviceId(deviceId)
}
/**
* 插入或更新单个调料槽位配置
*/
suspend fun upsertSeasoningSlot(slot: SeasoningSlotEntity) = withContext(Dispatchers.IO) {
seasoningSlotDao.upsert(slot)
}
/**
* 批量插入或更新调料槽位配置
*/
suspend fun upsertAllSeasoningSlots(slots: List<SeasoningSlotEntity>) = withContext(Dispatchers.IO) {
seasoningSlotDao.upsertAll(slots)
}
}
//
//class SeasoningRepository(val seasoningDao: SeasoningDao) {
@@ -19,16 +19,19 @@ class NetViewModel(
private val repository: RemoteRepository = RemoteRepository()
) : ViewModel() {
/**
* 提交制作菜品的 UI 状态流,UI 层通过 collect 监听
*/
private val _submitCookFoodState = MutableStateFlow<UiState<Any?>>(UiState.Idle)
val submitCookFoodState: StateFlow<UiState<Any?>> = _submitCookFoodState.asStateFlow()
/**
* 提交制作菜品
*/
fun submitCookFood(
entity: CookFoodEntity,
onSuccess: (Any?) -> Unit,
onFailure: (String, String) -> Unit
) {
fun submitCookFood(entity: CookFoodEntity) {
viewModelScope.launch {
repository.submitCookFood(entity, onSuccess, onFailure)
_submitCookFoodState.value = UiState.Loading
_submitCookFoodState.value = repository.submitCookFood(entity)
}
}
@@ -14,18 +14,18 @@ class RemoteRepository {
/**
* 提交制作菜品
* @param entity 菜品实体
* @param onSuccess 成功回调
* @param onFailure 失败回调,参数为 (errorCode, errorMsg)
* @return UiState 包装的结果,Success 表示提交成功,Error 携带错误信息
*/
suspend fun submitCookFood(
entity: CookFoodEntity,
onSuccess: (Any?) -> Unit,
onFailure: (String, String) -> Unit
) = request(
onRequest = { apiService.submitCookFood(param = entity) },
onSuccess = onSuccess,
onFailure = onFailure
)
suspend fun submitCookFood(entity: CookFoodEntity): UiState<Any?> {
return try {
val resp = apiService.submitCookFood(param = entity)
if (resp.isSuccess()) UiState.Success(resp.data)
else UiState.Error(resp.code, resp.msg ?: "")
} catch (e: Exception) {
val ex = getApiException(e)
UiState.Error("-1", ex.errorMsg)
}
}
/**
* 查询菜品详情
@@ -26,12 +26,14 @@ import com.shuwei.dish.match.databinding.ListTypeScale18Binding
import com.shuwei.dish.match.databinding.ListTypeScale2Binding
import com.shuwei.dish.match.databinding.ListTypeScale22Binding
import com.shuwei.dish.match.base.BaseApp
import com.shuwei.dish.match.db.AppRepository
import androidx.lifecycle.ViewModelProvider
import com.shuwei.dish.match.viewmodel.AppViewModel
import com.shuwei.dish.match.viewmodel.factory.AppFactory
import com.shuwei.dish.match.databinding.ListItemScale22RowBinding
import com.shuwei.dish.match.scale.ScaleData
import com.shuwei.dish.match.scale.ScaleDeviceConfig
import com.shuwei.dish.match.scale.ScaleServiceManager
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import com.shuwei.dish.match.utils.NetworkUtil
import com.shuwei.dish.match.utils.SizeTool
import com.shuwei.dish.match.utils.WeightUtil
@@ -53,6 +55,8 @@ class MasterScaleActivity : BaseActivity() {
private lateinit var binding: ActivityMasterScaleBinding
private val size by lazy { SizeTool.getFlexLayoutSize(10.dp) }
private lateinit var appViewModel: AppViewModel
private data class DeviceGroup(
val deviceId: String,
val ip: String,
@@ -76,19 +80,19 @@ class MasterScaleActivity : BaseActivity() {
binding.rvScaleList.itemAnimator = null
binding.rvScaleList.adapter = adapter
val db = BaseApp.instance!!.database
appViewModel = ViewModelProvider(this, AppFactory(AppRepository(db.appDao(), db.seasoningSlotDao())))[AppViewModel::class.java]
loadSlotNames()
}
/** 从 Room 加载槽位配置到 slotNameMap,加载完成后启动数据观测 */
private fun loadSlotNames() {
lifecycleScope.launch(Dispatchers.IO) {
val slots = BaseApp.instance!!.database.seasoningSlotDao().queryAll()
withContext(Dispatchers.Main) {
slots.forEach { slot ->
slotNameMap["${slot.deviceId}#${slot.address}"] = slot.goodsName
}
observeScaleData()
lifecycleScope.launch {
val slots = appViewModel.loadSeasoningSlot()
slots.forEach { slot ->
slotNameMap["${slot.deviceId}#${slot.address}"] = slot.goodsName
}
observeScaleData()
}
}
@@ -141,7 +141,10 @@ class SamplingListActivity : BaseActivity() {
}
fun deleteCookFoodAndGoods(foodId: String, action: () -> Unit) {
appViewModel.deleteCookFoodAndGoods(cookMode = 1, foodId = foodId, onFinish = action)
lifecycleScope.launch {
appViewModel.deleteCookFoodAndGoods(cookMode = 1, foodId = foodId)
action()
}
}
override fun onNewIntent(intent: Intent) {
@@ -4,6 +4,8 @@ import android.content.Intent
import android.os.Bundle
import androidx.activity.addCallback
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import com.shuwei.dish.match.R
import com.shuwei.dish.match.base.BaseActivity
import com.shuwei.dish.match.base.BaseApp
@@ -152,7 +154,10 @@ class SelectDishActivity : BaseActivity() {
}
fun deleteCookFoodAndGoods(foodId: String, action: () -> Unit) {
appViewModel.deleteCookFoodAndGoods(cookMode = 0, foodId = foodId, onFinish = action)
lifecycleScope.launch {
appViewModel.deleteCookFoodAndGoods(cookMode = 0, foodId = foodId)
action()
}
}
override fun onNewIntent(intent: Intent) {
@@ -4,12 +4,17 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.shuwei.dish.match.base.BaseActivity
import com.shuwei.dish.match.base.BaseApp
import com.shuwei.dish.match.db.AppRepository
import com.shuwei.dish.match.ui.fragment.CollectFragment
import com.shuwei.dish.match.ui.fragment.DeviceConfigFragment
import com.shuwei.dish.match.ui.fragment.SeasoningConfigFragment
import com.shuwei.dish.match.utils.ext.gone
import com.shuwei.dish.match.utils.ext.visible
import com.shuwei.dish.match.viewmodel.AppViewModel
import com.shuwei.dish.match.viewmodel.factory.AppFactory
/**
* 通用单 Fragment 容器 Activity
@@ -58,8 +63,15 @@ class SingleFragmentActivity : BaseActivity() {
lifecycleCallback = callback
}
lateinit var appViewModel: AppViewModel
private set
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val db = BaseApp.instance!!.database
appViewModel = ViewModelProvider(this, AppFactory(AppRepository(db.appDao(), db.seasoningSlotDao())))[AppViewModel::class.java]
setHeaderBackground()
// 解析页面类型,非法值直接关闭
@@ -30,9 +30,11 @@ import com.shuwei.dish.match.utils.NetworkUtil
import com.shuwei.dish.match.utils.SizeTool
import com.shuwei.dish.match.utils.WeightUtil
import com.shuwei.dish.match.utils.ext.dp
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import androidx.lifecycle.ViewModelProvider
import com.shuwei.dish.match.db.AppRepository
import com.shuwei.dish.match.viewmodel.AppViewModel
import com.shuwei.dish.match.viewmodel.factory.AppFactory
/**
* 子设备专属页面(小屏幕设备使用)
@@ -64,12 +66,17 @@ class SlaveActivity : BaseActivity() {
private var clearHighlightRunnable: Runnable? = null
private val size by lazy { SizeTool.getFlexLayoutSize(10.dp) }
private lateinit var appViewModel: AppViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySlaveBinding.inflate(layoutInflater)
setContentView(binding.root)
setHeaderBackground()
val db = BaseApp.instance!!.database
appViewModel = ViewModelProvider(this, AppFactory(AppRepository(db.appDao(), db.seasoningSlotDao())))[AppViewModel::class.java]
binding.tvDeviceId.text = "设备:${GlobalData.deviceId}"
binding.tvDeviceIp.text = "IP${getLocalIpAddress()}"
@@ -152,10 +159,9 @@ class SlaveActivity : BaseActivity() {
* 主设备未开机时也能正常展示上次配置
*/
private fun loadSlotsFromDb() {
lifecycleScope.launch(Dispatchers.IO) {
val dao = BaseApp.instance!!.database.seasoningSlotDao()
val slots = dao.queryByDeviceId(GlobalData.deviceId)
withContext(Dispatchers.Main) { applySlots(slots) }
lifecycleScope.launch {
val slots = appViewModel.getSeasoningSlotsByDeviceId(GlobalData.deviceId)
applySlots(slots)
}
}
@@ -169,9 +175,9 @@ class SlaveActivity : BaseActivity() {
?.filter { it.deviceId == GlobalData.deviceId }
?.map { SeasoningSlotEntity(it.deviceId, it.address, it.goodsId, it.goodsName) }
?: return@onSeasoningConfig
lifecycleScope.launch(Dispatchers.IO) {
BaseApp.instance!!.database.seasoningSlotDao().upsertAll(mySlots)
withContext(Dispatchers.Main) { applySlots(mySlots) }
lifecycleScope.launch {
appViewModel.upsertAllSeasoningSlots(mySlots)
applySlots(mySlots)
}
}
}
@@ -5,7 +5,9 @@ import android.os.Bundle
import android.util.Log
import androidx.activity.addCallback
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.GridLayoutManager
import com.google.gson.reflect.TypeToken
import com.shuwei.dish.match.R
@@ -19,6 +21,7 @@ import com.shuwei.dish.match.entity.CookFoodEntity
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
import com.shuwei.dish.match.entity.FoodRecord
import com.shuwei.dish.match.net.NetViewModel
import com.shuwei.dish.match.net.UiState
import com.shuwei.dish.match.scale.ScaleDeviceConfig
import com.shuwei.dish.match.scale.ScaleServiceManager
import com.shuwei.dish.match.utils.AddressUtil
@@ -121,12 +124,33 @@ class SubmitFoodActivity : BaseActivity() {
})
setupRecyclerView()
addViewListener()
initObserver()
loadSlotsThenObserveScales()
onBackPressedDispatcher.addCallback(this) {
remindSaveDataDialog()
}
}
/**
* 收集 submitCookFoodState,处理提交成功/失败
*/
private fun initObserver() {
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
netViewModel.submitCookFoodState.collect { state ->
when (state) {
is UiState.Success -> submitSuccess(food?.cookMode == 1)
is UiState.Error -> {
toast(state.msg)
dismissLoading()
}
else -> {}
}
}
}
}
}
/** 初始化 RecyclerView2列 GridLayoutManager */
private fun setupRecyclerView() {
binding.rvSeasoning.itemAnimator = null
@@ -139,35 +163,32 @@ class SubmitFoodActivity : BaseActivity() {
* isCooking=true 时先从数据库查询 goodsList,筛选调料预填充 adapter,再开始观测
*/
private fun loadSlotsThenObserveScales() {
lifecycleScope.launch(Dispatchers.IO) {
val slots = BaseApp.instance!!.database.seasoningSlotDao().queryAll()
withContext(Dispatchers.Main) {
slots.forEach { slot ->
slotMap["${slot.deviceId}#${slot.address}"] = slot.goodsId to slot.goodsName
}
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()
lifecycleScope.launch {
val slots = appViewModel.loadSeasoningSlot()
slots.forEach { slot ->
slotMap["${slot.deviceId}#${slot.address}"] = slot.goodsId to slot.goodsName
}
if (food?.isCooking == true) {
// 制作中:从数据库查询 goodsList,筛选调料数据预填充 adapter
val foodId = food?.foodId ?: return@launch
val cookMode = food?.cookMode ?: return@launch
val list = appViewModel.getCookFoodGoodsList(foodId, cookMode)
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()
}
}
}
@@ -305,16 +326,15 @@ class SubmitFoodActivity : BaseActivity() {
}
goodsList?.forEach { it.foodId = cookFoodEntity.foodId }
appViewModel.saveCookFoodAndGoods(
cookMode = food!!.cookMode,
entity = cookFoodEntity,
list = goodsList,
onFinish = {
runOnUiThread {
dismissLoading()
jumpPage(isSamplingData, true)
}
})
lifecycleScope.launch {
appViewModel.saveCookFoodAndGoods(
cookMode = food!!.cookMode,
entity = cookFoodEntity,
list = goodsList
)
dismissLoading()
jumpPage(isSamplingData, true)
}
}
private fun submit() {
@@ -354,13 +374,7 @@ class SubmitFoodActivity : BaseActivity() {
}
Log.d(TAG, "submit: json=${cookFoodEntity.toJsonString()}")
netViewModel.submitCookFood(
entity = cookFoodEntity,
onSuccess = { submitSuccess(isSamplingData) },
onFailure = { _, msg ->
toast(msg)
dismissLoading()
})
netViewModel.submitCookFood(entity = cookFoodEntity)
}
private fun submitSuccess(isSamplingData: Boolean) {
@@ -369,10 +383,11 @@ class SubmitFoodActivity : BaseActivity() {
jumpPage(isSamplingData, false)
return
}
appViewModel.deleteCookFoodAndGoods(
cookMode = food!!.cookMode,
foodId = food!!.foodId!!
) {
lifecycleScope.launch {
appViewModel.deleteCookFoodAndGoods(
cookMode = food!!.cookMode,
foodId = food!!.foodId!!
)
dismissLoading()
jumpPage(isSamplingData, false)
}
@@ -13,7 +13,6 @@ import com.google.android.flexbox.FlexWrap
import com.google.android.flexbox.FlexboxLayoutManager
import com.shuwei.dish.match.adapter.Seasoning18GridAdapter
import com.shuwei.dish.match.adapter.Seasoning22GridAdapter
import com.shuwei.dish.match.base.BaseApp
import com.shuwei.dish.match.base.BaseFragment
import com.shuwei.dish.match.base.DeviceRole
import com.shuwei.dish.match.base.GlobalData
@@ -29,9 +28,7 @@ import com.shuwei.dish.match.ui.SingleFragmentActivity
import com.shuwei.dish.match.utils.SizeTool
import com.shuwei.dish.match.utils.WeightUtil
import com.shuwei.dish.match.utils.ext.dp
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
@@ -149,11 +146,10 @@ class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
* 仅主设备执行广播,子设备不调用此方法
*/
private fun saveSlotAndBroadcast(slot: SeasoningSlotEntity) {
lifecycleScope.launch(Dispatchers.IO) {
val dao = BaseApp.instance!!.database.seasoningSlotDao()
dao.upsert(slot)
lifecycleScope.launch {
currentActivity.appViewModel.upsertSeasoningSlot(slot)
// 读取全量配置,通过 wsClient 推送给所有已连接子设备
val allSlots = dao.queryAll().map {
val allSlots = currentActivity.appViewModel.loadSeasoningSlot().map {
SlotConfig(it.deviceId, it.address, it.goodsId, it.goodsName)
}
ScaleServiceManager.sendSeasoningConfig(allSlots)
@@ -205,25 +201,22 @@ class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
private fun loadData() {
adapter22.update(emptyList())
adapter18.update(emptyList())
lifecycleScope.launch(Dispatchers.IO) {
val dao = BaseApp.instance!!.database.seasoningSlotDao()
val slots22 = dao.queryByDeviceId(ScaleDeviceConfig.DEVICE_ID_22)
val slots18 = dao.queryByDeviceId(ScaleDeviceConfig.DEVICE_ID_18)
val slotsOil = dao.queryByDeviceId(ScaleDeviceConfig.DEVICE_ID_1)
withContext(Dispatchers.Main) {
slots22.forEach { slot ->
val pos = ScaleDeviceConfig.SCALE_ORDER_22.indexOf(slot.address)
if (pos >= 0) adapter22.updateItemName(pos, slot.goodsName)
}
slots18.forEach { slot ->
val pos = ScaleDeviceConfig.SCALE_ORDER_18.indexOf(slot.address)
if (pos >= 0) adapter18.updateItemName(pos, slot.goodsName)
}
// 加载油盆格子名称(address=1
val oilSlot = slotsOil.firstOrNull { it.address == 1 }
binding.tvOilSlot.text =
if (oilSlot != null && oilSlot.goodsName.isNotEmpty()) oilSlot.goodsName else "-"
lifecycleScope.launch {
val slots22 = currentActivity.appViewModel.getSeasoningSlotsByDeviceId(ScaleDeviceConfig.DEVICE_ID_22)
val slots18 = currentActivity.appViewModel.getSeasoningSlotsByDeviceId(ScaleDeviceConfig.DEVICE_ID_18)
val slotsOil = currentActivity.appViewModel.getSeasoningSlotsByDeviceId(ScaleDeviceConfig.DEVICE_ID_1)
slots22.forEach { slot ->
val pos = ScaleDeviceConfig.SCALE_ORDER_22.indexOf(slot.address)
if (pos >= 0) adapter22.updateItemName(pos, slot.goodsName)
}
slots18.forEach { slot ->
val pos = ScaleDeviceConfig.SCALE_ORDER_18.indexOf(slot.address)
if (pos >= 0) adapter18.updateItemName(pos, slot.goodsName)
}
// 加载油盆格子名称(address=1
val oilSlot = slotsOil.firstOrNull { it.address == 1 }
binding.tvOilSlot.text =
if (oilSlot != null && oilSlot.goodsName.isNotEmpty()) oilSlot.goodsName else "-"
}
}
@@ -60,63 +60,46 @@ class AppViewModel(private val rep: AppRepository) : ViewModel() {
// }
// }
fun saveCookFoodAndGoods(
suspend fun saveCookFoodAndGoods(
cookMode: Int,
entity: CookFoodEntity,
list: MutableList<CookFoodGoodsEntity>?,
onFinish: () -> Unit
list: MutableList<CookFoodGoodsEntity>?
) {
viewModelScope.launch {
val data = rep.getCookFoodById(entity.foodId, cookMode)
if (data != null) {
//存在数据删除
rep.deleteCookFood(entity.foodId, cookMode)
rep.deleteCookFoodGoodsList(data.id, entity.foodId)
val data = rep.getCookFoodById(entity.foodId, cookMode)
if (data != null) {
// 存在数据先删除
rep.deleteCookFood(entity.foodId, cookMode)
rep.deleteCookFoodGoodsList(data.id, entity.foodId)
}
// 重新保存数据
rep.insertCookFood(entity)
val newData = rep.getCookFoodById(entity.foodId, cookMode)
list?.let { it ->
it.forEach { goods ->
goods.id = 0
goods.pid = newData?.id ?: 0
}
//重新保存数据
rep.insertCookFood(entity)
val newData = rep.getCookFoodById(entity.foodId, cookMode)
list?.let { it ->
it.forEach { goods ->
goods.id = 0
goods.pid = newData?.id?:0
}
rep.insertGoodsList(it)
}
onFinish()
rep.insertGoodsList(it)
}
}
fun deleteCookFoodAndGoods(
cookMode: Int,
foodId: String,
onFinish: () -> Unit
) {
viewModelScope.launch {
val data = rep.getCookFoodById(foodId, cookMode)
if (data != null) {
rep.deleteCookFood(foodId = foodId, cookMode = cookMode)
rep.deleteCookFoodGoodsList(pid = data.id, foodId = foodId)
}
onFinish()
suspend fun deleteCookFoodAndGoods(cookMode: Int, foodId: String) {
val data = rep.getCookFoodById(foodId, cookMode)
if (data != null) {
rep.deleteCookFood(foodId = foodId, cookMode = cookMode)
rep.deleteCookFoodGoodsList(pid = data.id, foodId = foodId)
}
}
//--------------------------------------------------------------------------------------------------------
fun getCookFoodGoodsList(
suspend fun getCookFoodGoodsList(
foodId: String,
cookMode: Int,
action: (list: MutableList<CookFoodGoodsEntity>) -> Unit
) {
viewModelScope.launch {
val cookFood = rep.getCookFoodById(foodId, cookMode)
cookFood?.let {
val list = rep.getCookFoodGoodsList(pid = it.id, foodId = it.foodId)
action(list)
}
}
cookMode: Int
): MutableList<CookFoodGoodsEntity> {
val cookFood = rep.getCookFoodById(foodId, cookMode)
return if (cookFood != null) rep.getCookFoodGoodsList(pid = cookFood.id, foodId = cookFood.foodId)
else mutableListOf()
}
// fun updateGoods(entity: CookFoodGoodsEntity) {
@@ -206,6 +189,24 @@ class AppViewModel(private val rep: AppRepository) : ViewModel() {
}
}
/**
* 查询指定设备的调料槽位配置
*/
suspend fun getSeasoningSlotsByDeviceId(deviceId: String) =
rep.getSeasoningSlotsByDeviceId(deviceId)
/**
* 插入或更新单个调料槽位配置
*/
suspend fun upsertSeasoningSlot(slot: SeasoningSlotEntity) =
rep.upsertSeasoningSlot(slot)
/**
* 批量插入或更新调料槽位配置
*/
suspend fun upsertAllSeasoningSlots(slots: List<SeasoningSlotEntity>) =
rep.upsertAllSeasoningSlots(slots)
// fun updateAll(list: MutableList<SeasoningEntity>) {
// viewModelScope.launch {
// list.forEach {