Files
Inbound20260114/app/src/main/java/com/sw/inbound/viewmodel/BaseViewModel.kt
T
2026-02-10 09:36:18 +08:00

377 lines
13 KiB
Kotlin

package com.sw.inbound.viewmodel
import android.net.Uri
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.gson.reflect.TypeToken
import com.sw.inbound.GlobalData
import com.sw.inbound.model.response.ApiResponse
import com.sw.inbound.model.response.DictType
import com.sw.inbound.model.response.EquipmentInfo
import com.sw.inbound.model.response.GoodsInfo
import com.sw.inbound.model.response.SearchGoodsInfo
import com.sw.inbound.network.LoadingState
import com.sw.inbound.objbox.FoodModule
import com.sw.inbound.repository.RemoteRepository
import com.sw.inbound.utils.SPUtil
import com.sw.inbound.utils.ToastUtils
import com.sw.inbound.utils.ext.toType
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import retrofit2.HttpException
import timber.log.Timber
import java.io.IOException
import kotlin.collections.List
import kotlin.math.roundToInt
abstract class BaseViewModel(
private val repository: RemoteRepository
) : ViewModel() {
// 需要拍照
private val _takePhotoState = MutableStateFlow(false)
val takePhotoState: StateFlow<Boolean> = _takePhotoState
// 称重结果
private val _weightInfo = MutableStateFlow<Double>(0.0)
val weightInfo: StateFlow<Double> = _weightInfo
// 搜索物品列表
private val _searchListItems = MutableStateFlow<List<SearchGoodsInfo.Record>>(emptyList())
val searchListItems: StateFlow<List<SearchGoodsInfo.Record>> = _searchListItems
// 识别列表
private val _identityListItems = MutableStateFlow<List<SearchGoodsInfo.Record>>(emptyList())
val identityListItems: StateFlow<List<SearchGoodsInfo.Record>> = _identityListItems
// 待收货的列表 用于识别时从中获取
private val _receiptList = MutableStateFlow<List<SearchGoodsInfo.Record>>(emptyList())
val receiptList: StateFlow<List<SearchGoodsInfo.Record>> = _receiptList
// 拍照uri
private val _lastPhotoUri = MutableStateFlow<Uri?>(null)
val lastPhotoUri: StateFlow<Uri?> = _lastPhotoUri
/**
* 是否可以加载更多
*/
private val _canLoadMore = MutableStateFlow(true)
val canLoadMore: StateFlow<Boolean> = _canLoadMore
/**
* 是否显示进度条
*/
private val _isMoreLoading = MutableStateFlow(false)
val isMoreLoading = _isMoreLoading
/**
* 带进度条的请求
*/
protected fun launchWithLoading(block: suspend () -> Unit) {
viewModelScope.launch {
try {
LoadingState.show()
block()
} catch (e: Exception) {
// 错误处理可被子类重写
handleError(e)
} finally {
delay(500)
LoadingState.hide()
}
}
}
/**
* 不带进度条的请求
*/
protected fun launch(block: suspend () -> Unit) {
viewModelScope.launch() {
try {
block()
} catch (e: Exception) {
// 错误处理可被子类重写
handleError(e)
}
}
}
protected open fun parseResponse(response: ApiResponse<*>): Boolean {
if (response.isSuccess()) {
return true
}
Timber.d("msg = ${response.msg}, code = ${response.code}")
//ToastUtils.showToast("${response.msg}(${response.code})")
return false
}
protected open fun handleError(e: Exception) = {
Timber.e(e)
val message = when (e) {
is IOException -> "网络连接异常"
is HttpException -> "服务器错误: ${e.code()}"
else -> "操作失败: ${e.message}"
}
ToastUtils.showToast(message)
}
// fun startSensorScale() {
// Timber.d("开始称重")
// SensorScaleUtils.startScale(callback = { weight ->
// _weightInfo.value = weight
// handleSensorScale(weight)
// })
// }
//
// fun stopSensorScale() {
// Timber.d("关闭称重")
// SensorScaleUtils.stopContinuousRead()
// }
abstract fun handleSensorScale(weight: Double)
fun updateCanLoadMore(canLoad: Boolean) {
_canLoadMore.value = canLoad
}
fun updateLastPhotoUri(photoUri: Uri?) {
_lastPhotoUri.value = photoUri
}
// fun updateReceiptList(list: List<GoodsInfo>) {
// _receiptList.value = list.map { goods ->
// SearchGoodsInfo.Record(
// goodsId = goods.goodId,
// goodsName = goods.goodName
// )
// }
// }
//
// fun updateIdentityList(list: List<SearchGoodsInfo.Record>) {
// _identityListItems.value = list
// }
/**
* 获取识别列表
*/
// fun getIdentityList(photoUri: Uri) {
// Timber.d("getIdentityList")
// launchWithLoading {
// _searchListItems.value = emptyList<SearchGoodsInfo.Record>()
// // 有收货列表,则返回收货列表
// if (_receiptList.value.isNotEmpty()) {
// _identityListItems.value = _receiptList.value
// if (_identityListItems.value.isNotEmpty()) {
// handleIdentityItem(_identityListItems.value[0])
// }
// } else {
// val response = repository.searchGoodsInfoList("", 1, 10)
// if (parseResponse(response)) {
// _identityListItems.value = response.result?.records ?: emptyList()
// if (_identityListItems.value.isNotEmpty()) {
// handleIdentityItem(_identityListItems.value[0])
// }
// }
// }
// }
// }
/**
* 处理识别后要选中的值
*/
open fun handleIdentityItem(goodsInfo: SearchGoodsInfo.Record) {}
fun updateMoreLoading(moreLoading: Boolean) {
_isMoreLoading.value = moreLoading
}
/**
* 搜索物品
*/
suspend fun searchGoodsInfoList2(
goodsName: String,
pageNo: Int = 1,
pageSize: Int = 10
): List<SearchGoodsInfo.Record> {
val response = repository.searchGoodsInfoList(goodsName, pageNo, pageSize)
return if (parseResponse(response)) {
response.result?.records ?: listOf()
} else {
listOf()
}
}
fun recognizeGoodsList(
nameList: List<String>? = null,
scoreList: List<FoodModule.IdNameScore>? = null,
callback: (List<SearchGoodsInfo.Record>) -> Unit
) {
launch {
if (nameList.isNullOrEmpty() && scoreList.isNullOrEmpty()) return@launch
val paramList = if (nameList.isNullOrEmpty()) scoreList!!.map { it.name } else nameList
val response = repository.recognizeGoodsList(paramList)
val list = if (parseResponse(response)) response.data ?: listOf() else listOf()
if (scoreList.isNullOrEmpty().not()) {
list.forEach { record ->
val item = scoreList.firstOrNull { it.name == record.goodsName }
record.score = ((1 - (item?.score ?: 0.0)) * 10000).roundToInt()
}
}
callback(list)
}
}
// fun searchGoodsInfoList(
// goodsName: String,
// pageNo: Int = 1,
// pageSize: Int = 10,
// searchCallback: ((pageNo: Int, List<SearchGoodsInfo.Record>) -> Unit)? = null
// ) {
// launch {
// if (pageNo > 1) {
// _isMoreLoading.value = true
// }
// _identityListItems.value = emptyList<SearchGoodsInfo.Record>()
// val response = repository.searchGoodsInfoList(goodsName, pageNo, pageSize)
// _isMoreLoading.value = false
// if (parseResponse(response)) {
// val data = response.result
// data?.records?.let {
// _canLoadMore.value = data.records.size >= pageSize
// if (pageNo > 1) {
// _searchListItems.value = _searchListItems.value + data.records
// } else {
// _searchListItems.value = data.records
// }
// searchCallback?.invoke(pageNo, _searchListItems.value)
// }
// } else {
// _searchListItems.value = emptyList<SearchGoodsInfo.Record>()
// searchCallback?.invoke(pageNo, _searchListItems.value)
// }
// }
// }
fun getDictType() {
Timber.d("获取所有字典列表")
launchWithLoading {
val response = repository.getGoodsStorageType()
if (parseResponse(response)) {
Timber.d("getGoodsStorageType data = ${response.result}")
response.result?.let {
val list: MutableList<DictType> = mutableListOf()
response.result
?.filter { it.id.isNullOrBlank().not() && it.title.isNullOrBlank().not() }
?.forEach {
list.add(DictType(id = it.value, value = it.title))
}
GlobalData.storageTypeList = list
}
} else {
Timber.e("getGoodsStorageType msg = ${response.message}, code = ${response.code}")
}
val response1 = repository.getGoodsType()
if (parseResponse(response1)) {
Timber.d("getGoodsType data = ${response1.result?.allType}")
val list = mutableListOf<DictType>()
response1.result
?.allType
?.filter { it?.id.isNullOrBlank().not() && it.typeName.isNullOrBlank().not() }
?.forEach {
list.add(DictType(it!!.id, it.typeName!!))
}
GlobalData.goodsTypeList = list.toList()
} else {
Timber.e("getGoodsType msg = ${response1.message}, code = ${response1.code}")
}
val response2 = repository.getDictType(RemoteRepository.TypeEnum.WAREHOUSE)
if (parseResponse(response2)) {
Timber.d("getDictType WAREHOUSE data = ${response2.result}")
val list: MutableList<DictType> = mutableListOf()
response2.result
?.filter { it.id.isNullOrBlank().not() && it.value.isNullOrBlank().not() }
?.forEach {
list.add(DictType(id = it.id, value = it.value))
}
GlobalData.warehouseTypeList = list.toList()
} else {
Timber.e("getDictType WAREHOUSE msg = ${response2.message}, code = ${response2.code}")
}
val response3 = repository.getDictType(RemoteRepository.TypeEnum.SUPPLIER)
if (parseResponse(response3)) {
Timber.d("getDictType SUPPLIER data = ${response3.result}")
val list: MutableList<DictType> = mutableListOf()
response3.result
?.filter { it.id.isNullOrBlank().not() && it.value.isNullOrBlank().not() }
?.forEach {
list.add(DictType(id = it.id, value = it.value))
}
GlobalData.supplierTypeList = list.toList()
} else {
Timber.e("getDictType SUPPLIER msg = ${response3.message}, code = ${response3.code}")
}
val response4 = repository.getDictType(RemoteRepository.TypeEnum.UNIT)
if (parseResponse(response4)) {
Timber.d("getDictType UNIT data = ${response4.result}")
val list: MutableList<DictType> = mutableListOf()
response4.result
?.filter { it.id.isNullOrBlank().not() && it.value.isNullOrBlank().not() }
?.forEach {
list.add(DictType(id = it.id, value = it.value))
}
GlobalData.unitTypeList = list.toList()
} else {
Timber.e("getDictType UNIT msg = ${response4.message}, code = ${response4.code}")
}
}
}
fun parseEquipmentInfo(equipmentInfo: EquipmentInfo) {
GlobalData.appBaseUrl = equipmentInfo.appPackageUrl!!
GlobalData.sdkKey = equipmentInfo.arcsoftSdkKey!!
GlobalData.appId = equipmentInfo.arcsoftAppId!!
// GlobalData.activeKey = equipmentInfo.arcsoftActiveKey!!
GlobalData.restId = equipmentInfo.canteenId!!
}
val goodsKey = "goods"
fun putGoodsData(key: String, jsonData: String) {
try {
SPUtil.getInstance(spName = goodsKey).put(key, jsonData)
} catch (e: Exception) {
e.printStackTrace()
}
}
fun getGoodsData(key: String):String? {
try {
return SPUtil.getInstance(spName = goodsKey).get<String>(key)
} catch (e: Exception) {
e.printStackTrace()
}
return ""
}
fun getGoodsList(key:String):List<GoodsInfo>? {
try {
val jsonData = getGoodsData(key)
return jsonData?.toType(typeToken=object:TypeToken<List<GoodsInfo>?>(){})
} catch (e: Exception) {
e.printStackTrace()
}
return emptyList()
}
fun deleteKey(key:String) {
try {
SPUtil.getInstance(spName = goodsKey).remove(key)
} catch (e: Exception) {
e.printStackTrace()
}
}
}