营养接口调试、支付接口联调

This commit is contained in:
2025-12-08 18:06:48 +08:00
parent 04e318f47b
commit 086845dd16
27 changed files with 491 additions and 237 deletions
@@ -87,6 +87,12 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
checkedItem = item
notifyDataSetChanged()
updateCurrentFood(item)
val mode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0)
//不计费模式切换菜品,重新加载数据
if(mode == 1) {
presentation?.loadUnbilledMode()
}
}
}
}
@@ -222,8 +228,19 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
return@setOnClickListener
}
val realWeight = (lastWeight * 1000).roundToInt()
createOrder(foodInfo = checkedItem!!, foodWeight = realWeight, eatWeight = realWeight) {
//val realWeight = (lastWeight * 1000).roundToInt()
val mealPickupMode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0) ?: 0
val eatWeight = if (mealPickupMode == 0) {
//即放即取
presentation?.recognitionWeight?:0.0
} else {
presentation?.recognitionWeight?.minus(lastWeight)?:0.0
}
createOrder(
foodInfo = checkedItem!!,
foodWeight = presentation?.lastWeight?.roundToInt()?:0,
eatWeight = eatWeight.roundToInt()
) {
presentation?.dismiss()
startActivity(Intent(this, PayActivity::class.java).apply {
putExtra(PayActivity.FOOD_INFO, checkedItem!!)
@@ -684,7 +701,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
viewModel.createOrder(order) { orderId ->
runOnUiThread {
if (orderId.isBlank()) {
ToastUtils.showToast("订单id为空")
//ToastUtils.showToast("订单id为空")
return@runOnUiThread
}
foodOrderId = orderId
@@ -9,6 +9,7 @@ import com.sw.dualscreen.activity.fragment.pay.NumberPayFragment
import com.sw.dualscreen.activity.fragment.pay.PayResultFragment
import com.sw.dualscreen.activity.fragment.pay.ScanQrCodePayFragment
import com.sw.dualscreen.databinding.ActivityPayBinding
import com.sw.dualscreen.ext.gone
import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.model.response.MemberInfo
import com.sw.dualscreen.presentation.pay.ScanQrCodePayPresentation
@@ -60,6 +61,7 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
super.initialize()
foodInfo = intent.getParcelableExtra(FOOD_INFO)
foodOrderId = intent.getStringExtra(FOOD_ORDER_ID) ?: ""
// totalAmount = intent.getDoubleExtra(TOTAL_AMOUNT,0.0)
// memberInfo = intent.getParcelableExtra(MEMBER_INFO)
binding.tvFoodName.text = foodInfo?.foodName
@@ -160,6 +162,7 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
cashPayFragment?.presentation?.dismiss()
numberPayFragment?.presentation?.dismiss()
facePayFragment?.presentation?.dismiss()
scanQrCodePayPresentation?.dismiss()
super.onDestroy()
}
@@ -188,6 +191,7 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
fun showPaySuccess(isVip: Boolean) {
showPayInfo(type = 2, isVip = isVip, memberInfo = memberInfo)
hidePayTab()
}
fun getQrCodeImg(orderId: String, userId: String? = null, block: (String?) -> Unit) {
@@ -218,11 +222,31 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
}
}
fun paySuccessCallback(isVip: Boolean, block: () -> Unit = {}) {
userViewModel.paySuccessCallback(queryType = 1, orderId = foodOrderId) {
suspend fun queryOrderState(isVip: Boolean, block: (Boolean) -> Unit) {
userViewModel.queryOrderState(orderId = foodOrderId) { payResult ->
runOnUiThread {
if (payResult) {
showPaySuccess(isVip)
block()
block(true)
} else {
block(false)
}
}
}
}
fun hidePayTab() {
binding.llPayTab.gone()
}
// private val intervalExecutor by lazy { IntervalExecutor() }
// private var payTaskJob: Job? = null
// fun paySuccessCallback() {
// payTaskJob = intervalExecutor.startIntervalTaskWithInitialDelay(5000, 10000) {
//
// }
// }
}
@@ -12,7 +12,9 @@ import com.sw.dualscreen.ext.load
import com.sw.dualscreen.ext.visible
import com.sw.dualscreen.model.response.MemberInfo
import com.sw.dualscreen.model.response.TextBean
import com.sw.dualscreen.utils.IntervalExecutor
import com.sw.dualscreen.utils.SpannedUtils
import kotlinx.coroutines.Job
class PayResultFragment : BaseFragment<FragmentPayResultBinding>() {
@@ -44,13 +46,7 @@ class PayResultFragment : BaseFragment<FragmentPayResultBinding>() {
override fun initialize() {
payActivity = activity as PayActivity
binding.btnBack.setOnClickListener {
//payActivity?.showFacePay()
}
if (memberInfo != null) {
binding.layoutMemberInfo.visible()
} else {
binding.layoutMemberInfo.gone()
activity?.finish()
}
arguments?.let {
pageType = it.getInt(PAGE_TYPE, 0)
@@ -58,11 +54,14 @@ class PayResultFragment : BaseFragment<FragmentPayResultBinding>() {
}
totalPrice = payActivity?.foodInfo?.vipPrice ?: 0.0
memberInfo?.let {
balance = (memberInfo?.topUpBalance ?: 0.0) + (memberInfo?.rewardBalance ?: 0.0)
if (memberInfo != null) {
binding.layoutMemberInfo.visible()
balance = (memberInfo!!.topUpBalance ?: 0.0) + (memberInfo!!.rewardBalance ?: 0.0)
realPayPrice = if (balance >= totalPrice) 0.0 else totalPrice - balance
expensesBalance = if (balance >= totalPrice) totalPrice else balance
loadUserInfo(it)
loadUserInfo(memberInfo!!)
} else {
binding.layoutMemberInfo.gone()
}
when (pageType) {
@@ -112,7 +111,7 @@ class PayResultFragment : BaseFragment<FragmentPayResultBinding>() {
) { qrCodeImg ->
binding.ivPayQrCode.load(qrCodeImg)
//扫码成功回调打开成功页面
payActivity?.paySuccessCallback(true)
paySuccessCallback(true)
}
}
}
@@ -208,4 +207,21 @@ class PayResultFragment : BaseFragment<FragmentPayResultBinding>() {
}
}
override fun onDestroy() {
payTaskJob?.cancel()
super.onDestroy()
}
private val intervalExecutor by lazy { IntervalExecutor() }
private var payTaskJob: Job? = null
fun paySuccessCallback(isVip: Boolean) {
payTaskJob = intervalExecutor.startIntervalTaskWithInitialDelay(5000, 10000) {
payActivity?.queryOrderState(isVip) { paySuccess ->
if (paySuccess) {
payTaskJob?.cancel()
}
}
}
}
}
@@ -14,6 +14,7 @@ import com.sw.dualscreen.utils.countDownByFlow
import kotlinx.coroutines.Job
import com.sw.dualscreen.databinding.FragmentScanQrcodePayBinding
import com.sw.dualscreen.ext.format2String
import com.sw.dualscreen.utils.IntervalExecutor
class ScanQrCodePayFragment: BaseFragment<FragmentScanQrcodePayBinding>() {
@@ -44,7 +45,7 @@ class ScanQrCodePayFragment: BaseFragment<FragmentScanQrcodePayBinding>() {
binding.ivPayQrCode.load(payQrCodePic)
binding.tvPayResult.text = "待支付(60s)..."
payActivity.paySuccessCallback(false)
paySuccessCallback(false)
showSubScreen()
@@ -64,6 +65,7 @@ class ScanQrCodePayFragment: BaseFragment<FragmentScanQrcodePayBinding>() {
override fun onDestroy() {
delayDismiss()
countDownJob?.cancel() // 自动取消订阅,防止内存泄漏
payTaskJob?.cancel()
super.onDestroy()
}
@@ -110,4 +112,16 @@ class ScanQrCodePayFragment: BaseFragment<FragmentScanQrcodePayBinding>() {
)
}
private val intervalExecutor by lazy { IntervalExecutor() }
private var payTaskJob: Job? = null
fun paySuccessCallback(isVip: Boolean) {
payTaskJob = intervalExecutor.startIntervalTaskWithInitialDelay(5000, 10000) {
payActivity.queryOrderState(isVip) { paySuccess ->
if (paySuccess) {
payTaskJob?.cancel()
}
}
}
}
}
@@ -58,7 +58,7 @@ data class UserNutrition(
//姓名
val name: String?,
//推荐能量
val recommendEnergy: Double?,
// val recommendEnergy: Double?,
//热量
val calorie: Double?,
//果蔬
@@ -67,8 +67,39 @@ data class UserNutrition(
val meatEggs: Double?,
//主食
val stapleFood: Double?,
//能量最大值
val maxCalorie: Double? = null,
//能量最小值
val minCalorie: Double? = null,
//推荐能量
val recommendCalorie: Double? = null,
//主食推荐值
val stapleFoodRecommend: String?=null,
//主食即将超量
val stapleFoodNearExcess: String?=null,
//主食超量
val stapleFoodExcess: String?=null,
//果蔬推荐值
val fruitsVegetablesRecommend: String?=null,
//果蔬即将超量
val fruitsVegetablesNearExcess: String?=null,
//果蔬超量
val fruitsVegetablesExcess: String?=null,
//肉蛋推荐值
val meatEggsRecommend: String?=null,
//肉蛋即将超量
val meatEggsNearExcess: String?=null,
//肉蛋超量
val meatEggsExcess: String?=null,
)
data class PayResult(
val paySuc: String? = null
)
data class UserEnergy(
var calorie:Double,
var grain:Double,
var fruitsVegetables:Double,
var meatEggs:Double,
)
@@ -39,6 +39,8 @@ data class FoodInfo(
val fruitsVegetables:Double? = null,
//肉蛋
val meatEggs:Double? = null,
//推荐能量
val recommendCalorie: Double? = null,
//-----------------------------------
var score: Int = 0,
@@ -123,17 +123,6 @@ interface ApiService {
@Query("id") userId: String
): ApiResponse<UserNutrition>
/**
* 获取支付二维码
*/
@GET
suspend fun getQrCodeImg(
@Url url: String = "${GlobalData.appBaseUrl}/pay/yx-check-out-pay/getQrCodeImg",
@Query("orderNo") orderNo: String,
@Query("memberId") memberId: String?,
@Query("totalFee") totalFee: String?
): ApiResponse<String?>
/**
* 获取当前餐点类型
*/
@@ -166,21 +155,30 @@ interface ApiService {
@Body req: FoodSearchReq
): ApiResponse<List<FoodInfo>>
// /**
// * 查询支付结果
// */
// @POST
// suspend fun queryOrderState(
// @Url url: String = "${GlobalData.appBaseUrl}/pay/yx-check-out-pay/turnOrderInfo",
// @Body param: HashMap<String, String>
// ): ApiResponse<PayResult?>
/**
* 查询支付结果
*/
@POST
suspend fun queryOrderState(
@Url url: String = "${GlobalData.appBaseUrl}/pay/yx-check-out-pay/turnOrderInfo",
@Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/pay/app/turnOrderInfo",
// @Query("orderNo") orderNo: String
@Body param: HashMap<String, String>
): ApiResponse<PayResult?>
): ApiResponse<Any?>
/**
* 现金支付
*/
@POST
suspend fun cashPay(
@Url url: String = "${GlobalData.appBaseUrl}/pay/yx-check-out-pay/cashPayment",
@Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/pay/app/cashPayment",
@Body param: HashMap<String, String>
): ApiResponse<Boolean?>
@@ -189,10 +187,21 @@ interface ApiService {
*/
@POST
suspend fun memberPay(
@Url url: String = "${GlobalData.appBaseUrl}/pay/yx-check-out-pay/memberPay",
@Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/pay/app/memberPay",
@Body param: HashMap<String, String>
): ApiResponse<Any?>
/**
* 获取支付二维码
*/
@GET
suspend fun getQrCodeImg(
@Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/pay/app/getQrCodeImg",
@Query("orderNo") orderNo: String,
@Query("memberId") memberId: String?,
@Query("totalFee") totalFee: String?
): ApiResponse<String?>
/**
* 开餐-生成订单
*/
@@ -218,7 +227,7 @@ interface ApiService {
suspend fun bindOrder(
@Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/boothMachine/app/bingOrder",
@Query("userId") userId: String,
@Query("orderId") orderId: String
@Query("orderNo") orderId: String
): ApiResponse<Any?>
@@ -34,6 +34,7 @@ import com.sw.dualscreen.ext.visible
import com.sw.dualscreen.model.request.UserNutritionParam
import com.sw.dualscreen.model.response.DinnerType
import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.model.response.UserEnergy
import com.sw.dualscreen.model.response.UserNutrition
import com.sw.dualscreen.model.response.UserNutritionData
import com.sw.dualscreen.utils.Debouncer
@@ -91,14 +92,14 @@ class MainScreenPresentation(
private var irFaceRectTransformer: FaceRectTransformer? = null
private var detectWeight = 0.0 //识别菜品时的重量
private var lastWeight = 0.0 // 上一次的计算热量结果
var lastWeight = 0.0 // 上一次的计算热量结果
// private var userNutritionData: UserNutritionData? = null
private var userNutrition: UserNutrition? = null
private var dinnerTypeInfo: DinnerType? = null
private val debouncer = Debouncer(500)
private var recognitionTime: Long = 0L // 人脸识别时的时间
private var recognitionWeight: Double = 0.0 // 人脸识别时的重量
var recognitionWeight: Double = 0.0 // 人脸识别时的重量
private var lastFaceTrackId: Int = -1 // 上一次的人脸信息
var mealPickupMode: Int = 0 // 取餐模式 0 即放即取 1 余量取餐
@@ -342,7 +343,7 @@ class MainScreenPresentation(
/**
* 餐品识别成功,不计费模式
*/
fun loadUnbilledMode(nutrition: UserNutrition) {
fun loadUnbilledMode() {
binding.calorieInclude.root.gone()
binding.nutritionInclude.root.visible()
@@ -354,9 +355,9 @@ class MainScreenPresentation(
//binding.ivRecImage.gone()
//updateFoodInfo(foodInfo)
binding.nutritionInclude.tvUserName.text = nutrition.name.maskName()
binding.nutritionInclude.tvUserName.text = userNutrition?.name.maskName()
binding.nutritionInclude.tvRecommendHeat.text =
"推荐热量:${nutrition.recommendEnergy ?: 0}kcal"
"推荐热量:${userNutrition?.recommendCalorie.format2String(2)}kcal"
//updateWeight(lastWeight / 1000)
// -------------------------------------------------
// 删除userNutritionData,改为userNutrition
@@ -524,100 +525,107 @@ class MainScreenPresentation(
val dinnerType = dinnerTypeInfo!!.dinnerType!!
// Timber.tag(TAG)
// .d("calculateNutrition foodName = ${currentFood!!.foodName}, dinnerType = $dinnerType, userId = ${userNutritionData!!.userId}")
val calcResultInfo = UserNutritionUtils.calculateNutrition2(
val energy: UserEnergy = UserNutritionUtils.calculateNutrition2(
currentFood!!,
// userNutritionData!!,
userNutrition!!,
weight,
dinnerType = dinnerType
)
Timber.tag(TAG).d("calculateNutrition calcResultInfo = $calcResultInfo")
val columnMax = UserNutritionUtils.getMaxInt(calcResultInfo)
// Timber.tag(TAG).d("calculateNutrition calcResultInfo = $calcResultInfo")
// val columnMax = UserNutritionUtils.getMaxInt(calcResultInfo)
var columnMax = max(energy.grain, energy.fruitsVegetables)
columnMax = max(columnMax, energy.meatEggs)
activity.runOnUiThread {
val totalKcal = calcResultInfo.totalKcal
val grain = calcResultInfo.grain
val fruits = calcResultInfo.fruits
val meat = calcResultInfo.meat
// 设置热量
binding.nutritionInclude.customKcalColumn.setImageDrawable(
true,
totalKcal.max < totalKcal.current
val totalKcal = energy.calorie
val grain = energy.grain
val fruitsVegetables = energy.fruitsVegetables
val meatEggs = energy.meatEggs
val include = binding.nutritionInclude
// 设置热量---------------------------------------------------------------------
val calorieArray = doubleArrayOf(
0.0,
userNutrition?.minCalorie?:0.0,
userNutrition?.recommendCalorie?:0.0,
((userNutrition?.recommendCalorie?:0.0) + (userNutrition?.maxCalorie?:0.0))/2,
userNutrition?.maxCalorie?:0.0,
)
var maxKcal = totalKcal.max
val calorieIndex = UserNutritionUtils.findCalorieIndex(energy.grain, calorieArray)
include.customKcalColumn.setImageDrawable(true, calorieIndex)
var maxKcal = userNutrition?.maxCalorie?:1.0
Timber.tag(TAG).d("maxKcal = $maxKcal")
// 避免0作为被除数
if (maxKcal <= 0.0) {
maxKcal = 1.0
}
Timber.tag(TAG).d("maxKcal 1 = $maxKcal")
binding.nutritionInclude.totalKcalTv.text = totalKcal.current.format2String()
var totalKcalHeight = (totalKcal.current / maxKcal).toFloat()
include.totalKcalTv.text = totalKcal.format2String(2)
var totalKcalHeight = (totalKcal / maxKcal).toFloat()
if (totalKcalHeight == 0F) {
binding.nutritionInclude.divKcalView.visibility = View.VISIBLE
include.divKcalView.visibility = View.VISIBLE
} else {
binding.nutritionInclude.divKcalView.visibility = View.GONE
include.divKcalView.visibility = View.GONE
totalKcalHeight += 0.1F
}
binding.nutritionInclude.customKcalColumn.setCustomHeightPercent(
totalKcalHeight,
true
)
include.customKcalColumn.setCustomHeightPercent(totalKcalHeight, true)
// 设置主食
binding.nutritionInclude.customFoodColumn.setImageDrawable(
false,
grain.max < grain.current
// 设置主食-----------------------------------------------------------
val grainArray = UserNutritionUtils.getCalorieArray(
left = userNutrition?.stapleFoodRecommend,
mid = userNutrition?.stapleFoodNearExcess,
right = userNutrition?.stapleFoodExcess
)
binding.nutritionInclude.totalFoodTv.text = grain.current.format2String()
var grainHeight = (grain.current / columnMax).toFloat()
val grainIndex = UserNutritionUtils.findCalorieIndex(energy.grain, grainArray)
include.customFoodColumn.setImageDrawable(false, grainIndex)
include.totalFoodTv.text = grain.format2String(2)
var grainHeight = (grain / columnMax).toFloat()
if (grainHeight == 0F) {
binding.nutritionInclude.divTotalFoodView.visibility = View.VISIBLE
include.divTotalFoodView.visibility = View.VISIBLE
} else {
binding.nutritionInclude.divTotalFoodView.visibility = View.GONE
include.divTotalFoodView.visibility = View.GONE
grainHeight += 0.1F
}
binding.nutritionInclude.customFoodColumn.setCustomHeightPercent(
grainHeight,
true
)
include.customFoodColumn.setCustomHeightPercent(grainHeight, true)
// 设置果蔬
binding.nutritionInclude.customVegetableColumn.setImageDrawable(
false,
fruits.max < fruits.current
// 设置果蔬-------------------------------------------------------------
val fruitsArray = UserNutritionUtils.getCalorieArray(
left = userNutrition?.fruitsVegetablesRecommend,
mid = userNutrition?.fruitsVegetablesNearExcess,
right = userNutrition?.fruitsVegetablesExcess
)
binding.nutritionInclude.totalVegetableTv.text = fruits.current.format2String()
var fruitsHeight = (fruits.current / columnMax).toFloat()
val fruitsIndex = UserNutritionUtils.findCalorieIndex(energy.fruitsVegetables, fruitsArray)
include.customVegetableColumn.setImageDrawable(false, fruitsIndex)
include.totalVegetableTv.text = fruitsVegetables.format2String(2)
var fruitsHeight = (fruitsVegetables / columnMax).toFloat()
if (fruitsHeight == 0F) {
binding.nutritionInclude.divVegetableView.visibility = View.VISIBLE
include.divVegetableView.visibility = View.VISIBLE
} else {
binding.nutritionInclude.divVegetableView.visibility = View.GONE
include.divVegetableView.visibility = View.GONE
fruitsHeight += 0.1F
}
binding.nutritionInclude.customVegetableColumn.setCustomHeightPercent(
fruitsHeight,
true
)
include.customVegetableColumn.setCustomHeightPercent(fruitsHeight, true)
// 设置肉蛋
binding.nutritionInclude.customMeatColumn.setImageDrawable(
false,
meat.max < meat.current
// 设置肉蛋-----------------------------------------------------------
val meatEggsArray = UserNutritionUtils.getCalorieArray(
left = userNutrition?.meatEggsRecommend,
mid = userNutrition?.meatEggsNearExcess,
right = userNutrition?.meatEggsExcess
)
binding.nutritionInclude.totalMeatTv.text = meat.current.format2String()
var meatHeight = (meat.current / columnMax).toFloat()
val meatEggsIndex = UserNutritionUtils.findCalorieIndex(energy.meatEggs, meatEggsArray)
include.customMeatColumn.setImageDrawable(false, meatEggsIndex)
include.totalMeatTv.text = meatEggs.format2String(2)
var meatHeight = (meatEggs / columnMax).toFloat()
if (meatHeight == 0F) {
binding.nutritionInclude.divMeatView.visibility = View.VISIBLE
include.divMeatView.visibility = View.VISIBLE
} else {
binding.nutritionInclude.divMeatView.visibility = View.GONE
include.divMeatView.visibility = View.GONE
meatHeight += 0.1F
}
binding.nutritionInclude.customMeatColumn.setCustomHeightPercent(
meatHeight,
true
)
include.customMeatColumn.setCustomHeightPercent(meatHeight, true)
}
}
}
@@ -718,7 +726,7 @@ class MainScreenPresentation(
val faceEntity = compareResult.faceEntity
val userId = faceEntity.userName
if (userId == null) return@Observer
ToastUtils.showToast("人脸识别成功,userId = $userId")
//ToastUtils.showToast("人脸识别成功,userId = $userId")
if (currentFood == null) {
currentFood = activity.checkedItem
}
@@ -737,7 +745,7 @@ class MainScreenPresentation(
return@runOnUiThread
}
this@MainScreenPresentation.userNutrition = nutrition
loadUnbilledMode(nutrition)
loadUnbilledMode()
// -------------------------------
}
}
@@ -1058,10 +1066,14 @@ class MainScreenPresentation(
.d("postUserData userNutritionData = ${userNutrition == null}, currentFood = ${currentFood == null}")
return
}
var eatWeight = 0.0
eatWeight = if (mealPickupMode == 0) {
createOrder()
}
fun createOrder() {
mealPickupMode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0) ?: 0
val eatWeight = if (mealPickupMode == 0) {
//即放即取
recognitionWeight - 0
recognitionWeight
} else {
recognitionWeight - lastWeight
}
@@ -1084,4 +1096,5 @@ class MainScreenPresentation(
}
}
}
}
@@ -4,6 +4,7 @@ package com.sw.dualscreen.presentation
import android.text.TextUtils
import com.sw.dualscreen.ext.toSafeDouble
import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.model.response.UserEnergy
import com.sw.dualscreen.model.response.UserNutrition
import com.sw.dualscreen.model.response.UserNutritionData
import timber.log.Timber
@@ -22,7 +23,7 @@ object UserNutritionUtils {
nutrition: UserNutrition,
weight: Double,
dinnerType: String
): CalcResultInfo {
): UserEnergy {
// 初始化变量
var totalKcal = 0.0
var (calorie, grain, fruitsVegetables, meatEggs) = List(4) { 0.0 }
@@ -34,6 +35,7 @@ object UserNutritionUtils {
meatEggs = calculateValue(foodInfo.meatEggs, weight)
// 合并用户数据
//val maxKcal = (nutrition.calorie?:0.0) * calculateDinnerTypeRatio(dinnerType) / 10.0
calorie += nutrition.calorie ?: 0.0
grain += nutrition.stapleFood ?: 0.0
fruitsVegetables += nutrition.fruitsVegetables ?: 0.0
@@ -43,24 +45,22 @@ object UserNutritionUtils {
// 判断当餐最大热量
//val maxKcal = userModel.totalEnergyCalculateScoreValue() * calculateDinnerTypeRatio(dinnerType) / 10
//Timber.d("calculateNutrition maxKcal = ${maxKcal}, CalculateScoreValue = ${userModel.totalEnergyCalculateScoreValue()}")
// TODO: 测试数据-------------------------------
val rate = calculateDinnerTypeRatio(dinnerType) / 10.0
val maxKcal = totalKcal/ 0.26 / rate
val grainRecommend = "0-100"
val meatRecommend = "0-100"
val fruitsRecommend = "0-100"
// TODO: 测试数据-------------------------------
val calcResult = CalcResultInfo(
totalKcal = CalcInfo(
max = maxKcal,
min = 0.0,
current = totalKcal
),
grain = parseRecommend(grainRecommend, grain),
fruits = parseRecommend(fruitsRecommend, fruitsVegetables),
meat = parseRecommend(meatRecommend, meatEggs)
// val calcResult = CalcResultInfo(
// totalKcal = CalcInfo(
// max = maxKcal,
// min = 0.0,
// current = totalKcal
// ),
// grain = parseRecommend(foodInfo.stapleFoodRecommend, grain),
// fruits = parseRecommend(foodInfo.fruitsVegetablesRecommend, fruitsVegetables),
// meat = parseRecommend(foodInfo.meatEggsRecommend, meatEggs)
// )
return UserEnergy(
calorie = totalKcal,
grain = grain,
fruitsVegetables = fruitsVegetables,
meatEggs = meatEggs
)
return calcResult
}
// fun calculateNutrition(
@@ -121,7 +121,7 @@ object UserNutritionUtils {
// }
fun parseRecommend(recommend: String?, current: Double): CalcInfo {
var newCurrent = if (current < 0) 0.0 else current
val newCurrent = if (current < 0) 0.0 else current
if (TextUtils.isEmpty(recommend) || !recommend!!.contains("-")) {
Timber.e("parseRecommend recommend 格式错误")
return CalcInfo(
@@ -154,6 +154,36 @@ object UserNutritionUtils {
return max(max1, calcResultInfo.meat.max).toInt()
}
fun getCalorieArray(left:String?, mid:String?, right: String?):DoubleArray {
val leftArray = (left?.ifBlank { "0-0" } ?: "0-0").split("-").map { it.toSafeDouble() }
val midArray = (mid?.ifBlank { "0-0" } ?: "0-0").split("-").map { it.toSafeDouble() }
val rightArray = (right?.ifBlank { "0-0" } ?: "0-0").split("-").map { it.toSafeDouble() }
return doubleArrayOf(
0.0, leftArray[0], midArray[0], rightArray[0], rightArray[1]
)
}
fun findCalorieIndex(num: Double, array: DoubleArray): Int {
if (array.isEmpty()) return 0
if (num < array[0]) return 0
if (num >= array[array.lastIndex]) return array.lastIndex
var left = 0
var right = array.lastIndex
while (left < right) {
val mid = left + (right - left) / 2
if (array[mid] <= num && num < array[mid + 1]) {
return mid
} else if (num < array[mid]) {
right = mid
} else {
left = mid + 1
}
}
return 0
}
data class CalcInfo(
var max: Double,
var min: Double,
@@ -248,8 +248,10 @@ class FacePayPresentation(
// recognitionWeight = lastWeight
lastFaceTrackId = compareResult.trackId
val faceEntity = compareResult.faceEntity
val userId = faceEntity.userName
var userId = faceEntity.userName
if (userId == null) return@Observer
// TODO: 测试支付用户id
userId = "1987710988425662466"
faceRecSuccess(userId)
})
@@ -601,6 +603,7 @@ class FacePayPresentation(
binding.root.postDelayed({
hideWaitingDialog()
activity.showPayInfo(type = 1, isVip = true, memberInfo = memberInfo)
activity.hidePayTab()
binding.root.postDelayed({
dismiss()
}, 500)
@@ -207,10 +207,15 @@ class RemoteRepository constructor(
/**
* 查询订单状态
* @param orderNo 订单好
* @param queryType 查询类型 1支付2退款
*/
suspend fun queryOrderState(param: HashMap<String, String>): ApiResponse<PayResult?> {
suspend fun queryOrderState(orderNo: String, queryType: Int = 1): ApiResponse<Any?> {
return safeApiCall {
apiService.queryOrderState(param = param)
apiService.queryOrderState(param = hashMapOf(
"payOrderNo" to orderNo,
"queryType" to "$queryType"
))
}
}
@@ -0,0 +1,64 @@
package com.sw.dualscreen.utils
import kotlinx.coroutines.*
class IntervalExecutor {
/**
* 启动定时任务
* @param delayMillis 延迟时间(毫秒)
* @param action 要执行的方法
* @return Job 可用于取消任务
*/
fun startIntervalTask(delayMillis: Long, action: suspend () -> Unit): Job {
return CoroutineScope(Dispatchers.Default).launch {
while (isActive) {
action()
delay(delayMillis)
}
}
}
/**
* 启动定时任务(带初始延迟)
* @param initialDelay 初始延迟时间(毫秒)
* @param delayMillis 后续执行间隔(毫秒)
* @param action 要执行的方法
* @return Job 可用于取消任务
*/
fun startIntervalTaskWithInitialDelay(
initialDelay: Long,
delayMillis: Long,
action: suspend () -> Unit
): Job {
return CoroutineScope(Dispatchers.Default).launch {
delay(initialDelay)
while (isActive) {
action()
delay(delayMillis)
}
}
}
}
// 使用示例
fun main() = runBlocking {
val executor = IntervalExecutor()
// 示例1:每隔10秒执行一次
val job1 = executor.startIntervalTask(10000) {
println("定时任务执行: ${System.currentTimeMillis()}")
// 这里可以执行你的业务逻辑
}
// 示例2:先延迟5秒,然后每隔3秒执行一次
val job2 = executor.startIntervalTaskWithInitialDelay(5000, 3000) {
println("带初始延迟的定时任务: ${System.currentTimeMillis()}")
}
// 运行30秒后取消任务
delay(30000)
job1.cancel()
job2.cancel()
println("所有定时任务已取消")
}
@@ -13,6 +13,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import androidx.appcompat.content.res.AppCompatResources;
import com.sw.dualscreen.R;
import com.sw.plate.utils.AppUtil;
@@ -33,10 +35,10 @@ public class CustomImageView extends androidx.appcompat.widget.AppCompatImageVie
private static final int MAX_HEIGHT = 250;
private boolean isDrawText = false;
private Drawable bigRedDrawable;
private Drawable bigGreenDrawable;
private Drawable redDrawable;
private Drawable greenDrawable;
// private Drawable bigRedDrawable;
// private Drawable bigGreenDrawable;
// private Drawable redDrawable;
// private Drawable greenDrawable;
public CustomImageView(Context context) {
super(context);
@@ -60,10 +62,10 @@ public class CustomImageView extends androidx.appcompat.widget.AppCompatImageVie
mPaint.setColor(Color.WHITE); // Set your desired color
mPaint.setTextSize(mTextSize); // Set your desired text size
mPaint.setAntiAlias(true);
bigRedDrawable = context.getDrawable(R.drawable.img_big_red_column);
bigGreenDrawable = context.getDrawable(R.drawable.img_big_green_column);
redDrawable = context.getDrawable(R.drawable.img_red_column);
greenDrawable = context.getDrawable(R.drawable.img_green_column);
// bigRedDrawable = context.getDrawable(R.drawable.img_big_red_column);
// bigGreenDrawable = context.getDrawable(R.drawable.img_big_green_column);
// redDrawable = context.getDrawable(R.drawable.img_red_column);
// greenDrawable = context.getDrawable(R.drawable.img_green_column);
// Typeface typeface = getResources().getFont(R.font.dakai);
// Typeface typeface = Typeface.create(Typeface.createFromAsset(getContext().getAssets(), "fonts/dakai.TTF"),
// Typeface.BOLD); // 创建Typeface
@@ -87,31 +89,31 @@ public class CustomImageView extends androidx.appcompat.widget.AppCompatImageVie
}
}
/**
* 设置图片
*
* @param isBig 大图
* @param isMore 是否超过
*/
public void setImageDrawable(boolean isBig, boolean isMore) {
if (isBig) {
setImageDrawable(isMore ? bigRedDrawable : bigGreenDrawable);
} else {
setImageDrawable(isMore ? redDrawable : greenDrawable);
}
}
public void setImageDrawable2(boolean isBig, Boolean isRed) {
if (isBig) {
setImageDrawable(isRed ? bigRedDrawable : bigGreenDrawable);
} else {
setImageDrawable(isRed ? redDrawable : greenDrawable);
}
}
// /**
// * 设置图片
// *
// * @param isBig 大图
// * @param isMore 是否超过
// */
// public void setImageDrawable(boolean isBig, boolean isMore) {
// if (isBig) {
// setImageDrawable(isMore ? bigRedDrawable : bigGreenDrawable);
// } else {
// setImageDrawable(isMore ? redDrawable : greenDrawable);
// }
// }
//
// public void setImageDrawable2(boolean isBig, Boolean isRed) {
// if (isBig) {
// setImageDrawable(isRed ? bigRedDrawable : bigGreenDrawable);
// } else {
// setImageDrawable(isRed ? redDrawable : greenDrawable);
// }
// }
public void setCustomHeightPercent(float percent, boolean isAnimation) {
Timber.d("setCustomHeightPercent percent = %s", percent);
if (percent<= 0){
if (percent <= 0) {
percent = 0f;
}
setCustomHeight((int) (percent * MAX_HEIGHT), false);
@@ -122,7 +124,7 @@ public class CustomImageView extends androidx.appcompat.widget.AppCompatImageVie
Timber.d("setCustomHeight height = %s", height);
setVisibility(height == 0 ? View.GONE : VISIBLE);
if (height > MAX_HEIGHT){
if (height > MAX_HEIGHT) {
height = MAX_HEIGHT;
}
ViewGroup.LayoutParams layoutParams = getLayoutParams();
@@ -184,4 +186,35 @@ public class CustomImageView extends androidx.appcompat.widget.AppCompatImageVie
float scale = getResources().getDisplayMetrics().density;
return (int) (dp * scale + 0.5f);
}
public void setImageDrawable(boolean isBigImage, int index) {
int myIndex = index;
if (index < 0) {
myIndex = 0;
}else if (index > 5) {
myIndex = 5;
}
if (isBigImage) {
//使用大图bigImgArr
setImageDrawable(AppCompatResources.getDrawable(getContext(), bigImgArr[myIndex]));
return;
}
//使用小图smallImgArr
setImageDrawable(AppCompatResources.getDrawable(getContext(), smallImgArr[myIndex]));
}
private static final Integer[] bigImgArr = new Integer[]{
R.drawable.ic_gray_big,
R.drawable.ic_green_big,
R.drawable.ic_yellow_big,
R.drawable.ic_orange_big,
R.drawable.ic_red_big
};
private static final Integer[] smallImgArr = new Integer[]{
R.drawable.ic_gray_small,
R.drawable.ic_green_small,
R.drawable.ic_yellow_small,
R.drawable.ic_orange_small,
R.drawable.ic_red_small
};
}
@@ -155,7 +155,11 @@ class UserViewModel : BaseViewModel() {
) {
Timber.tag(TAG).d("getCollectedFoodList index = $pageNo")
launch {
val response = repository.getCollectedFoodList(pageNum = pageNo, pageSize = pageSize, foodName = foodName)
val response = repository.getCollectedFoodList(
pageNum = pageNo,
pageSize = pageSize,
foodName = foodName
)
if (parseResponse(response)) {
withContext(Dispatchers.Default) {
val list: List<CollectedFoodInfo> = response.data ?: emptyList()
@@ -269,9 +273,9 @@ class UserViewModel : BaseViewModel() {
}
/**
* 获取用户就餐数据
* 获取支付二维码
*/
fun getQrCodeImg(orderId: String, userId: String?=null, block: (String?) -> Unit) {
fun getQrCodeImg(orderId: String, userId: String? = null, block: (String?) -> Unit) {
Timber.tag(TAG).d("getQrCodeImg orderId = $orderId, userId = $userId")
launch {
val response = repository.getQrCodeImg(orderNo = orderId, memberId = userId)
@@ -321,7 +325,7 @@ class UserViewModel : BaseViewModel() {
}
}
fun createOrder(order: FoodOrder, block:(String)-> Unit) {
fun createOrder(order: FoodOrder, block: (String) -> Unit) {
Timber.tag(TAG).d("createOrder")
launchWithLoading {
val response = repository.createOrder(order)
@@ -337,72 +341,60 @@ class UserViewModel : BaseViewModel() {
/**
* 现金支付
*/
fun cashPay(param: HashMap<String, String>, block:(Boolean)-> Unit) {
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)
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 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 queryType 查询类型 1支付2退款
* @param orderId 订单号
*/
fun paySuccessCallback(queryType:Int, orderId:String, block:()-> Unit) {
Timber.tag(TAG).d("paySuccessCallback")
val param = hashMapOf(
"queryType" to "$queryType",
"payOrderNo" to orderId
)
launchWithLoading {
var orderState = false
while (orderState.not()) {
val response = repository.queryOrderState(param)
suspend fun queryOrderState(orderId: String, block: (Boolean) -> Unit) {
Timber.tag(TAG).d("queryOrderState")
val response = repository.queryOrderState(orderNo = orderId)
if (parseResponse(response)) {
orderState = response.data?.paySuc == "1"
if (orderState) {
block()
}
}else {
orderState = false
}
}
val orderState = response.data == "1"
block(orderState)
} else {
block(false)
}
}
/**
* 会员支付
*/
fun memberPay(param: HashMap<String, String>, block:(Boolean)-> Unit) {
fun memberPay(param: HashMap<String, String>, block: (Boolean) -> Unit) {
Timber.tag(TAG).d("memberPay")
launchWithLoading {
val response = repository.memberPay(param)
@@ -417,7 +409,7 @@ class UserViewModel : BaseViewModel() {
/**
* 绑定订单
*/
fun bindOrder(userId: String, orderId: String, block:(Boolean)-> Unit){
fun bindOrder(userId: String, orderId: String, block: (Boolean) -> Unit) {
Timber.tag(TAG).d("bindOrder")
launchWithLoading {
val response = repository.bindOrder(userId = userId, orderId = orderId)
@@ -429,7 +421,7 @@ class UserViewModel : BaseViewModel() {
}
}
fun getMemberInfo(memberId: String, block:(MemberInfo?)-> Unit) {
fun getMemberInfo(memberId: String, block: (MemberInfo?) -> Unit) {
Timber.tag(TAG).d("getMemberInfo")
launchWithLoading {
val response = repository.getMemberInfo(memberId)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 876 B

After

Width:  |  Height:  |  Size: 875 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 914 B

After

Width:  |  Height:  |  Size: 913 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 863 B

After

Width:  |  Height:  |  Size: 866 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 829 B

After

Width:  |  Height:  |  Size: 829 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 925 B

After

Width:  |  Height:  |  Size: 927 B

+2 -1
View File
@@ -29,15 +29,16 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginHorizontal="32dp"
android:layout_marginBottom="48dp"
android:layout_weight="1"
android:background="@drawable/bg_pay_content" />
<LinearLayout
android:id="@+id/llPayTab"
android:layout_width="match_parent"
android:layout_height="167dp"
android:layout_gravity="bottom"
android:layout_marginHorizontal="32dp"
android:layout_marginTop="48dp"
android:layout_marginBottom="64dp"
android:gravity="center_vertical"
android:orientation="horizontal">
+1 -1
View File
@@ -16,7 +16,7 @@
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="@color/white"
android:text="请稍"
android:text="请稍后……"
android:textSize="22sp" />
<ProgressBar
@@ -233,8 +233,8 @@
<FrameLayout
android:id="@+id/flRecognizeIr"
android:layout_width="133.33dp"
android:layout_height="100dp"
android:layout_width="1.33dp"
android:layout_height="1dp"
android:layout_gravity="bottom"
android:visibility="gone">