Files
StallDualScreen/app/src/main/java/com/sw/dualscreen/activity/PayActivity.kt
T
lvmeng 8f1f15dd74 feat(payment): 添加会员折扣功能并重构支付逻辑
- 新增 getMemberDiscount 接口用于查询会员折扣
- 在人脸识别支付中集成会员折扣计算逻辑
- 将支付金额计算从 vipPrice 切换到 specPrice 并应用会员折扣
- 在初始化活动中添加设备配置获取功能
- 使用 ConstraintLayout 重构主餐品列表布局
- 添加 Timber 日志框架替换原有 Log 工具
- 重构 MainScreenPresentation 中的食物价格计算逻辑
- 移除重复的设备配置获取代码,统一在 InitActivity 中处理
2026-04-27 17:52:45 +08:00

375 lines
13 KiB
Kotlin

package com.sw.dualscreen.activity
import androidx.activity.OnBackPressedCallback
import androidx.activity.viewModels
import androidx.fragment.app.Fragment
import com.sw.dualscreen.GlobalKey
import com.sw.dualscreen.R
import com.sw.dualscreen.activity.fragment.pay.CashPayFragment
import com.sw.dualscreen.activity.fragment.pay.FacePayFragment
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.model.response.PaySuccessEvent
import com.sw.dualscreen.presentation.pay.PayPresentation
import com.sw.dualscreen.utils.Debouncer
import com.sw.dualscreen.utils.SPUtil
import com.sw.dualscreen.utils.SoundPoolUtil
import com.sw.dualscreen.viewmodel.BaseViewModel
import com.sw.dualscreen.viewmodel.UserViewModel
import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel
import org.greenrobot.eventbus.EventBus
import timber.log.Timber
class PayActivity : BaseActivity<ActivityPayBinding>() {
companion object {
const val FOOD_INFO = "foodInfo"
const val TOTAL_AMOUNT = "totalAmount"
const val FOOD_ORDER_ID = "foodOrderId"
const val FOOD_EAT_NUM = "foodEatNum"
// const val MEMBER_INFO = "memberInfo"
const val TAG_PAY_QR_CODE = "tagPayQrCode"
const val TAG_PAY_CASH = "tagPayCash"
const val TAG_PAY_NUMBER = "tagPayNumber"
const val TAG_PAY_FACE = "tagPayFace"
const val TAG_PAY_RESULT = "tagPayResult"
const val PAY_SUCCESS = "pay_success"
}
val userViewModel by viewModels<UserViewModel>()
val recognizeViewModel by viewModels<RecognizeViewModel>()
override fun getViewModel(): BaseViewModel {
return userViewModel
}
override fun inflateViewBinding(): ActivityPayBinding {
return ActivityPayBinding.inflate(layoutInflater)
}
var foodInfo: FoodInfo? = null
// var totalAmount:Double = 0.0
private var qrCodePayFragment: ScanQrCodePayFragment? = null
private var cashPayFragment: CashPayFragment? = null
private var numberPayFragment: NumberPayFragment? = null
var facePayFragment: FacePayFragment? = null
private var payResultFragment: PayResultFragment? = null
var foodOrderId: String = ""
var eatNum: Int = 1
var isMember: Boolean = false
val presentation by lazy {
PayPresentation(
activity = this@PayActivity,
userViewModel = userViewModel,
recognizeViewModel = recognizeViewModel,
display = displays[1]
)
}
fun playSoundOnPaySuccess() {
SoundPoolUtil.getInstance().play(PAY_SUCCESS, 0)
}
@Suppress("DEPRECATION")
override fun initialize() {
super.initialize()
presentation.show()
registerKeyEvent()
addBackEventListener()
val soundMap = hashMapOf<String, Int>()
soundMap[PAY_SUCCESS] = R.raw.pay_success
SoundPoolUtil.getInstance().loadR(this, soundMap)
foodInfo = intent.getParcelableExtra(FOOD_INFO)
foodOrderId = intent.getStringExtra(FOOD_ORDER_ID) ?: ""
eatNum = intent.getIntExtra(FOOD_EAT_NUM, 1)
// totalAmount = intent.getDoubleExtra(TOTAL_AMOUNT,0.0)
// memberInfo = intent.getParcelableExtra(MEMBER_INFO)
binding.tvFoodName.text = foodInfo?.foodName
binding.include.ivPageBack.setOnClickListener { finish() }
binding.include.tvPageTitle.text = "下单结算"
binding.btnPayQrCode.setOnClickListener {
isMember = false
if (binding.btnPayQrCode.isChecked) {
return@setOnClickListener
}
showScanQrCodePay()
}
binding.btnPayCash.setOnClickListener {
isMember = false
if (binding.btnPayCash.isChecked) {
return@setOnClickListener
}
cashPayFragment = CashPayFragment()
showFragment(cashPayFragment!!, TAG_PAY_CASH)
switchButton(false, true, false, false)
}
binding.btnPayNumber.setOnClickListener {
if (binding.btnPayNumber.isChecked) {
return@setOnClickListener
}
numberPayFragment = NumberPayFragment()
showFragment(numberPayFragment!!, TAG_PAY_NUMBER)
switchButton(false, false, true, false)
}
binding.btnPayFace.setOnClickListener {
if (binding.btnPayFace.isChecked) {
return@setOnClickListener
}
showFacePay()
}
showScanQrCodePay()
}
private fun showScanQrCodePay() {
qrCodePayFragment = ScanQrCodePayFragment()
showFragment(qrCodePayFragment!!, TAG_PAY_QR_CODE)
switchButton(true, false, false, false)
}
private fun switchButton(vararg arr: Boolean) {
binding.btnPayQrCode.isChecked = arr[0]
binding.btnPayCash.isChecked = arr[1]
binding.btnPayNumber.isChecked = arr[2]
binding.btnPayFace.isChecked = arr[3]
}
fun showFacePay() {
facePayFragment = FacePayFragment()
showFragment(facePayFragment!!, TAG_PAY_FACE)
switchButton(false, false, false, true)
}
private fun showFragment(fragment: Fragment, tag: String) {
runCatching {
supportFragmentManager.beginTransaction().apply {
replace(R.id.fragmentContainerView, fragment)
commitNowAllowingStateLoss()
}
}.onFailure {
it.printStackTrace()
}
}
override fun onDestroy() {
presentation.dismiss()
super.onDestroy()
}
var memberDiscount = 1.0
var memberInfo: MemberInfo? = null
fun showPayInfo(type: Int = 1, isVip: Boolean = false, memberInfo: MemberInfo? = null) {
this.memberInfo = memberInfo
payResultFragment = PayResultFragment.instance(type, memberInfo)
showFragment(payResultFragment!!, TAG_PAY_RESULT)
// if (displays.size > 1) {
// scanQrCodePayPresentation = ScanQrCodePayPresentation(
// activity = this,
// display = displays[1],
// type = type
// ) {
// scanQrCodePaypresentation.dismiss()
// }.also {
// it.foodName = foodInfo?.foodName
// //确认使用vipPrice 还是 specPrice
// val onePrice = if (isVip) foodInfo?.vipPrice else foodInfo?.specPrice
// it.totalPrice = (onePrice ?: 0.0) * eatNum
// }
// scanQrCodePaypresentation.show()
// }
presentation.let {
it.pageType = PayPresentation.QR_CODE_PAY
it.type = type
it.foodName = foodInfo?.foodName
//确认使用vipPrice 还是 specPrice
//val onePrice = if (isVip) foodInfo?.vipPrice else foodInfo?.specPrice
if (isVip) {
userViewModel.getMemberDiscount(memberInfo?.faceUserId?:"") { discount ->
memberDiscount = if (discount == null) 1.0 else discount / 10
var onePrice = foodInfo?.specPrice ?: 0.0
onePrice = if (isVip) onePrice * memberDiscount else onePrice
it.totalPrice = onePrice * eatNum
presentation.initView()
}
} else {
it.totalPrice = (foodInfo?.specPrice ?: 0.0) * eatNum
presentation.initView()
}
}
}
fun updateQrCodeImage(qrCodeUrl: String?) {
// scanQrCodePaypresentation.loadQrCodeImage(qrCodeUrl)
presentation.loadQrCodeImage(qrCodeUrl)
}
private var debouncer = Debouncer(5000)
fun showPaySuccess(isVip: Boolean) {
debouncer.debounce {
playSoundOnPaySuccess()
EventBus.getDefault().post(PaySuccessEvent())
showPayInfo(type = 2, isVip = isVip, memberInfo = memberInfo)
hidePayTab()
}
}
fun getQrCodeImg(
orderId: String,
userId: String? = null,
totalFee: String? = null,
block: (String?) -> Unit
) {
userViewModel.getQrCodeImg(
orderId = orderId,
userId = userId,
totalFee = totalFee
) { qrCodeImg ->
runOnUiThread {
if (qrCodeImg.isNullOrBlank()) {
//ToastUtils.showToast("获取二维码失败")
return@runOnUiThread
}
block(qrCodeImg)
}
}
}
fun cashPay(param: HashMap<String, String>, block: (Boolean) -> Unit) {
userViewModel.cashPay(param) {
runOnUiThread {
block(it)
}
}
}
fun memberPay(param: HashMap<String, String?>, block: () -> Unit) {
userViewModel.memberPay(param) {
runOnUiThread {
if (it.not()) {
//ToastUtils.showToast("支付失败,请稍后重试")
return@runOnUiThread
}
block()
}
}
}
suspend fun queryOrderState(block: (Boolean) -> Unit) {
userViewModel.queryOrderState(orderId = foodOrderId) { payResult ->
runOnUiThread {
if (payResult) {
block(true)
} else {
block(false)
}
}
}
}
fun hidePayTab() {
binding.llPayTab.gone()
}
fun getMemberInfoByPhone(phone: String, key: String, block: (MemberInfo?) -> Unit) {
userViewModel.getMemberInfoByPhone(phone, key) { memberInfo ->
runOnUiThread {
block(memberInfo)
}
}
}
fun getMemberInfoById(userId: String, block: (MemberInfo?) -> Unit) {
userViewModel.getMemberInfoById(memberId = userId) { memberInfo ->
runOnUiThread {
block(memberInfo)
}
}
}
fun bindOrder(userId: String, block: (Boolean) -> Unit) {
//0-即放即取,1-余量计量
val pickupMode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0)
val mode = if (pickupMode == 1) 1 else 2
userViewModel.bindOrder(userId, foodOrderId, mode = mode) { bindResult ->
runOnUiThread {
block(bindResult)
}
}
}
fun qrCodePay(scanInfo: String) {
showWaitingDialog("支付中……")
userViewModel.qrCodePay(scanInfo, foodOrderId, memberInfo?.id) { payState, backData ->
Timber.d("qrCodePay支付返回数据:state=$payState,backData=$backData")
hideWaitingDialog()
if (payState) {
showPaySuccess(isMember)
}
}
}
// fun bindOrder(userId: String, block: () -> Unit) {
// val pickupMode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0)
// val mode = if (pickupMode == 1) 1 else 2
// userViewModel.bindOrder(userId, foodOrderId, mode = mode) { bindResult ->
// runOnUiThread {
// if (bindResult.not()) {
// hideWaitingDialog()
// //ToastUtils.showToast("订单绑定失败")
// return@runOnUiThread
// }
// binding.root.postDelayed({
// hideWaitingDialog()
// showPayInfo(type = 1, isVip = true, memberInfo = memberInfo)
// hidePayTab()
// block()
// }, 1000)
// }
// }
// }
// fun getMemberInfoByPhone(phone: String, key: String, block: (MemberInfo) -> Unit) {
// userViewModel.getMemberInfoByPhone(phone, key) { memberInfo ->
// runOnUiThread {
// if (memberInfo == null) {
// hideWaitingDialog()
// //ToastUtils.showToast("查询会员信息失败,请稍后重试")
// return@runOnUiThread
// }
// block(memberInfo)
// }
// }
// }
// fun getMemberInfo(userId: String, block: (MemberInfo) -> Unit) {
// userViewModel.getMemberInfoById(memberId = userId) { memberInfo ->
// runOnUiThread {
// if (memberInfo == null) {
// hideWaitingDialog()
// //ToastUtils.showToast("查询会员信息失败,请稍后重试")
// return@runOnUiThread
// }
// block(memberInfo)
// }
// }
// }
fun addBackEventListener() {
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
}
})
}
}