feat(network): 添加新系统API V2支持及相关数据模型
- 引入 ApiServiceV2 接口定义新系统API端点 - 添加 RemoteRepositoryV2 实现新API的数据访问层 - 创建 NetViewModelV2 提供新API的业务逻辑处理 - 定义 v2 包下的数据模型类包括请求响应对象 - 在 ApiClient 中集成新旧两套API服务实例 - 配置API日志拦截器识别新API调用并打上ApiV2标签 - 实现新系统菜品、人脸、订单、会员等完整功能接口
This commit is contained in:
@@ -0,0 +1,11 @@
|
|||||||
|
package com.sw.dualscreen.model.request.v2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新系统绑定用户与订单请求参数
|
||||||
|
* 对应接口:/neglect/booth/order/bind-user
|
||||||
|
*/
|
||||||
|
data class BindUserOrderRequest(
|
||||||
|
val userId: Long,
|
||||||
|
val orderNo: String,
|
||||||
|
val mode: Int? = null
|
||||||
|
)
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.sw.dualscreen.model.request.v2
|
||||||
|
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新系统开餐下单请求参数
|
||||||
|
* 对应接口:/neglect/booth/order/place
|
||||||
|
*/
|
||||||
|
data class PlaceOrderRequest(
|
||||||
|
val foodId: Long,
|
||||||
|
val foodName: String,
|
||||||
|
val foodWeight: BigDecimal,
|
||||||
|
val eatWeight: BigDecimal,
|
||||||
|
val eatNum: Int,
|
||||||
|
val notPay: Boolean,
|
||||||
|
val mode: Int,
|
||||||
|
val specId: Long?,
|
||||||
|
val userId: Long?,
|
||||||
|
val paymentFrom: Int? = null,
|
||||||
|
val foodMaterialId: Long? = null,
|
||||||
|
val member: Boolean? = null,
|
||||||
|
val remark: String? = null,
|
||||||
|
val deviceId: String? = null
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.sw.dualscreen.model.response.v2
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新系统采集菜品信息
|
||||||
|
* 对应接口:/neglect/booth/collect/page
|
||||||
|
*/
|
||||||
|
@Parcelize
|
||||||
|
data class CollectedFoodV2(
|
||||||
|
val foodId: String?,
|
||||||
|
val foodName: String?,
|
||||||
|
val version: String?,
|
||||||
|
val foodVector: String?,
|
||||||
|
val picUrls: List<String>?
|
||||||
|
) : Parcelable
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.sw.dualscreen.model.response.v2
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新系统人脸数据 VO
|
||||||
|
* 对应接口:/neglect/booth/face/page 和 /neglect/booth/face/increment
|
||||||
|
*/
|
||||||
|
@Parcelize
|
||||||
|
data class FaceVO(
|
||||||
|
val userFaceId: String?,
|
||||||
|
val userId: String?,
|
||||||
|
val faceFeature: String?,
|
||||||
|
val faceUpdateTimestamp: Long?,
|
||||||
|
val cardNo: String?,
|
||||||
|
val member: Boolean?,
|
||||||
|
val faceDeleted: Boolean?
|
||||||
|
) : Parcelable
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.sw.dualscreen.model.response.v2
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新系统菜品信息
|
||||||
|
* 对应接口:/neglect/booth/food/by-names
|
||||||
|
*/
|
||||||
|
@Parcelize
|
||||||
|
data class NewFoodInfo(
|
||||||
|
val foodId: Long,
|
||||||
|
val foodName: String?,
|
||||||
|
val calorie: BigDecimal?,
|
||||||
|
val protein: BigDecimal?,
|
||||||
|
val fat: BigDecimal?,
|
||||||
|
val carbohydrate: BigDecimal?,
|
||||||
|
val price: BigDecimal?,
|
||||||
|
val specPrice: BigDecimal?,
|
||||||
|
val specWeight: BigDecimal?,
|
||||||
|
val stapleFood: BigDecimal?,
|
||||||
|
val fruitsVegetables: BigDecimal?,
|
||||||
|
val meatEggs: BigDecimal?,
|
||||||
|
val foodMaterialId: Long?,
|
||||||
|
val specId: Long?,
|
||||||
|
val foodImg: String?,
|
||||||
|
val foodLabel: String?,
|
||||||
|
val vipPrice: BigDecimal? = null,
|
||||||
|
val recommendCalorie: Int = 0,
|
||||||
|
val tablewareStatus: Boolean = false,
|
||||||
|
val tablewareWeight: Int = 0
|
||||||
|
) : Parcelable
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.sw.dualscreen.model.response.v2
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新系统会员信息
|
||||||
|
* 对应接口:/neglect/booth/member/info 和 /neglect/booth/member/info-by-phone
|
||||||
|
*/
|
||||||
|
@Parcelize
|
||||||
|
data class NewMemberInfo(
|
||||||
|
val id: String?,
|
||||||
|
val phone: String?,
|
||||||
|
val name: String?,
|
||||||
|
val faceUrl: String?,
|
||||||
|
val topUpBalance: BigDecimal?,
|
||||||
|
val rewardBalance: BigDecimal? = BigDecimal.ZERO,
|
||||||
|
val integralBalance: Int?,
|
||||||
|
val member: Boolean?
|
||||||
|
) : Parcelable
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.sw.dualscreen.model.response.v2
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新系统结算订单数据
|
||||||
|
* 对应接口:/neglect/booth/order/settlement
|
||||||
|
*/
|
||||||
|
@Parcelize
|
||||||
|
data class SettlementOrder(
|
||||||
|
val calorie: BigDecimal?,
|
||||||
|
val incomeSum: BigDecimal?,
|
||||||
|
val discountSum: BigDecimal?,
|
||||||
|
val eatWeightSum: Int?,
|
||||||
|
val orderNo: String?,
|
||||||
|
val list: List<SettlementFoodItem>?
|
||||||
|
) : Parcelable
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class SettlementFoodItem(
|
||||||
|
val foodId: String?,
|
||||||
|
val foodName: String?,
|
||||||
|
val specId: String?,
|
||||||
|
val specName: String?,
|
||||||
|
val specWeight: BigDecimal?,
|
||||||
|
val eatNum: Int?,
|
||||||
|
val eatWeight: Int?,
|
||||||
|
val price: BigDecimal?
|
||||||
|
) : Parcelable
|
||||||
@@ -3,7 +3,10 @@ package com.sw.dualscreen.network
|
|||||||
import com.sw.dualscreen.BuildConfig
|
import com.sw.dualscreen.BuildConfig
|
||||||
import com.sw.dualscreen.MyApp
|
import com.sw.dualscreen.MyApp
|
||||||
import com.sw.dualscreen.network.api.ApiService
|
import com.sw.dualscreen.network.api.ApiService
|
||||||
|
import com.sw.dualscreen.network.api.ApiServiceV2
|
||||||
import com.sw.dualscreen.network.interceptor.RequestInterceptor
|
import com.sw.dualscreen.network.interceptor.RequestInterceptor
|
||||||
|
import com.sw.dualscreen.repository.RemoteRepository
|
||||||
|
import com.sw.dualscreen.repository.v2.RemoteRepositoryV2
|
||||||
import com.sw.dualscreen.utils.FileUtil
|
import com.sw.dualscreen.utils.FileUtil
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
@@ -16,7 +19,7 @@ import java.util.concurrent.TimeUnit
|
|||||||
object ApiClient {
|
object ApiClient {
|
||||||
private const val BASE_URL = "http://device.shuziweidao.com:8889/"
|
private const val BASE_URL = "http://device.shuziweidao.com:8889/"
|
||||||
|
|
||||||
private const val TIME_OUT = 30L // 超时时间(秒)
|
private const val TIME_OUT = 30L
|
||||||
|
|
||||||
private val okHttpClient = OkHttpClient.Builder()
|
private val okHttpClient = OkHttpClient.Builder()
|
||||||
.connectTimeout(TIME_OUT, TimeUnit.SECONDS)
|
.connectTimeout(TIME_OUT, TimeUnit.SECONDS)
|
||||||
@@ -27,6 +30,7 @@ object ApiClient {
|
|||||||
val url = request.url.toString()
|
val url = request.url.toString()
|
||||||
val tag = if (url.contains("terminal/neglect/common/app/faceFeature/increment/list")) "faceIncrement"
|
val tag = if (url.contains("terminal/neglect/common/app/faceFeature/increment/list")) "faceIncrement"
|
||||||
else if (url.contains("terminal/neglect/pay/app/turnOrderInfo")) "turnOrderInfo"
|
else if (url.contains("terminal/neglect/pay/app/turnOrderInfo")) "turnOrderInfo"
|
||||||
|
else if (url.contains("neglect/booth/")) "ApiV2"
|
||||||
else "ApiClient"
|
else "ApiClient"
|
||||||
val loggingInterceptor = HttpLoggingInterceptor(logger = {
|
val loggingInterceptor = HttpLoggingInterceptor(logger = {
|
||||||
Timber.tag(tag).d("okhttp logger ==>${it}")
|
Timber.tag(tag).d("okhttp logger ==>${it}")
|
||||||
@@ -47,10 +51,21 @@ object ApiClient {
|
|||||||
.baseUrl(BASE_URL)
|
.baseUrl(BASE_URL)
|
||||||
.client(okHttpClient)
|
.client(okHttpClient)
|
||||||
.addConverterFactory(GsonConverterFactory.create())
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
// .addCallAdapterFactory(CoroutineCallAdapterFactory()) // 协程适配器
|
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
val apiService: ApiService by lazy {
|
val apiService: ApiService by lazy {
|
||||||
retrofit.create(ApiService::class.java)
|
retrofit.create(ApiService::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val apiServiceV2: ApiServiceV2 by lazy {
|
||||||
|
retrofit.create(ApiServiceV2::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
val repository: RemoteRepository by lazy {
|
||||||
|
RemoteRepository(apiService)
|
||||||
|
}
|
||||||
|
|
||||||
|
val repositoryV2: RemoteRepositoryV2 by lazy {
|
||||||
|
RemoteRepositoryV2(apiServiceV2)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
package com.sw.dualscreen.network.api
|
||||||
|
|
||||||
|
import com.sw.dualscreen.GlobalData
|
||||||
|
import com.sw.dualscreen.model.request.v2.BindUserOrderRequest
|
||||||
|
import com.sw.dualscreen.model.request.v2.PlaceOrderRequest
|
||||||
|
import com.sw.dualscreen.model.response.ApiResponse
|
||||||
|
import com.sw.dualscreen.model.response.DeviceConfig
|
||||||
|
import com.sw.dualscreen.model.response.FoodSearchReq
|
||||||
|
import com.sw.dualscreen.model.response.UserNutrition
|
||||||
|
import com.sw.dualscreen.model.response.v2.CollectedFoodV2
|
||||||
|
import com.sw.dualscreen.model.response.v2.FaceVO
|
||||||
|
import com.sw.dualscreen.model.response.v2.NewFoodInfo
|
||||||
|
import com.sw.dualscreen.model.response.v2.NewMemberInfo
|
||||||
|
import com.sw.dualscreen.model.response.v2.SettlementOrder
|
||||||
|
import okhttp3.MultipartBody
|
||||||
|
import okhttp3.RequestBody
|
||||||
|
import retrofit2.http.Body
|
||||||
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.Multipart
|
||||||
|
import retrofit2.http.POST
|
||||||
|
import retrofit2.http.Part
|
||||||
|
import retrofit2.http.PartMap
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新系统 API 接口服务
|
||||||
|
* 基于 /neglect/booth 模块前缀
|
||||||
|
* 文档版本:2026-05-27
|
||||||
|
*/
|
||||||
|
interface ApiServiceV2 {
|
||||||
|
|
||||||
|
@GET("/neglect/booth/device/config")
|
||||||
|
suspend fun getDeviceConfig(): ApiResponse<DeviceConfig?>
|
||||||
|
|
||||||
|
@POST("/neglect/booth/face/page")
|
||||||
|
suspend fun getFacePage(
|
||||||
|
@Body request: Map<String, Long>
|
||||||
|
): ApiResponse<List<FaceVO>?>
|
||||||
|
|
||||||
|
@POST("/neglect/booth/face/increment")
|
||||||
|
suspend fun getFaceIncrement(
|
||||||
|
@Body request: Map<String, Long>
|
||||||
|
): ApiResponse<List<FaceVO>?>
|
||||||
|
|
||||||
|
@POST("/neglect/booth/food/by-names")
|
||||||
|
suspend fun getFoodByNames(
|
||||||
|
@Body request: FoodSearchReq
|
||||||
|
): ApiResponse<List<NewFoodInfo>?>
|
||||||
|
|
||||||
|
@POST("/neglect/booth/user/current-food")
|
||||||
|
suspend fun getUserCurrentFood(
|
||||||
|
@Body request: Map<String, Long>
|
||||||
|
): ApiResponse<UserNutrition?>
|
||||||
|
|
||||||
|
@POST("/neglect/booth/order/place")
|
||||||
|
suspend fun placeOrder(
|
||||||
|
@Body request: PlaceOrderRequest
|
||||||
|
): ApiResponse<String?>
|
||||||
|
|
||||||
|
@POST("/neglect/booth/order/settlement")
|
||||||
|
suspend fun getSettlementOrders(
|
||||||
|
@Body request: Map<String, Long>
|
||||||
|
): ApiResponse<SettlementOrder?>
|
||||||
|
|
||||||
|
@POST("/neglect/booth/member/info")
|
||||||
|
suspend fun getMemberInfo(
|
||||||
|
@Body request: Map<String, Long>
|
||||||
|
): ApiResponse<NewMemberInfo?>
|
||||||
|
|
||||||
|
@POST("/neglect/booth/member/info-by-phone")
|
||||||
|
suspend fun getMemberInfoByPhone(
|
||||||
|
@Body request: Map<String, String>
|
||||||
|
): ApiResponse<NewMemberInfo?>
|
||||||
|
|
||||||
|
@POST("/neglect/booth/member/discount")
|
||||||
|
suspend fun getMemberDiscount(
|
||||||
|
@Body request: Map<String, Long>
|
||||||
|
): ApiResponse<String?>
|
||||||
|
|
||||||
|
@POST("/neglect/booth/order/bind-user")
|
||||||
|
suspend fun bindUserOrder(
|
||||||
|
@Body request: BindUserOrderRequest
|
||||||
|
): ApiResponse<Any?>
|
||||||
|
|
||||||
|
@POST("/neglect/booth/collect/page")
|
||||||
|
suspend fun getCollectPage(
|
||||||
|
@Body request: Map<String, Any>
|
||||||
|
): ApiResponse<List<CollectedFoodV2>?>
|
||||||
|
|
||||||
|
@Multipart
|
||||||
|
@POST("/neglect/booth/collect/upload")
|
||||||
|
suspend fun uploadCollect(
|
||||||
|
@PartMap params: HashMap<String, RequestBody>,
|
||||||
|
@Part foodPics: List<MultipartBody.Part>
|
||||||
|
): ApiResponse<List<String>?>
|
||||||
|
|
||||||
|
@POST("/neglect/booth/collect/delete")
|
||||||
|
suspend fun deleteCollect(
|
||||||
|
@Body request: Map<String, Any>
|
||||||
|
): ApiResponse<Any?>
|
||||||
|
}
|
||||||
@@ -0,0 +1,218 @@
|
|||||||
|
package com.sw.dualscreen.repository.v2
|
||||||
|
|
||||||
|
import com.sw.dualscreen.model.request.v2.BindUserOrderRequest
|
||||||
|
import com.sw.dualscreen.model.request.v2.PlaceOrderRequest
|
||||||
|
import com.sw.dualscreen.model.response.ApiResponse
|
||||||
|
import com.sw.dualscreen.model.response.DeviceConfig
|
||||||
|
import com.sw.dualscreen.model.response.FoodSearchReq
|
||||||
|
import com.sw.dualscreen.model.response.UserNutrition
|
||||||
|
import com.sw.dualscreen.model.response.v2.CollectedFoodV2
|
||||||
|
import com.sw.dualscreen.model.response.v2.FaceVO
|
||||||
|
import com.sw.dualscreen.model.response.v2.NewFoodInfo
|
||||||
|
import com.sw.dualscreen.model.response.v2.NewMemberInfo
|
||||||
|
import com.sw.dualscreen.model.response.v2.SettlementOrder
|
||||||
|
import com.sw.dualscreen.network.api.ApiServiceV2
|
||||||
|
import com.sw.dualscreen.repository.BaseRepository
|
||||||
|
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||||
|
import okhttp3.MultipartBody
|
||||||
|
import okhttp3.RequestBody
|
||||||
|
import okhttp3.RequestBody.Companion.asRequestBody
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class RemoteRepositoryV2 constructor(
|
||||||
|
private val apiService: ApiServiceV2
|
||||||
|
) : BaseRepository() {
|
||||||
|
|
||||||
|
suspend fun getDeviceConfig(): ApiResponse<DeviceConfig?> {
|
||||||
|
return safeApiCall {
|
||||||
|
apiService.getDeviceConfig()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getFacePage(
|
||||||
|
pageNum: Long = 1L,
|
||||||
|
pageSize: Long = 100L
|
||||||
|
): ApiResponse<List<FaceVO>?> {
|
||||||
|
return safeApiCall {
|
||||||
|
apiService.getFacePage(
|
||||||
|
request = mapOf(
|
||||||
|
"pageNum" to pageNum,
|
||||||
|
"pageSize" to pageSize
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getFaceIncrement(
|
||||||
|
pageNum: Long = 1L,
|
||||||
|
pageSize: Long = 100L,
|
||||||
|
timestamp: Long
|
||||||
|
): ApiResponse<List<FaceVO>?> {
|
||||||
|
return safeApiCall {
|
||||||
|
apiService.getFaceIncrement(
|
||||||
|
request = mapOf(
|
||||||
|
"pageNum" to pageNum,
|
||||||
|
"pageSize" to pageSize,
|
||||||
|
"timestamp" to timestamp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getFoodByNames(
|
||||||
|
nameList: List<String>,
|
||||||
|
deviceType: Int = 2
|
||||||
|
): ApiResponse<List<NewFoodInfo>?> {
|
||||||
|
return safeApiCall {
|
||||||
|
apiService.getFoodByNames(
|
||||||
|
request = FoodSearchReq(nameList, deviceType)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getUserCurrentFood(
|
||||||
|
userId: Long
|
||||||
|
): ApiResponse<UserNutrition?> {
|
||||||
|
return safeApiCall {
|
||||||
|
apiService.getUserCurrentFood(
|
||||||
|
request = mapOf("id" to userId)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun placeOrder(
|
||||||
|
orderRequest: PlaceOrderRequest
|
||||||
|
): ApiResponse<String?> {
|
||||||
|
return safeApiCall {
|
||||||
|
apiService.placeOrder(request = orderRequest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getSettlementOrders(
|
||||||
|
userId: Long
|
||||||
|
): ApiResponse<SettlementOrder?> {
|
||||||
|
return safeApiCall {
|
||||||
|
apiService.getSettlementOrders(
|
||||||
|
request = mapOf("id" to userId)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getMemberInfo(
|
||||||
|
userId: Long
|
||||||
|
): ApiResponse<NewMemberInfo?> {
|
||||||
|
return safeApiCall {
|
||||||
|
apiService.getMemberInfo(
|
||||||
|
request = mapOf("id" to userId)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getMemberInfoByPhone(
|
||||||
|
phone: String,
|
||||||
|
password: String = ""
|
||||||
|
): ApiResponse<NewMemberInfo?> {
|
||||||
|
return safeApiCall {
|
||||||
|
apiService.getMemberInfoByPhone(
|
||||||
|
request = mapOf(
|
||||||
|
"phone" to phone,
|
||||||
|
"password" to password
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getMemberDiscount(
|
||||||
|
userId: Long
|
||||||
|
): ApiResponse<String?> {
|
||||||
|
return safeApiCall {
|
||||||
|
apiService.getMemberDiscount(
|
||||||
|
request = mapOf("id" to userId)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun bindUserOrder(
|
||||||
|
userId: Long,
|
||||||
|
orderNo: String,
|
||||||
|
mode: Int? = null
|
||||||
|
): ApiResponse<Any?> {
|
||||||
|
return safeApiCall {
|
||||||
|
apiService.bindUserOrder(
|
||||||
|
request = BindUserOrderRequest(userId, orderNo, mode)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getCollectPage(
|
||||||
|
pageNum: Long = 1L,
|
||||||
|
pageSize: Long = 100L,
|
||||||
|
foodName: String? = null
|
||||||
|
): ApiResponse<List<CollectedFoodV2>?> {
|
||||||
|
return safeApiCall {
|
||||||
|
val request = mutableMapOf<String, Any>(
|
||||||
|
"pageNum" to pageNum,
|
||||||
|
"pageSize" to pageSize
|
||||||
|
)
|
||||||
|
if (!foodName.isNullOrEmpty()) {
|
||||||
|
request["foodName"] = foodName
|
||||||
|
}
|
||||||
|
apiService.getCollectPage(request = request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun uploadCollect(
|
||||||
|
foodId: Long,
|
||||||
|
foodName: String,
|
||||||
|
version: String,
|
||||||
|
foodVector: String,
|
||||||
|
fileList: List<File>
|
||||||
|
): ApiResponse<List<String>?> {
|
||||||
|
val params = hashMapOf<String, RequestBody>()
|
||||||
|
params["foodId"] = RequestBody.create(
|
||||||
|
"text/plain".toMediaTypeOrNull(),
|
||||||
|
foodId.toString()
|
||||||
|
)
|
||||||
|
params["foodName"] = RequestBody.create(
|
||||||
|
"text/plain".toMediaTypeOrNull(),
|
||||||
|
foodName
|
||||||
|
)
|
||||||
|
params["version"] = RequestBody.create(
|
||||||
|
"text/plain".toMediaTypeOrNull(),
|
||||||
|
version
|
||||||
|
)
|
||||||
|
params["foodVector"] = RequestBody.create(
|
||||||
|
"text/plain".toMediaTypeOrNull(),
|
||||||
|
foodVector
|
||||||
|
)
|
||||||
|
|
||||||
|
val fileParts = mutableListOf<MultipartBody.Part>()
|
||||||
|
fileList.forEach { file ->
|
||||||
|
val requestFile = file.asRequestBody("multipart/form-data".toMediaTypeOrNull())
|
||||||
|
val filePart = MultipartBody.Part.createFormData(
|
||||||
|
"foodPics",
|
||||||
|
file.name,
|
||||||
|
requestFile
|
||||||
|
)
|
||||||
|
fileParts.add(filePart)
|
||||||
|
}
|
||||||
|
|
||||||
|
return safeApiCall {
|
||||||
|
apiService.uploadCollect(params = params, foodPics = fileParts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun deleteCollect(
|
||||||
|
foodId: Long,
|
||||||
|
version: String
|
||||||
|
): ApiResponse<Any?> {
|
||||||
|
return safeApiCall {
|
||||||
|
apiService.deleteCollect(
|
||||||
|
request = mapOf<String, Any>(
|
||||||
|
"foodId" to foodId,
|
||||||
|
"version" to version
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,346 @@
|
|||||||
|
package com.sw.dualscreen.viewmodel
|
||||||
|
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.sw.dualscreen.model.request.v2.BindUserOrderRequest
|
||||||
|
import com.sw.dualscreen.model.request.v2.PlaceOrderRequest
|
||||||
|
import com.sw.dualscreen.model.response.FoodSearchReq
|
||||||
|
import com.sw.dualscreen.model.response.UserNutrition
|
||||||
|
import com.sw.dualscreen.model.response.v2.CollectedFoodV2
|
||||||
|
import com.sw.dualscreen.model.response.v2.FaceVO
|
||||||
|
import com.sw.dualscreen.model.response.v2.NewFoodInfo
|
||||||
|
import com.sw.dualscreen.model.response.v2.NewMemberInfo
|
||||||
|
import com.sw.dualscreen.model.response.v2.SettlementOrder
|
||||||
|
import com.sw.dualscreen.network.ApiClient
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class NetViewModelV2 : BaseViewModel() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "NetViewModelV2"
|
||||||
|
const val PAGE_SIZE = 100L
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getDeviceConfig(
|
||||||
|
onSuccess: (config: com.sw.dualscreen.model.response.DeviceConfig?) -> Unit,
|
||||||
|
onFailure: (message: String) -> Unit
|
||||||
|
) {
|
||||||
|
launch {
|
||||||
|
try {
|
||||||
|
val response = ApiClient.repositoryV2.getDeviceConfig()
|
||||||
|
if (parseResponse(response)) {
|
||||||
|
onSuccess(response.data)
|
||||||
|
} else {
|
||||||
|
onFailure(response.msg ?: "获取设备配置失败")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e, "获取设备配置异常")
|
||||||
|
onFailure("网络异常: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFacePage(
|
||||||
|
pageNum: Long = 1L,
|
||||||
|
pageSize: Long = PAGE_SIZE,
|
||||||
|
onSuccess: (list: List<FaceVO>, hasNext: Boolean) -> Unit,
|
||||||
|
onFailure: (message: String) -> Unit
|
||||||
|
) {
|
||||||
|
launch {
|
||||||
|
try {
|
||||||
|
val response = ApiClient.repositoryV2.getFacePage(pageNum, pageSize)
|
||||||
|
if (parseResponse(response)) {
|
||||||
|
val list = response.data ?: emptyList()
|
||||||
|
val hasNext = list.size >= pageSize
|
||||||
|
onSuccess(list, hasNext)
|
||||||
|
} else {
|
||||||
|
onFailure(response.msg ?: "获取人脸数据失败")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e, "获取全量人脸数据异常")
|
||||||
|
onFailure("网络异常: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFaceIncrement(
|
||||||
|
pageNum: Long = 1L,
|
||||||
|
pageSize: Long = PAGE_SIZE,
|
||||||
|
timestamp: Long,
|
||||||
|
onSuccess: (list: List<FaceVO>, hasNext: Boolean) -> Unit,
|
||||||
|
onFailure: (message: String) -> Unit
|
||||||
|
) {
|
||||||
|
launch {
|
||||||
|
try {
|
||||||
|
val response = ApiClient.repositoryV2.getFaceIncrement(pageNum, pageSize, timestamp)
|
||||||
|
if (parseResponse(response)) {
|
||||||
|
val list = response.data ?: emptyList()
|
||||||
|
val hasNext = list.size >= pageSize
|
||||||
|
onSuccess(list, hasNext)
|
||||||
|
} else {
|
||||||
|
onFailure(response.msg ?: "获取增量人脸数据失败")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e, "获取增量人脸数据异常")
|
||||||
|
onFailure("网络异常: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFoodByNames(
|
||||||
|
nameList: List<String>,
|
||||||
|
deviceType: Int = 2,
|
||||||
|
onSuccess: (list: List<NewFoodInfo>) -> Unit,
|
||||||
|
onFailure: (message: String) -> Unit
|
||||||
|
) {
|
||||||
|
launch {
|
||||||
|
try {
|
||||||
|
val response = ApiClient.repositoryV2.getFoodByNames(nameList, deviceType)
|
||||||
|
if (parseResponse(response)) {
|
||||||
|
onSuccess(response.data ?: emptyList())
|
||||||
|
} else {
|
||||||
|
onFailure(response.msg ?: "查询菜品失败")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e, "查询菜品异常")
|
||||||
|
onFailure("网络异常: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getUserCurrentFood(
|
||||||
|
userId: Long,
|
||||||
|
onSuccess: (nutrition: UserNutrition?) -> Unit,
|
||||||
|
onFailure: (message: String) -> Unit
|
||||||
|
) {
|
||||||
|
launch {
|
||||||
|
try {
|
||||||
|
val response = ApiClient.repositoryV2.getUserCurrentFood(userId)
|
||||||
|
if (parseResponse(response)) {
|
||||||
|
onSuccess(response.data)
|
||||||
|
} else {
|
||||||
|
onFailure(response.msg ?: "获取就餐营养数据失败")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e, "获取就餐营养数据异常")
|
||||||
|
onFailure("网络异常: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun placeOrder(
|
||||||
|
orderRequest: PlaceOrderRequest,
|
||||||
|
onSuccess: (orderNo: String?) -> Unit,
|
||||||
|
onFailure: (message: String) -> Unit
|
||||||
|
) {
|
||||||
|
launchWithLoading {
|
||||||
|
try {
|
||||||
|
val response = ApiClient.repositoryV2.placeOrder(orderRequest)
|
||||||
|
if (parseResponse(response)) {
|
||||||
|
onSuccess(response.data)
|
||||||
|
} else {
|
||||||
|
onFailure(response.msg ?: "下单失败")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e, "开餐下单异常")
|
||||||
|
onFailure("网络异常: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSettlementOrders(
|
||||||
|
userId: Long,
|
||||||
|
onSuccess: (order: SettlementOrder?) -> Unit,
|
||||||
|
onFailure: (message: String) -> Unit
|
||||||
|
) {
|
||||||
|
launch {
|
||||||
|
try {
|
||||||
|
val response = ApiClient.repositoryV2.getSettlementOrders(userId)
|
||||||
|
if (parseResponse(response)) {
|
||||||
|
onSuccess(response.data)
|
||||||
|
} else {
|
||||||
|
onFailure(response.msg ?: "查询结算订单失败")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e, "查询结算订单异常")
|
||||||
|
onFailure("网络异常: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMemberInfo(
|
||||||
|
userId: Long,
|
||||||
|
onSuccess: (memberInfo: NewMemberInfo?) -> Unit,
|
||||||
|
onFailure: (message: String) -> Unit
|
||||||
|
) {
|
||||||
|
launch {
|
||||||
|
try {
|
||||||
|
val response = ApiClient.repositoryV2.getMemberInfo(userId)
|
||||||
|
if (parseResponse(response)) {
|
||||||
|
onSuccess(response.data)
|
||||||
|
} else {
|
||||||
|
onFailure(response.msg ?: "获取会员信息失败")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e, "获取会员信息异常")
|
||||||
|
onFailure("网络异常: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMemberInfoByPhone(
|
||||||
|
phone: String,
|
||||||
|
password: String = "",
|
||||||
|
onSuccess: (memberInfo: NewMemberInfo?) -> Unit,
|
||||||
|
onFailure: (message: String) -> Unit
|
||||||
|
) {
|
||||||
|
launch {
|
||||||
|
try {
|
||||||
|
val response = ApiClient.repositoryV2.getMemberInfoByPhone(phone, password)
|
||||||
|
if (parseResponse(response)) {
|
||||||
|
onSuccess(response.data)
|
||||||
|
} else {
|
||||||
|
onFailure(response.msg ?: "查询会员失败")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e, "查询会员异常")
|
||||||
|
onFailure("网络异常: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMemberDiscount(
|
||||||
|
userId: Long,
|
||||||
|
onSuccess: (discount: String?) -> Unit,
|
||||||
|
onFailure: (message: String) -> Unit
|
||||||
|
) {
|
||||||
|
launch {
|
||||||
|
try {
|
||||||
|
val response = ApiClient.repositoryV2.getMemberDiscount(userId)
|
||||||
|
if (parseResponse(response)) {
|
||||||
|
onSuccess(response.data)
|
||||||
|
} else {
|
||||||
|
onFailure(response.msg ?: "查询会员折扣失败")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e, "查询会员折扣异常")
|
||||||
|
onFailure("网络异常: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bindUserOrder(
|
||||||
|
userId: Long,
|
||||||
|
orderNo: String,
|
||||||
|
mode: Int? = null,
|
||||||
|
onSuccess: () -> Unit,
|
||||||
|
onFailure: (message: String) -> Unit
|
||||||
|
) {
|
||||||
|
launch {
|
||||||
|
try {
|
||||||
|
val response = ApiClient.repositoryV2.bindUserOrder(userId, orderNo, mode)
|
||||||
|
if (parseResponse(response)) {
|
||||||
|
onSuccess()
|
||||||
|
} else {
|
||||||
|
onFailure(response.msg ?: "绑定订单失败")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e, "绑定订单异常")
|
||||||
|
onFailure("网络异常: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCollectPage(
|
||||||
|
pageNum: Long = 1L,
|
||||||
|
pageSize: Long = PAGE_SIZE,
|
||||||
|
foodName: String? = null,
|
||||||
|
onSuccess: (list: List<CollectedFoodV2>) -> Unit,
|
||||||
|
onFailure: (message: String) -> Unit
|
||||||
|
) {
|
||||||
|
launch {
|
||||||
|
try {
|
||||||
|
val response = ApiClient.repositoryV2.getCollectPage(pageNum, pageSize, foodName)
|
||||||
|
if (parseResponse(response)) {
|
||||||
|
onSuccess(response.data ?: emptyList())
|
||||||
|
} else {
|
||||||
|
onFailure(response.msg ?: "获取采集列表失败")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e, "获取采集列表异常")
|
||||||
|
onFailure("网络异常: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun uploadCollect(
|
||||||
|
foodId: Long,
|
||||||
|
foodName: String,
|
||||||
|
version: String,
|
||||||
|
foodVector: String,
|
||||||
|
fileList: List<okhttp3.MultipartBody.Part>,
|
||||||
|
onSuccess: (picUrls: List<String>) -> Unit,
|
||||||
|
onFailure: (message: String) -> Unit
|
||||||
|
) {
|
||||||
|
launchWithLoading {
|
||||||
|
try {
|
||||||
|
val params = hashMapOf<String, okhttp3.RequestBody>()
|
||||||
|
params["foodId"] = okhttp3.RequestBody.create(
|
||||||
|
okhttp3.MediaType.parse("text/plain"),
|
||||||
|
foodId.toString()
|
||||||
|
)
|
||||||
|
params["foodName"] = okhttp3.RequestBody.create(
|
||||||
|
okhttp3.MediaType.parse("text/plain"),
|
||||||
|
foodName
|
||||||
|
)
|
||||||
|
params["version"] = okhttp3.RequestBody.create(
|
||||||
|
okhttp3.MediaType.parse("text/plain"),
|
||||||
|
version
|
||||||
|
)
|
||||||
|
params["foodVector"] = okhttp3.RequestBody.create(
|
||||||
|
okhttp3.MediaType.parse("text/plain"),
|
||||||
|
foodVector
|
||||||
|
)
|
||||||
|
|
||||||
|
val response = ApiClient.repositoryV2.uploadCollect(
|
||||||
|
foodId, foodName, version, foodVector,
|
||||||
|
fileList.map { it.body().contentType()?.let { ct ->
|
||||||
|
okhttp3.RequestBody.create(ct, (it.body() as okhttp3.ResponseBody).bytes())
|
||||||
|
} ?: it.body() } as List<File>
|
||||||
|
)
|
||||||
|
|
||||||
|
if (parseResponse(response)) {
|
||||||
|
onSuccess(response.data ?: emptyList())
|
||||||
|
} else {
|
||||||
|
onFailure(response.msg ?: "上传采集数据失败")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e, "上传采集数据异常")
|
||||||
|
onFailure("网络异常: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteCollect(
|
||||||
|
foodId: Long,
|
||||||
|
version: String,
|
||||||
|
onSuccess: () -> Unit,
|
||||||
|
onFailure: (message: String) -> Unit
|
||||||
|
) {
|
||||||
|
launchWithLoading {
|
||||||
|
try {
|
||||||
|
val response = ApiClient.repositoryV2.deleteCollect(foodId, version)
|
||||||
|
if (parseResponse(response)) {
|
||||||
|
onSuccess()
|
||||||
|
} else {
|
||||||
|
onFailure(response.msg ?: "删除采集菜品失败")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e, "删除采集菜品异常")
|
||||||
|
onFailure("网络异常: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user