594 lines
20 KiB
Kotlin
594 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.Debouncer
|
|
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)
|
|
}
|
|
} else {
|
|
block(emptyList())
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 激活人脸识别引擎
|
|
*/
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
} |