feat(data): 更新食物营养数据模型并优化向量数据处理

- 在DataBean中将肉蛋相关字段重命名为肉蛋豆,并添加总重量字段
- 新增FoodVectorTool工具类用于处理食物向量数据的分页获取和存储
- 重构InitActivity中的食物向量数据获取逻辑,使用新的工具类替代原有实现
- 在MainActivity中集成食物向量数据同步功能,在清除本地数据后重新获取
- 更新MainScreenPresentation中营养信息显示逻辑,适配新的数据模型结构
- 修改ApiClient中的日志标记逻辑,为不同接口添加特定的标签
- 调整食物订单列表的数据更新方式,优化适配器通知策略
This commit is contained in:
2026-04-03 18:04:59 +08:00
parent 0127697560
commit ab0d9b35f5
6 changed files with 152 additions and 67 deletions
@@ -17,6 +17,7 @@ import com.sw.dualscreen.model.response.FoodVector
import com.sw.dualscreen.objbox.Food
import com.sw.dualscreen.objbox.FoodModule
import com.sw.dualscreen.objbox.ObjectBox
import com.sw.dualscreen.utils.FoodVectorTool
import com.sw.dualscreen.utils.L
import com.sw.dualscreen.utils.NetworkUtils
import com.sw.dualscreen.viewmodel.BaseViewModel
@@ -26,7 +27,7 @@ import kotlinx.coroutines.launch
class InitActivity : BaseActivity<ActivityInitBinding>() {
companion object {
private const val PAGE_SIZE = 100
const val PAGE_SIZE = 100
}
private val userViewModel by viewModels<UserViewModel>()
@@ -41,52 +42,47 @@ class InitActivity : BaseActivity<ActivityInitBinding>() {
}
private fun getCollectedFoodVector(block: () -> Unit) {
userViewModel.getCollectedFoodVector(
param = mutableMapOf(
"pageNum" to "$pageNum",
"pageSize" to "$PAGE_SIZE",
"version" to GlobalData.foodModelVersion
)
) { items ->
if (items == null) {
// userViewModel.getCollectedFoodVector(
// param = mutableMapOf(
// "pageNum" to "$pageNum",
// "pageSize" to "$PAGE_SIZE",
// "version" to GlobalData.foodModelVersion
// )
// ) { items ->
// if (items == null) {
// getVectorErrorDialog()
// return@getCollectedFoodVector
// }
// val list = items
// if (pageNum == 1 && list.isEmpty()) {
// block()
// return@getCollectedFoodVector
// }
// if (list.size >= PAGE_SIZE) {
// saveFoodVector(list)
// pageNum++
// getCollectedFoodVector(block)
// return@getCollectedFoodVector
// }
// if (list.isNotEmpty()) {
// saveFoodVector(list)
// block()
// }
// }
FoodVectorTool.getFoodVector(
userViewModel,
onPageFinish = { list ->
list?.let { FoodVectorTool.saveFoodVector(lifecycleScope,list) }
}, successBlock = {
block()
}, failureBlock = {
getVectorErrorDialog()
return@getCollectedFoodVector
}
val list = items
if (pageNum == 1 && list.isEmpty()) {
block()
return@getCollectedFoodVector
}
if (list.size >= PAGE_SIZE) {
saveFoodVector(list)
pageNum++
getCollectedFoodVector(block)
return@getCollectedFoodVector
}
if (list.isNotEmpty()) {
saveFoodVector(list)
block()
}
}
)
}
// private val box by lazy { ObjectBox.boxStore.boxFor(Food::class) }
private fun saveFoodVector(list: List<FoodVector>) {
lifecycleScope.launch {
val vectorList = list.map { vt ->
val foodVector = vt.foodVector?.removeSurrounding("[", "]")?.split(",")
?.map { it.toFloatOrNull() ?: 0.0f }?.toFloatArray()
Food(
collectId = vt.id,
foodId = vt.foodId,
foodName = vt.foodName,
version = vt.version,
foodVector = foodVector
)
}
ObjectBox.putAll(vectorList)
}
}
override fun initialize() {
super.initialize()
@@ -55,6 +55,7 @@ import com.sw.dualscreen.socket.TcpClient
import com.sw.dualscreen.utils.ActivityManager
import com.sw.dualscreen.utils.BitmapSaver
import com.sw.dualscreen.utils.Debouncer
import com.sw.dualscreen.utils.FoodVectorTool
import com.sw.dualscreen.utils.GsonUtils
import com.sw.dualscreen.utils.ImageUtil
import com.sw.dualscreen.utils.IntervalExecutor
@@ -215,6 +216,21 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
withContext(Dispatchers.IO) {
FaceServer.getInstance().clearAllFaces()
}
withContext(Dispatchers.IO) {
ObjectBox.removeAll()
}
FoodVectorTool.getFoodVector(
userViewModel = viewModel,
onPageFinish = { list ->
list?.let { FoodVectorTool.saveFoodVector(lifecycleScope,list) }
},
successBlock = {
viewModel.getUserFaceCache(pageNo = 1)
}, failureBlock = {
hideWaitingDialog() // 显示提示信息
ToastUtils.showToast(it)
}
)
}
viewModel.getUserFaceCache(pageNo = 1, onSuccess = {
recognizeViewModel.refreshFaceList()
@@ -100,12 +100,14 @@ data class UserNutrition(
val fruitsVegetablesNearExcess: String? = null,
//果蔬超量
val fruitsVegetablesExcess: String? = null,
//肉蛋推荐值
val meatEggsRecommend: String? = null,
//肉蛋即将超量
val meatEggsNearExcess: String? = null,
//肉蛋超量
val meatEggsExcess: String? = null,
//肉蛋推荐值
val meatEggsBeansRecommend: String? = null,
//肉蛋即将超量
val meatEggsBeansNearExcess: String? = null,
//肉蛋超量
val meatEggsBeansExcess: String? = null,
//总重量
val eatWeightSum:Double? = null,
)
//{"code":"00000","data":"{\"orderType\":0,\"orderPayFrom\":2,\"payType\":\"1\",\"paySuc\":0,\"totalFee\":0.01,\"orderCode\":\"1998193614899372032\",\"message\":\"支付成功\",\"payCode\":\"1998193614899372032508227\"}","msg":"成功","total":0}
@@ -24,7 +24,9 @@ object ApiClient {
.addNetworkInterceptor(Interceptor {chain ->
val request = chain.request()
val url = request.url.toString()
val tag = if (url.contains("terminal/neglect/common/app/faceFeature/increment/list")) "faceIncrement" else "ApiClient"
val tag = if (url.contains("terminal/neglect/common/app/faceFeature/increment/list")) "faceIncrement"
else if (url.contains("terminal/neglect/pay/app/turnOrderInfo")) "turnOrderInfo"
else "ApiClient"
val loggingInterceptor = HttpLoggingInterceptor(logger = {
Timber.tag(tag).d("okhttp logger ==>${it}")
}).apply {
@@ -485,9 +485,7 @@ class MainScreenPresentation(
binding.nutritionInclude.tvUserName.text = userNutrition?.name.maskName()
val recommendCalorie = (userNutrition?.recommendCalorie ?: 0.0).roundedDecimalPlace(1)
// binding.detailInclude.tvTotalWeight.text = "总重量:${userNutrition?.}克"
binding.nutritionInclude.tvRecommendHeat.text =
"推荐热量:${recommendCalorie.roundedDecimalPlace(1)}kcal"
binding.nutritionInclude.tvRecommendHeat.text = "推荐热量:${recommendCalorie.roundedDecimalPlace(1)}kcal"
// binding.nutritionInclude.tvRecommendHeat.text = "推荐热量:${recommendCalorie.removeTrailingZeros()}kcal"
//updateWeight(lastWeight / 1000)
// -------------------------------------------------
@@ -715,8 +713,8 @@ class MainScreenPresentation(
val last = foodOrderList.last()
if (last.isLocalData) {
foodOrderList.remove(last)
foodOrderAdapter.submitList(foodOrderList)
//foodOrderAdapter.notifyDataSetChanged()
// foodOrderAdapter.submitList(foodOrderList)
foodOrderAdapter.notifyDataSetChanged()
}
}
return
@@ -730,8 +728,8 @@ class MainScreenPresentation(
last.eatNum = eatNum
last.num = weight
last.price = price
foodOrderAdapter.submitList(foodOrderList)
//foodOrderAdapter.notifyItemChanged(foodOrderList.lastIndex)
// foodOrderAdapter.submitList(foodOrderList)
foodOrderAdapter.notifyItemChanged(foodOrderList.lastIndex)
return
}
}
@@ -750,7 +748,8 @@ class MainScreenPresentation(
isLocalData = true
)
)
foodOrderAdapter.submitList(foodOrderList)
// foodOrderAdapter.submitList(foodOrderList)
foodOrderAdapter.notifyDataSetChanged()
Log.d(
TAG,
"addFoodToOrder: size=${foodOrderList.size},新增数据:${foodOrderList.last()}"
@@ -803,8 +802,10 @@ class MainScreenPresentation(
val fruitsVegetables = energy.fruitsVegetables
val meatEggs = energy.meatEggs
binding.detailInclude.tvTotalCalorie.text =
"总热量:${totalKcal.roundedDecimalPlace(1)}千卡"
binding.detailInclude.tvTotalCalorie.text = "总热量:${totalKcal.roundedDecimalPlace(1)}千卡"
val totalWeight = (userNutrition?.eatWeightSum ?: 0.0) + weight
binding.detailInclude.tvTotalWeight.text = "总重量:${totalWeight.roundedDecimalPlace(1)}"
val include = binding.nutritionInclude
@@ -874,9 +875,9 @@ class MainScreenPresentation(
// 设置肉蛋-----------------------------------------------------------
val meatEggsArray = UserNutritionUtils.getCalorieArray(
left = userNutrition?.meatEggsRecommend,
mid = userNutrition?.meatEggsNearExcess,
right = userNutrition?.meatEggsExcess
left = userNutrition?.meatEggsBeansRecommend,
mid = userNutrition?.meatEggsBeansNearExcess,
right = userNutrition?.meatEggsBeansExcess
)
val meatEggsIndex =
UserNutritionUtils.findCalorieIndex(energy.meatEggs, meatEggsArray)
@@ -1480,12 +1481,11 @@ class MainScreenPresentation(
if (model == null) return@runOnUiThread
foodOrderList.clear()
foodOrderList.addAll(model.list ?: emptyList())
foodOrderAdapter.submitList(foodOrderList)
//foodOrderAdapter.notifyDataSetChanged()
binding.detailInclude.tvTotalWeight.text = "总重量:${model.eatWeightSum}"
//foodOrderAdapter.submitList(foodOrderList)
foodOrderAdapter.notifyDataSetChanged()
//binding.detailInclude.tvTotalWeight.text = "总重量:${model.eatWeightSum}克"
Log.d(TAG, "addFoodToOrder: 更新总重量,订单列表------------------------------")
binding.detailInclude.tvTotalCalorie.text =
"总热量:${model.calorie.roundedDecimalPlace(1)}千卡"
// binding.detailInclude.tvTotalCalorie.text = "总热量:${model.calorie.roundedDecimalPlace(1)}千卡"
jointPaymentQueryFinish = true
//重新加载营养信息
@@ -0,0 +1,69 @@
package com.sw.dualscreen.utils
import androidx.lifecycle.lifecycleScope
import com.sw.dualscreen.GlobalData
import com.sw.dualscreen.activity.InitActivity
import com.sw.dualscreen.model.response.FoodVector
import com.sw.dualscreen.objbox.Food
import com.sw.dualscreen.objbox.ObjectBox
import com.sw.dualscreen.viewmodel.UserViewModel
import kotlinx.coroutines.launch
object FoodVectorTool {
var pageNum: Int = 1
const val PAGE_SIZE: Int = InitActivity.PAGE_SIZE
fun getFoodVector(
userViewModel: UserViewModel,
onPageFinish:(List<FoodVector>?)-> Unit,
successBlock: () -> Unit,
failureBlock: (String) -> Unit
): Unit {
userViewModel.getCollectedFoodVector(
param = mutableMapOf(
"pageNum" to "$pageNum",
"pageSize" to "$PAGE_SIZE",
"version" to GlobalData.foodModelVersion
)
) { items ->
if (items == null) {
failureBlock("未查询到向量数据")
return@getCollectedFoodVector
}
val list = items
if (pageNum == 1 && list.isEmpty()) {
//接口成功无数据,暂时认为成功
successBlock()
return@getCollectedFoodVector
}
if (list.size >= PAGE_SIZE) {
onPageFinish(list)
pageNum++
getFoodVector(userViewModel, onPageFinish, successBlock, failureBlock)
return@getCollectedFoodVector
}
if (list.isNotEmpty()) {
onPageFinish(list)
}
successBlock()
}
}
fun saveFoodVector(lifecycleScope: androidx.lifecycle.LifecycleCoroutineScope ,list: List<FoodVector>) {
lifecycleScope.launch {
val vectorList = list.map { vt ->
val foodVector = vt.foodVector?.removeSurrounding("[", "]")?.split(",")
?.map { it.toFloatOrNull() ?: 0.0f }?.toFloatArray()
Food(
collectId = vt.id,
foodId = vt.foodId,
foodName = vt.foodName,
version = vt.version,
foodVector = foodVector
)
}
ObjectBox.putAll(vectorList)
}
}
}