refactor(network): 重构网络请求配置和API接口实现

- 将BASE_URL改为使用GlobalData.PROD_BASE_URL常量
- 更新ApiClient中的URL匹配规则以支持新的营养模块接口
- 将ApiServiceV2中的接口路径从/neglect/booth改为/nutrition/neglect/booth
- 使用@Url注解动态传入完整URL地址
- 在CollectedFoodActivity中切换到NetViewModelV2和新API模型
- 更新采集功能的数据模型和接口调用方式
- 调整人脸数据获取逻辑以支持增量和全量同步
- 优化文件上传和删除操作的参数传递方式
This commit is contained in:
2026-05-28 15:14:44 +08:00
parent 6abd2f9b0b
commit bf6b2547f3
17 changed files with 563 additions and 250 deletions
@@ -5,7 +5,6 @@ import androidx.activity.viewModels
import androidx.core.widget.addTextChangedListener
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.sw.dualscreen.GlobalData
import com.sw.dualscreen.R
import com.sw.dualscreen.adapter.CollectedFoodNewAdapter
import com.sw.dualscreen.databinding.ActivityCollectedFoodBinding
@@ -14,10 +13,10 @@ import com.sw.dualscreen.ext.addOnActionSearchListener
import com.sw.dualscreen.ext.gone
import com.sw.dualscreen.ext.hideKeyboard
import com.sw.dualscreen.ext.visible
import com.sw.dualscreen.objbox.CollectedFoodInfo
import com.sw.dualscreen.model.response.v2.CollectedFoodV2
import com.sw.dualscreen.objbox.ObjectBox
import com.sw.dualscreen.viewmodel.BaseViewModel
import com.sw.dualscreen.viewmodel.UserViewModel
import com.sw.dualscreen.viewmodel.NetViewModelV2
import com.sw.plate.utils.ToastUtils
import kotlinx.coroutines.launch
@@ -27,7 +26,7 @@ class CollectedFoodActivity : BaseActivity<ActivityCollectedFoodBinding>() {
private const val PAGE_SIZE = 100
}
private val viewModel by viewModels<UserViewModel>()
private val viewModel by viewModels<NetViewModelV2>()
override fun getViewModel(): BaseViewModel {
return viewModel
}
@@ -36,7 +35,7 @@ class CollectedFoodActivity : BaseActivity<ActivityCollectedFoodBinding>() {
return ActivityCollectedFoodBinding.inflate(layoutInflater)
}
private val list: MutableList<CollectedFoodInfo> = mutableListOf()
private val list: MutableList<CollectedFoodV2> = mutableListOf()
private val adapter by lazy {
CollectedFoodNewAdapter(list).apply {
// isStateViewEnable = true
@@ -127,19 +126,26 @@ class CollectedFoodActivity : BaseActivity<ActivityCollectedFoodBinding>() {
// loadEmptyView()
// }
viewModel.getCollectedFoodList(
pageNo = pageNo,
pageSize = PAGE_SIZE,
foodName = searchName ?: ""
) { items ->
runOnUiThread {
loadFoodList(items)
viewModel.getCollectPage(
pageNum = pageNo.toLong(),
pageSize = PAGE_SIZE.toLong(),
foodName = searchName,
onSuccess = { items ->
runOnUiThread {
loadFoodList(items.onEach { it.foodCount = 1 })
}
},
onFailure = {
runOnUiThread {
finishRefresh()
ToastUtils.showToast(it)
}
}
}
)
}
@SuppressLint("NotifyDataSetChanged")
private fun loadFoodList(items: List<CollectedFoodInfo>) {
private fun loadFoodList(items: List<CollectedFoodV2>) {
finishRefresh()
if (pageNo == 1 && items.isEmpty()) {
list.clear()
@@ -191,7 +197,7 @@ class CollectedFoodActivity : BaseActivity<ActivityCollectedFoodBinding>() {
private fun deleteGoods(position: Int) {
val food = list[position]
showWaitingDialog("加载中……")
viewModel.deleteCollectFood(food.foodId, GlobalData.foodModelVersion) { deleteSuccess ->
viewModel.deleteCollect(food.foodId, food.version) { deleteSuccess ->
if (deleteSuccess) {
// Thread {}.start()
lifecycleScope.launch {
@@ -19,7 +19,7 @@ import com.sw.dualscreen.utils.L
import com.sw.dualscreen.utils.NetworkUtils
import com.sw.dualscreen.utils.SpTool
import com.sw.dualscreen.viewmodel.BaseViewModel
import com.sw.dualscreen.viewmodel.UserViewModel
import com.sw.dualscreen.viewmodel.NetViewModelV2
import com.sw.plate.utils.AppUtil
import com.sw.plate.utils.ToastUtils
import kotlinx.coroutines.launch
@@ -29,7 +29,7 @@ class InitActivity : BaseActivity<ActivityInitBinding>() {
const val PAGE_SIZE = 100
}
private val userViewModel by viewModels<UserViewModel>()
private val userViewModel by viewModels<NetViewModelV2>()
private var pageNum = 1
override fun getViewModel(): BaseViewModel {
@@ -107,6 +107,7 @@ class InitActivity : BaseActivity<ActivityInitBinding>() {
}
}
}
checkCameraPermissionAndGo()
}
private fun goMainActivity() {
@@ -189,23 +190,23 @@ class InitActivity : BaseActivity<ActivityInitBinding>() {
}
private fun getDeviceConfig() {
userViewModel.getDeviceConfig { deviceConfig ->
runOnUiThread {
if (deviceConfig == null) {
ToastUtils.showToast("获取设备配置数据失败")
return@runOnUiThread
}
//var settlementMode = 1
//结算模式:1-独立支付,2-联合结算
val settlementMode = if (deviceConfig.payType == 2) 0 else 1
// TODO: 2022/10/13 修改为独立支付
SpTool.settlementMode = settlementMode
userViewModel.getDeviceConfig(
onSuccess = { deviceConfig ->
runOnUiThread {
if (deviceConfig == null) {
ToastUtils.showToast("获取设备配置数据失败")
return@runOnUiThread
}
val settlementMode = if (deviceConfig.payType == 2) 0 else 1
SpTool.settlementMode = settlementMode
GlobalData.appId = deviceConfig.arcsoftAppId ?: ""
GlobalData.sdkKey = deviceConfig.arcsoftSdkKey ?: ""
GlobalData.activeKey = deviceConfig.arcsoftActiveKey ?: ""
}
}
GlobalData.appId = deviceConfig.arcsoftAppId ?: ""
GlobalData.sdkKey = deviceConfig.arcsoftSdkKey ?: ""
GlobalData.activeKey = deviceConfig.arcsoftActiveKey ?: ""
}
},
onFailure = { runOnUiThread { ToastUtils.showToast(it) } }
)
}
private fun loadNetworkErrorDialog() {
@@ -48,7 +48,7 @@ import com.sw.dualscreen.model.response.FoodOrder
import com.sw.dualscreen.model.response.PaySuccessEvent
import com.sw.dualscreen.model.response.ResetRecognizeEvent
import com.sw.dualscreen.model.response.UpdateRefreshEvent
import com.sw.dualscreen.model.response.UserFaceModel
import com.sw.dualscreen.model.response.v2.FaceVO
import com.sw.dualscreen.objbox.Food
import com.sw.dualscreen.objbox.FoodModule
import com.sw.dualscreen.objbox.FoodModule.IdNameScore
@@ -67,7 +67,7 @@ import com.sw.dualscreen.utils.SPUtil
import com.sw.dualscreen.utils.SpTool
import com.sw.dualscreen.view.CustomBottomSheetDialog
import com.sw.dualscreen.viewmodel.BaseViewModel
import com.sw.dualscreen.viewmodel.UserViewModel
import com.sw.dualscreen.viewmodel.NetViewModelV2
import com.sw.plate.utils.Base64
import com.sw.plate.utils.LightManager
import com.sw.plate.utils.ToastUtils
@@ -81,8 +81,6 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.json.JSONObject
@@ -109,7 +107,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
const val WEIGHT_RESET_RECOGNIZE = 10
}
private val viewModel by viewModels<UserViewModel>()
private val viewModel by viewModels<NetViewModelV2>()
private var imageCapture: ImageCapture? = null
var isAnalyzing = true // 控制是否进行图像分析
@@ -208,7 +206,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
addBackEventListener()
initView()
if (SpTool.firstGetFace) {
viewModel.getUserFaceCache(pageNo = 1)
viewModel.getFacePage(pageNum = 1)
}
setupCamera()
initData()
@@ -273,7 +271,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
userViewModel = viewModel,
lifecycleScope = lifecycleScope,
successBlock = {
viewModel.getUserFaceCache(pageNo = 1)
hideWaitingDialog()
},
failureBlock = {
hideWaitingDialog()
@@ -281,7 +279,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
)
}
viewModel.getUserFaceCache(pageNo = 1, onSuccess = {
viewModel.getFacePage(pageNum = 1, onSuccess = {
recognizeViewModel.refreshFaceList()
hideWaitingDialog()
ToastUtils.showToast("人脸数据已更新")
@@ -1111,14 +1109,12 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
log("是否null判断,imageFile == null:${imageFile == null},imageVector == null:${imageVector == null}")
return
}
val foodId = foodInfo.foodId
val foodId = foodInfo.foodId.toLongOrNull() ?: run {
loadRemindDialog("foodId 格式错误: ${foodInfo.foodId}")
return
}
val foodName = foodInfo.foodName ?: ""
val foodModelVersion = GlobalData.foodModelVersion
val params = HashMap<String, RequestBody>()
params["foodId"] = foodId.toRequestBody()
params["foodName"] = foodName.toRequestBody()
params["version"] = foodModelVersion.toRequestBody()
val files = listOf(imageFile)
val vectors = listOf(imageVector)
val foodVectorList = vectors.map {
it.joinToString(
@@ -1128,8 +1124,13 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
val foodVectorJson =
foodVectorList.joinToString(separator = ",", prefix = "[", postfix = "]")
log("json=$foodVectorJson")
params["foodVector"] = foodVectorJson.toRequestBody()
val idList = viewModel.uploadCollectFoodPics(files, params)
val idList = viewModel.uploadCollect(
foodId = foodId,
foodName = foodName,
version = foodModelVersion,
foodVector = foodVectorJson,
fileList = listOf(imageFile)
)
if (idList.isNullOrEmpty()) {
loadRemindDialog("上传失败,未返回向量数据id")
log("idList为空")
@@ -1146,7 +1147,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
ObjectBox.put(
Food(
collectId = idList[0],
foodId = foodId,
foodId = "$foodId",
foodName = foodName,
foodVector = imageVector,
version = foodModelVersion
@@ -1204,7 +1205,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
//if (timestamp == 0L) {
// return@startIntervalTaskWithInitialDelay
//}
viewModel.getFaceIncrementList(
viewModel.getFaceIncrement(
// pageNo = taskPageNo,
timestamp = timestamp,
onAllQueryFinished = {
@@ -1223,21 +1224,21 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
}
private fun updateFaceData(list: List<UserFaceModel>) {
private fun updateFaceData(list: List<FaceVO>) {
val faceList = mutableListOf<FaceEntity>()
try {
list.forEach { model ->
if (model.faceDeleted == true) {
list.forEach { vo ->
if (vo.faceDeleted == true) {
//删除数据
FaceDatabase.getInstance(this).faceDao().deleteFaceById(model.userId)
FaceDatabase.getInstance(this).faceDao().deleteFaceById(vo.userId)
} else {
//保存数据
val faceEntity = FaceEntity(
model.userId, null, Base64.decode(model.faceFeatureStr)
vo.userId, null, Base64.decode(vo.faceFeature)
).also {
//1-会员、2-临时用户
it.userType = if (model.member) "1" else "2"
it.cardNo = model.cardNo
it.userType = if (vo.member == true) "1" else "2"
it.cardNo = vo.cardNo
}
faceList.add(faceEntity)
}
@@ -20,7 +20,7 @@ import com.sw.dualscreen.utils.Debouncer
import com.sw.dualscreen.utils.SPUtil
import com.sw.dualscreen.utils.SoundPoolUtil
import com.sw.dualscreen.viewmodel.BaseViewModel
import com.sw.dualscreen.viewmodel.UserViewModel
import com.sw.dualscreen.viewmodel.NetViewModelV2
import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel
import org.greenrobot.eventbus.EventBus
import timber.log.Timber
@@ -43,7 +43,7 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
const val PAY_SUCCESS = "pay_success"
}
val userViewModel by viewModels<UserViewModel>()
val userViewModel by viewModels<NetViewModelV2>()
val recognizeViewModel by viewModels<RecognizeViewModel>()
override fun getViewModel(): BaseViewModel {
@@ -11,12 +11,12 @@ import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.model.response.ClickBackEvent
import com.sw.dualscreen.model.response.UpdateRefreshEvent
import com.sw.dualscreen.viewmodel.BaseViewModel
import com.sw.dualscreen.viewmodel.UserViewModel
import com.sw.dualscreen.viewmodel.NetViewModelV2
import org.greenrobot.eventbus.EventBus
class SettingActivity : BaseActivity<ActivitySettingBinding>() {
val viewModel by viewModels<UserViewModel>()
val viewModel by viewModels<NetViewModelV2>()
override fun getViewModel(): BaseViewModel {
return viewModel
}
@@ -36,8 +36,6 @@ import com.sw.dualscreen.utils.ImageUtil
import com.sw.plate.utils.ToastUtils
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import timber.log.Timber
@SuppressLint("NotifyDataSetChanged")
@@ -263,14 +261,15 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>() {
lifecycleScope.launch {
val totalFileCount = foodCollectionList.count { it.imageFile != null }
settingActivity?.showWaitingDialog2("图片上传中0/$totalFileCount")
val params = HashMap<String, RequestBody>()
//params["placeId"] = restId.toRequestBody()
params["foodId"] = checkedItem!!.foodId.toRequestBody()
params["foodName"] = checkedItem!!.foodName!!.toRequestBody()
params["version"] = GlobalData.foodModelVersion.toRequestBody()
val foodId = checkedItem!!.foodId.toLongOrNull() ?: run {
ToastUtils.showToast("foodId 格式错误")
return@launch
}
val foodName = checkedItem!!.foodName ?: ""
val version = GlobalData.foodModelVersion
ImageUploader(totalList = foodCollectionList, uploadImage = { batch ->
val files = batch.map { it.imageFile }
val files = batch.mapNotNull { it.imageFile }
val foodVectorList = batch.filter { it.imageVector != null }.map {
it.imageVector!!.joinToString(
separator = ",", prefix = "[", postfix = "]"
@@ -279,8 +278,13 @@ class CollectFragment : BaseFragment<FragmentCollectBinding>() {
val foodVectorJson =
foodVectorList.joinToString(separator = ",", prefix = "[", postfix = "]")
Timber.tag(TAG).d("json=$foodVectorJson")
params["foodVector"] = foodVectorJson.toRequestBody()
settingActivity?.viewModel?.uploadCollectFoodPics(files, params)
settingActivity?.viewModel?.uploadCollect(
foodId = foodId,
foodName = foodName,
version = version,
foodVector = foodVectorJson,
fileList = files
)
}, onProgress = { count, batch, idList ->
//batch.forEach {
// it.uploadSuccess = true