Files
StallDualScreen/app/src/main/java/com/sw/dualscreen/viewmodel/UserViewModel.kt
T
2026-01-06 18:49:33 +08:00

591 lines
20 KiB
Kotlin

package com.sw.dualscreen.viewmodel
import androidx.lifecycle.viewModelScope
import com.arcsoft.face.ErrorInfo
import com.sw.dualscreen.GlobalData
import com.sw.dualscreen.GlobalKey
import com.sw.dualscreen.model.request.UserNutritionParam
import com.sw.dualscreen.model.response.DeviceConfig
import com.sw.dualscreen.model.response.DinnerType
import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.model.response.FoodOrder
import com.sw.dualscreen.model.response.FoodVector
import com.sw.dualscreen.model.response.MemberInfo
import com.sw.dualscreen.model.response.UserFaceModel
import com.sw.dualscreen.model.response.UserFaceModel2
import com.sw.dualscreen.model.response.UserNutrition
import com.sw.dualscreen.objbox.CollectedFoodInfo
import com.sw.dualscreen.utils.SPUtil
import com.sw.dualscreen.utils.SpTool
import com.sw.plate.App
import com.sw.plate.utils.Base64
import com.sw.plate.utils.ToastUtils
import com.sw.plate.utils.arcface.FaceApi
import com.sw.plate.utils.arcface.facedb.entity.FaceEntity
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.RequestBody
import timber.log.Timber
import java.io.File
class UserViewModel : BaseViewModel() {
companion object {
private const val TAG = "UserViewModel"
const val PAGE_SIZE = 100
}
private val faceApi: FaceApi = FaceApi()
// 识别出的列表
private val _identifiedFoodInfoList = MutableStateFlow<List<FoodInfo>>(emptyList())
val identifiedFoodInfoList: StateFlow<List<FoodInfo>> = _identifiedFoodInfoList
// 搜索出的食物列表
private val _searchFoodInfoList = MutableStateFlow<List<FoodInfo>>(emptyList())
val searchFoodInfoList: StateFlow<List<FoodInfo>> = _searchFoodInfoList
// 就餐数据
// private val _nutritionData = MutableStateFlow<UserNutritionData?>(null)
// val nutritionData: StateFlow<UserNutritionData?> = _nutritionData
/**
* 饭点类型 早餐/午餐/晚餐
*/
private val _dinnerTypeInfo = MutableStateFlow<DinnerType?>(null)
val dinnerTypeInfo: StateFlow<DinnerType?> = _dinnerTypeInfo
/**
* 人脸加载完成
*/
private val _loadFaceResult = MutableStateFlow<Boolean>(false)
val loadFaceResult: StateFlow<Boolean> = _loadFaceResult
private val _identifiedFoodInfoList2 = MutableStateFlow<List<FoodInfo>>(emptyList())
val identifiedFoodInfoList2: StateFlow<List<FoodInfo>> = _identifiedFoodInfoList2
private var lastFaceTimestamp = 0L
/**
* 获取token
*/
fun getEquipmentToken(qrcodeId: String = GlobalData.deviceId) {
// Timber.tag(TAG).d("getEquipmentToken")
// launchWithLoading {
// val response = repository.getEquipmentToken(qrcodeId)
// if (parseResponse(response)) {
// // 缓存token
// SPUtil.getInstance().put(GlobalKey.KEY_TOKEN, response.result)
// // 首次运行获取人脸数据
// if (SPUtil.getInstance().get(GlobalKey.KEY_FIRST_RUN, false) != true) {
// getUserFaceCache(pageNo = 1)
// }
// }
// }
}
/**
* 获取人脸数据
*/
fun getUserFaceCache(pageNo: Int = 1, pageSize: Int = PAGE_SIZE) {
var currentPageNo = pageNo
Timber.tag(TAG).d("getUserFaceCache index = $currentPageNo")
launch {
_loadFaceResult.value = false
//获取全量数据时,时间戳改为0
SpTool.setLastFaceTimestamp(0)
val response = repository.getUserFaceCache(currentPageNo)
if (parseResponse(response)) {
// 获取成功一次后缓存状态
SPUtil.getInstance().put(GlobalKey.KEY_FIRST_RUN, true)
withContext(Dispatchers.Default) {
val list: List<UserFaceModel> = response.data ?: emptyList()
if (pageNo == 1 && list.isEmpty()) {
ToastUtils.showToast("查询人脸数据为空")
return@withContext
}
// val item = list.firstOrNull { it.userId == "1951105919342936066" }
// Timber.tag(TAG).d("getUserFaceCache userId = ${item?.userId}")
val faceEntity = list.map {
FaceEntity(it.userId, null, Base64.decode(it.faceFeatureStr))
}
faceApi.updateFaceData(currentPageNo, faceEntity)
if (list.size >= pageSize) {
lastFaceTimestamp = list.last().faceUpdateTimestamp ?: 0L
currentPageNo++
getUserFaceCache(currentPageNo)
return@withContext
}
//查询完成所有数据,保存时间戳
if (list.isNotEmpty()) {
//非空最后一条数据的是时间戳,空使用上次list最后一条时间戳
lastFaceTimestamp = list.last().faceUpdateTimestamp ?: 0L
}
SpTool.setLastFaceTimestamp(lastFaceTimestamp)
_loadFaceResult.value = true
}
// val nextPageIndex = response.result?.nextPageIndex ?: -1
// if (nextPageIndex > 0) {
// getUserFaceCache(nextPageIndex)
// } else {
// _loadFaceResult.value = true
// }
}
}
}
// fun getUserFaceCache2(index: Int = 0) {
// Timber.d("getUserFaceCache index = $index")
// launch {
// _loadFaceResult.value = false
// val response = repository.getUserFaceCache2(index)
// if (parseResponse(response)) {
// // 获取成功一次后缓存状态
// SPUtil.getInstance().put(GlobalKey.KEY_FIRST_RUN, true)
// withContext(Dispatchers.Default) {
// val list: List<UserFaceModel2> = response.result?.records ?: emptyList()
// val faceEntity = list.map {
// FaceEntity(it.userId, null, Base64.decode(it.face))
// }
// faceApi.updateFaceData2(index, faceEntity)
// }
// val nextPageIndex = response.result?.nextPageIndex ?: -1
// if (nextPageIndex > 0) {
// getUserFaceCache2(nextPageIndex)
// } else {
// _loadFaceResult.value = true
// }
// }
// }
// }
/**
* 获取人脸数据
*/
fun getFaceIncrementList(
pageNo: Int = 1,
pageSize: Int = PAGE_SIZE,
timestamp: Long,
onAllQueryFinished: () -> Unit,
onPageQueryFinished: (List<UserFaceModel>) -> Unit
) {
Timber.tag(TAG).d("getFaceIncrementList")
launch {
val response = repository.getFaceIncrementList(
pageNum = pageNo.toLong(),
pageSize = pageSize.toLong(),
timestamp = timestamp
)
if (parseResponse(response)) {
withContext(Dispatchers.Default) {
val list: List<UserFaceModel> = response.data ?: emptyList()
if (pageNo == 1 && list.isEmpty()) {
return@withContext
}
onPageQueryFinished(list)
if (list.size >= pageSize) {
lastFaceTimestamp = list.last().faceUpdateTimestamp ?: 0L
getFaceIncrementList(
pageNo = pageNo + 1,
pageSize = pageSize,
timestamp = timestamp,
onAllQueryFinished = onAllQueryFinished,
onPageQueryFinished = onPageQueryFinished
)
return@withContext
}
//查询完成所有数据,保存时间戳
if (list.isNotEmpty()) {
//非空实现最后一条数据的是时间戳,空使用上次list最后一条时间戳
lastFaceTimestamp = list.last().faceUpdateTimestamp ?: 0L
}
SpTool.setLastFaceTimestamp(lastFaceTimestamp)
onAllQueryFinished()
}
}
}
}
fun getCollectedFoodList(
pageNo: Int = 1,
pageSize: Int = 100,
foodName: String,
block: (List<CollectedFoodInfo>) -> Unit
) {
Timber.tag(TAG).d("getCollectedFoodList index = $pageNo")
launch {
val response = repository.getCollectedFoodList(
pageNum = pageNo,
pageSize = pageSize,
foodName = foodName
)
if (parseResponse(response)) {
withContext(Dispatchers.Default) {
val list: List<CollectedFoodInfo> = response.data ?: emptyList()
block(list)
}
}
}
}
/**
* 激活人脸识别引擎
*/
fun activeEngine() {
Timber.tag(TAG).d("activeEngine")
faceApi.activeEngine(
App.getContext(),
GlobalData.appId,
GlobalData.sdkKey,
GlobalData.activeKey,
object : FaceApi.ActiveCallback {
override fun onSuccess(activeCode: Int) {
Timber.tag(TAG).d("activeEngine activeCode = $activeCode")
viewModelScope.launch(Dispatchers.Main) {
when (activeCode) {
ErrorInfo.MOK -> {
ToastUtils.showToast("激活引擎成功")
}
ErrorInfo.MERR_ASF_ALREADY_ACTIVATED -> {
// ToastUtils.showToast("引擎已激活,无需再次激活")
}
else -> {
ToastUtils.showToast("激活引擎失败($activeCode)")
}
}
}
}
override fun onFail(e: Exception?) {
viewModelScope.launch(Dispatchers.Main) {
ToastUtils.showToast("激活引擎异常,${e?.message}")
}
}
})
}
// fun getIdentifiedFoodList() {
// Timber.tag(TAG).d("identifiedFoodList")
// launchWithLoading {
// val response = repository.getRestInfoFoodsByType(foodName = "")
// if (parseResponse(response)) {
// _identifiedFoodInfoList.value = response.result ?: emptyList()
// }
// }
// }
fun cleanIdentifiedFoodInfoList() {
Timber.tag(TAG).d("cleanIdentifiedFoodInfoList")
_identifiedFoodInfoList.value = emptyList<FoodInfo>()
}
/**
* 搜索食物
*/
fun searchByFoodName(foodName: String, action: (List<FoodInfo>) -> Unit = {}) {
Timber.tag(TAG).d("searchByFoodName foodName = $foodName")
launchWithLoading {
val response = repository.getRestInfoFoodsByType(foodName = foodName)
if (parseResponse(response)) {
val list = response.data ?: emptyList()
action(list)
_identifiedFoodInfoList.value = response.data ?: emptyList()
}
}
}
fun cleanSearchFoodInfoList() {
Timber.tag(TAG).d("cleanSearchFoodInfoList")
_searchFoodInfoList.value = emptyList<FoodInfo>()
}
// /**
// * 获取用户就餐数据
// */
// fun getUserNutritionData(userId: String, foodId: String) {
// Timber.tag(TAG).d("getUserNutritionData userId = ${userId}, foodId = $foodId")
// _nutritionData.value = null
// launch {
// val response = repository.getUserNutritionData(userId = userId, foodId = foodId)
// if (parseResponse(response)) {
// _nutritionData.value = response.result
// }
// }
// }
/**
* 获取用户就餐数据
*/
fun getUserNutritionData(userId: String, block: (UserNutrition?) -> Unit) {
Timber.tag(TAG).d("getUserNutritionData userId = $userId")
launch {
val response = repository.getUserNutritionData(userId = userId)
if (parseResponse(response)) {
block(response.data)
} else {
block(null)
}
}
}
/**
* 获取支付二维码
*/
fun getQrCodeImg(
orderId: String,
userId: String? = null,
totalFee: String? = null,
block: (String?) -> Unit
) {
Timber.tag(TAG).d("getQrCodeImg orderId = $orderId, userId = $userId")
launch {
val response =
repository.getQrCodeImg(orderNo = orderId, memberId = userId, totalFee = totalFee)
if (parseResponse(response)) {
block(response.data)
} else {
block(null)
}
}
}
fun getDinnerType() {
Timber.tag(TAG).d("getDinnerType")
_dinnerTypeInfo.value = null
launch {
val response = repository.getDinnerType()
if (parseResponse(response)) {
_dinnerTypeInfo.value = response.data
}
}
}
/**
* 提交就餐数据
*/
fun postUserNutritionData(param: List<UserNutritionParam>) {
Timber.tag(TAG).d("postUserNutritionData param = $param")
launch {
val response = repository.postUserNutritionData(param)
if (parseResponse(response)) {
}
}
}
fun getFoodInfo(foodName: String, action: (List<FoodInfo>) -> Unit = {}) {
Timber.tag(TAG).d("getFoodInfo")
launchWithLoading {
val response = repository.getFoodInfo(foodName = foodName)
if (parseResponse(response)) {
val list = response.data ?: emptyList()
_identifiedFoodInfoList.value = list
action(list)
} else {
action(emptyList())
}
}
}
fun createOrder(order: FoodOrder, block: (String) -> Unit) {
Timber.tag(TAG).d("createOrder")
launchWithLoading {
val response = repository.createOrder(order)
if (parseResponse(response)) {
block(response.data.toString())
} else {
block("")
}
}
}
/**
* 现金支付
*/
fun cashPay(param: HashMap<String, String>, block: (Boolean) -> Unit) {
Timber.tag(TAG).d("cashPay")
launchWithLoading {
val response = repository.cashPay(param)
if (parseResponse(response)) {
block(response.data ?: false)
} else {
block(false)
}
}
}
// /**
// * 查询订单状态
// *
// * @param queryType 查询类型 1支付2退款
// * @param orderId 订单号
// */
// fun queryOrderState(queryType:Int, orderId:String, block:(PayResult?)-> Unit) {
// Timber.tag(TAG).d("queryOrderState")
// val param = hashMapOf(
// "queryType" to "$queryType",
// "payOrderNo" to orderId
// )
// launchWithLoading {
// val response = repository.queryOrderState(param)
// if (parseResponse(response)) {
// block(response.data)
// } else {
// block(null)
// }
// }
// }
/**
* 扫码成功回调
*
* @param orderId 订单号
*/
suspend fun queryOrderState(orderId: String, block: (Boolean) -> Unit) {
Timber.tag(TAG).d("queryOrderState")
val response = repository.queryOrderState(orderNo = orderId)
if (parseResponse(response)) {
//val respData = response.data as? String
// ?: if (response.data is Any) {
// GsonUtils.toJson(response.data)
// } else {
// ""
// }
//al payResult = GsonUtils.fromJson(respData, PayResult::class.java)
//val orderState = payResult?.paySuc == "1"
//data=1的话 是支付成功 0是待支付
block(response.data == "1")
} else {
block(false)
}
}
/**
* 会员支付
*/
fun memberPay(param: HashMap<String, String>, block: (Boolean) -> Unit) {
Timber.tag(TAG).d("memberPay")
launchWithLoading {
val response = repository.memberPay(param)
if (parseResponse(response)) {
block(true)
} else {
block(false)
}
}
}
/**
* 绑定订单
*/
fun bindOrder(userId: String, orderId: String, mode: Int, block: (Boolean) -> Unit) {
Timber.tag(TAG).d("bindOrder")
launchWithLoading {
val response = repository.bindOrder(userId = userId, orderId = orderId, mode = mode)
if (parseResponse(response)) {
block(true)
} else {
block(false)
}
}
}
fun getMemberInfoById(memberId: String, block: (MemberInfo?) -> Unit) {
Timber.tag(TAG).d("getMemberInfo")
launchWithLoading {
val response = repository.getMemberInfoById(memberId)
if (parseResponse(response)) {
block(response.data)
} else {
block(null)
}
}
}
fun getMemberInfoByPhone(phone: String, key: String, block: (MemberInfo?) -> Unit) {
Timber.tag(TAG).d("getMemberInfo")
launchWithLoading {
val response = repository.getMemberInfoByPhone(phone, key)
if (parseResponse(response)) {
block(response.data)
} else {
block(null)
}
}
}
// fun uploadCollectFoodPics(files: List<File?>, params: HashMap<String, RequestBody>, callback: (Boolean) -> Unit) {
// Timber.tag(TAG).d("uploadCollectFoodPics")
// launchWithLoading {
// val fileList = files.filterNotNull()
// if (fileList.isEmpty()) {
// callback(false)
// return@launchWithLoading
// }
// val resp = repository.uploadCollectFoodPics(fileList, params)
// if (!parseResponse(resp)) {
// callback(false)
// return@launchWithLoading
// }
// callback(resp.code == "00000")
// }
// }
suspend fun uploadCollectFoodPics(
files: List<File?>,
params: HashMap<String, RequestBody>
): List<String>? {
Timber.tag(TAG).d("uploadCollectFoodPics")
val fileList = files.filterNotNull()
if (fileList.isEmpty()) {
return null
}
val resp = repository.uploadCollectFoodPics(fileList, params)
if (resp.code != "00000") {
return null
}
return resp.data
}
fun getDeviceConfig(block: (DeviceConfig?) -> Unit) {
Timber.tag(TAG).d("getDeviceConfig")
launchWithLoading {
val response = repository.getDeviceConfig()
if (parseResponse(response)) {
block(response.data)
} else {
block(null)
}
}
}
fun getCollectedFoodVector(param: MutableMap<String, String>, block: (List<FoodVector>?) -> Unit) {
Timber.tag(TAG).d("getCollectedFoodVector")
launchWithLoading {
val response = repository.getCollectedFoodVector(param)
if (parseResponse(response)) {
block(response.data)
} else {
block(null)
}
}
}
fun deleteCollectFood(foodId:String?, version: String?, block: (Boolean) -> Unit) {
Timber.tag(TAG).d("deleteCollectFood")
launchWithLoading {
val response = repository.deleteCollectFood(foodId, version)
if (parseResponse(response)) {
block(true)
} else {
block(false)
}
}
}
}