refactor(network): 菜品详情接口改用 DTO 与 Room 实体解耦

This commit is contained in:
2026-05-11 11:10:45 +08:00
parent 879af8426f
commit 8f15c0efb7
7 changed files with 176 additions and 15 deletions
@@ -0,0 +1,41 @@
package com.shuwei.dish.match.entity
import java.io.Serializable
/**
* 菜品详情接口传输对象(DTO),不依赖 Room
* 对应接口:getConstituteByFoodId / saveConstitute
*/
data class CookFoodDTO(
var foodId: String = "",
var foodName: String? = null,
var canteenId: String? = null,
var foodWeight: Double = 0.0,
// 0-制作模式,1-采样模式,2-品控模式
var cookMode: Int = 0,
var dinnerType: String? = "0",
// 接口返回的食材构成列表
var matchingConstituteInfoList: MutableList<CookFoodGoodsDTO>? = null,
var foodConstituteList: MutableList<CookFoodGoodsDTO>? = null
) : Serializable {
/**
* 转换为 Room 实体,用于写入本地数据库
* id/isDel/createTime 由 Room 自行管理,不从 DTO 携带
*/
fun toEntity(): CookFoodEntity = CookFoodEntity(
foodId = foodId,
foodName = foodName,
canteenId = canteenId,
foodWeight = foodWeight,
cookMode = cookMode,
dinnerType = dinnerType
).also { entity ->
entity.matchingConstituteInfoList = matchingConstituteInfoList
?.map { it.toEntity() }
?.toMutableList()
entity.foodConstituteList = foodConstituteList
?.map { it.toEntity() }
?.toMutableList()
}
}
@@ -0,0 +1,117 @@
package com.shuwei.dish.match.entity
import java.io.Serializable
/**
* 菜品构成(主辅料/调料)接口传输对象(DTO),不依赖 Room
* 对应 CookFoodDTO 中 foodConstituteList、matchingConstituteInfoList 的元素
*/
data class CookFoodGoodsDTO(
var goodsId: String = "",
var goodsName: String? = null,
var foodId: String? = "",
var goodsOrRelationCode: String? = "",
// 调料数据顺序
var sort: Int = 0,
// 食材原材料:1,预制品:2
var relateionType: Int = 0,
// 物品类型:1主料 2辅料 3调料
var materialType: Int = 0,
// 物品 是否全部可食:true-全部可食,false-部分可食
var allEdible: Boolean = true,
// 物品 用料重量
var useWeight: Double? = 0.0,
var popularName: String? = "",
var canteenId: String? = "",
var relateionType_dictText: String? = "",
var zjmCode: String? = "",
var materId: String? = "",
// 物料编码
var goodsCode: String? = "",
// 净材种类
var rawMaterialsType: String? = null
) : Serializable {
/**
* 转换为 GoodsItem,用于 UI 层
*/
fun toGoodsItem(): GoodsItem = GoodsItem(
goodsId = goodsId,
goodsName = goodsName,
popularName = popularName,
zjmCode = zjmCode,
materId = materId,
materCode = goodsCode,
materialType = materialType,
useWeight = useWeight,
relateionType = relateionType,
allEdible = allEdible,
goodsOrRelationCode = goodsOrRelationCode,
rawMaterialsType = rawMaterialsType
)
/**
* 转换为 Room 实体,用于写入本地数据库
* id/pid/isDel/createTime 由 Room 自行管理,不从 DTO 携带
*/
fun toEntity(): CookFoodGoodsEntity = CookFoodGoodsEntity(
goodsId = goodsId,
goodsName = goodsName,
foodId = foodId,
goodsOrRelationCode = goodsOrRelationCode,
sort = sort,
relateionType = relateionType,
materialType = materialType,
allEdible = allEdible,
useWeight = useWeight,
popularName = popularName,
canteenId = canteenId,
relateionType_dictText = relateionType_dictText,
zjmCode = zjmCode,
materId = materId,
goodsCode = goodsCode,
rawMaterialsType = rawMaterialsType
)
}
/**
* Room 实体 → DTO 反向映射,用于将本地数据转为接口提交格式
* id/pid/isDel/createTime 为本地数据库字段,不参与提交
*/
fun CookFoodGoodsEntity.toDTO(): CookFoodGoodsDTO = CookFoodGoodsDTO(
goodsId = goodsId,
goodsName = goodsName,
foodId = foodId,
goodsOrRelationCode = goodsOrRelationCode,
sort = sort,
relateionType = relateionType,
materialType = materialType,
allEdible = allEdible,
useWeight = useWeight,
popularName = popularName,
canteenId = canteenId,
relateionType_dictText = relateionType_dictText,
zjmCode = zjmCode,
materId = materId,
goodsCode = goodsCode,
rawMaterialsType = rawMaterialsType
)
/**
* Room 实体 → DTO 反向映射,用于将本地数据转为接口提交格式
* id/isDel/createTime 为本地数据库字段,不参与提交
*/
fun CookFoodEntity.toDTO(): CookFoodDTO = CookFoodDTO(
foodId = foodId,
foodName = foodName,
canteenId = canteenId,
foodWeight = foodWeight,
cookMode = cookMode,
dinnerType = dinnerType,
matchingConstituteInfoList = matchingConstituteInfoList
?.map { it.toDTO() }
?.toMutableList(),
foodConstituteList = foodConstituteList
?.map { it.toDTO() }
?.toMutableList()
)
@@ -1,7 +1,7 @@
package com.shuwei.dish.match.net package com.shuwei.dish.match.net
import com.shuwei.dish.match.base.GlobalData import com.shuwei.dish.match.base.GlobalData
import com.shuwei.dish.match.entity.CookFoodEntity import com.shuwei.dish.match.entity.CookFoodDTO
import com.shuwei.dish.match.entity.FoodRecord import com.shuwei.dish.match.entity.FoodRecord
import com.shuwei.dish.match.entity.GoodsItem import com.shuwei.dish.match.entity.GoodsItem
import okhttp3.MultipartBody import okhttp3.MultipartBody
@@ -24,7 +24,7 @@ interface ApiService {
suspend fun getFoodDetail( suspend fun getFoodDetail(
@Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/matching/app/getConstituteByFoodId", @Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/matching/app/getConstituteByFoodId",
@Query("foodId") foodId: String @Query("foodId") foodId: String
): ApiResponse<CookFoodEntity?> ): ApiResponse<CookFoodDTO?>
/** /**
@@ -33,7 +33,7 @@ interface ApiService {
@POST @POST
suspend fun submitCookFood( suspend fun submitCookFood(
@Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/matching/app/saveConstitute", @Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/matching/app/saveConstitute",
@Body param: CookFoodEntity @Body param: CookFoodDTO
): ApiResponse<Any?> ): ApiResponse<Any?>
/** /**
@@ -3,9 +3,10 @@ package com.shuwei.dish.match.net
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.shuwei.dish.match.base.BaseApp import com.shuwei.dish.match.base.BaseApp
import com.shuwei.dish.match.entity.CookFoodEntity import com.shuwei.dish.match.entity.CookFoodDTO
import com.shuwei.dish.match.entity.FoodRecord import com.shuwei.dish.match.entity.FoodRecord
import com.shuwei.dish.match.entity.GoodsItem import com.shuwei.dish.match.entity.GoodsItem
import com.shuwei.dish.match.entity.GoodsNameQueryDTO
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
@@ -33,7 +34,7 @@ class NetViewModel(
/** /**
* 提交制作菜品 * 提交制作菜品
*/ */
fun submitCookFood(entity: CookFoodEntity) { fun submitCookFood(entity: CookFoodDTO) {
viewModelScope.launch { viewModelScope.launch {
_submitCookFoodState.value = UiState.Loading _submitCookFoodState.value = UiState.Loading
_submitCookFoodState.value = repository.submitCookFood(entity) _submitCookFoodState.value = repository.submitCookFood(entity)
@@ -43,8 +44,8 @@ class NetViewModel(
/** /**
* 查询菜品详情的 UI 状态流,UI 层通过 collect 监听 * 查询菜品详情的 UI 状态流,UI 层通过 collect 监听
*/ */
private val _foodDetailState = MutableStateFlow<UiState<CookFoodEntity?>>(UiState.Idle) private val _foodDetailState = MutableStateFlow<UiState<CookFoodDTO?>>(UiState.Idle)
val foodDetailState: StateFlow<UiState<CookFoodEntity?>> = _foodDetailState.asStateFlow() val foodDetailState: StateFlow<UiState<CookFoodDTO?>> = _foodDetailState.asStateFlow()
/** /**
* 查询菜品详情 * 查询菜品详情
@@ -108,7 +109,7 @@ class NetViewModel(
* @param pageNum 页码,默认第 1 页 * @param pageNum 页码,默认第 1 页
* @param pageSize 每页条数,默认 50 * @param pageSize 每页条数,默认 50
* @param goodsName 按名称模糊搜索,为 null 时不传该字段 * @param goodsName 按名称模糊搜索,为 null 时不传该字段
* @param goodsNames 按名称列表批量查询,为 null 时不传该字段 * @param goodsNames 按名称+净材种类列表批量查询,为 null 时不传该字段
*/ */
fun queryGoodsList( fun queryGoodsList(
goodsType: String, goodsType: String,
@@ -116,7 +117,7 @@ class NetViewModel(
pageNum: Int = 1, pageNum: Int = 1,
pageSize: Int = 50, pageSize: Int = 50,
goodsName: String? = null, goodsName: String? = null,
goodsNames: List<String>? = null goodsNames: List<GoodsNameQueryDTO>? = null
) { ) {
val param = mutableMapOf<String, Any>( val param = mutableMapOf<String, Any>(
"goodsType" to goodsType, "goodsType" to goodsType,
@@ -1,6 +1,6 @@
package com.shuwei.dish.match.net package com.shuwei.dish.match.net
import com.shuwei.dish.match.entity.CookFoodEntity import com.shuwei.dish.match.entity.CookFoodDTO
import com.shuwei.dish.match.entity.FoodRecord import com.shuwei.dish.match.entity.FoodRecord
import com.shuwei.dish.match.entity.GoodsItem import com.shuwei.dish.match.entity.GoodsItem
import okhttp3.MultipartBody import okhttp3.MultipartBody
@@ -18,7 +18,7 @@ class RemoteRepository {
* @param entity 菜品实体 * @param entity 菜品实体
* @return UiState 包装的结果,Success 表示提交成功,Error 携带错误信息 * @return UiState 包装的结果,Success 表示提交成功,Error 携带错误信息
*/ */
suspend fun submitCookFood(entity: CookFoodEntity): UiState<Any?> { suspend fun submitCookFood(entity: CookFoodDTO): UiState<Any?> {
return try { return try {
val resp = apiService.submitCookFood(param = entity) val resp = apiService.submitCookFood(param = entity)
if (resp.isSuccess()) UiState.Success(resp.data) if (resp.isSuccess()) UiState.Success(resp.data)
@@ -34,7 +34,7 @@ class RemoteRepository {
* @param foodId 菜品 ID * @param foodId 菜品 ID
* @return UiState 包装的结果,Success 携带详情数据,Error 携带错误信息 * @return UiState 包装的结果,Success 携带详情数据,Error 携带错误信息
*/ */
suspend fun getFoodDetail(foodId: String): UiState<CookFoodEntity?> { suspend fun getFoodDetail(foodId: String): UiState<CookFoodDTO?> {
return try { return try {
val resp = apiService.getFoodDetail(foodId = foodId) val resp = apiService.getFoodDetail(foodId = foodId)
if (resp.isSuccess()) UiState.Success(resp.data) if (resp.isSuccess()) UiState.Success(resp.data)
@@ -19,7 +19,7 @@ import com.shuwei.dish.match.base.BaseActivity
import com.shuwei.dish.match.databinding.ActivityPrepareFoodBinding import com.shuwei.dish.match.databinding.ActivityPrepareFoodBinding
import com.shuwei.dish.match.databinding.LayoutCameraPreviewBinding import com.shuwei.dish.match.databinding.LayoutCameraPreviewBinding
import com.shuwei.dish.match.dialog.CommonDialog import com.shuwei.dish.match.dialog.CommonDialog
import com.shuwei.dish.match.entity.CookFoodEntity import com.shuwei.dish.match.entity.CookFoodDTO
import com.shuwei.dish.match.entity.CookFoodGoodsEntity import com.shuwei.dish.match.entity.CookFoodGoodsEntity
import com.shuwei.dish.match.entity.FoodRecord import com.shuwei.dish.match.entity.FoodRecord
import com.shuwei.dish.match.entity.GoodsItem import com.shuwei.dish.match.entity.GoodsItem
@@ -349,7 +349,7 @@ class PrepareFoodActivity : BaseActivity() {
} }
private fun loadDishDetail(detail: CookFoodEntity) { private fun loadDishDetail(detail: CookFoodDTO) {
// val voList = detail.stFoodInfoConstituteList // val voList = detail.stFoodInfoConstituteList
val voList = detail.foodConstituteList val voList = detail.foodConstituteList
if (voList.isNullOrEmpty()) { if (voList.isNullOrEmpty()) {
@@ -20,6 +20,7 @@ import com.shuwei.dish.match.dialog.CommonDialog
import com.shuwei.dish.match.entity.CookFoodEntity import com.shuwei.dish.match.entity.CookFoodEntity
import com.shuwei.dish.match.entity.CookFoodGoodsEntity import com.shuwei.dish.match.entity.CookFoodGoodsEntity
import com.shuwei.dish.match.entity.FoodRecord import com.shuwei.dish.match.entity.FoodRecord
import com.shuwei.dish.match.entity.toDTO
import com.shuwei.dish.match.net.UiState import com.shuwei.dish.match.net.UiState
import com.shuwei.dish.match.scale.ScaleDeviceConfig import com.shuwei.dish.match.scale.ScaleDeviceConfig
import com.shuwei.dish.match.scale.ScaleServiceManager import com.shuwei.dish.match.scale.ScaleServiceManager
@@ -357,7 +358,8 @@ class SubmitFoodActivity : BaseActivity() {
} }
Log.d(TAG, "submit: json=${cookFoodEntity.toJsonString()}") Log.d(TAG, "submit: json=${cookFoodEntity.toJsonString()}")
netViewModel.submitCookFood(entity = cookFoodEntity) // 接口提交使用 DTO,与本地 Room 实体解耦
netViewModel.submitCookFood(entity = cookFoodEntity.toDTO())
} }
} }