接入微信支付

This commit is contained in:
fengjignqi
2026-08-10 15:41:43 +08:00
parent 579e9427c8
commit f3006f4255
27 changed files with 2649 additions and 47 deletions

Binary file not shown.

2289
.idea/caches/deviceStreaming.xml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -4,10 +4,10 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2026-08-06T08:17:58.704098200Z">
<DropdownSelection timestamp="2026-08-10T02:36:52.136106800Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=80bece4" />
<DeviceId pluginId="PhysicalDevice" identifier="serial=D122222104A9" />
</handle>
</Target>
</DropdownSelection>

View File

@@ -0,0 +1,12 @@
package com.ck.ckcollar.app.model
import com.google.gson.JsonElement
class OrderPaymentModel {
var orderStr: JsonElement? = null
var wxMap: JsonElement? = null
var pointsAmount: Double = 0.0
var balanceAmount: Double = 0.0
var alipayAmount: Double = 0.0
var info: String? = ""
}

View File

@@ -70,18 +70,24 @@ class WithDrawActivity : CKLHBaseActionBarActivity() {
toast(getString(R.string.no_balance_data))
return
}
if (TextUtils.isEmpty(binding.editAmount.text.toString())){
val amountText = binding.editAmount.text.toString()
if (TextUtils.isEmpty(amountText)){
toast(getString(R.string.withdraw_amount_not_empty))
return
}
if (binding.editAmount.text.toString().toDouble() > model!!.balance){
val amount = amountText.toBigDecimalOrNull()
if (amount == null || amount < BigDecimal("0.1")) {
toast(getString(R.string.withdraw_amount_minimum))
return
}
if (amount > BigDecimal.valueOf(model!!.balance)){
toast(getString(R.string.withdraw_amount_alert))
return
}
showProgeassDialog(getString(R.string.withdraw))
TTHttpClient.postJson(this, "提现", TTRequestParam().apply {
add(TTRequestData("amount", binding.editAmount.text.toString()))
add(TTRequestData("amount", amountText))
add(TTRequestData("payType", payType))
}, object : ICallback {
override fun onSuccess(data: String) {

View File

@@ -160,6 +160,7 @@ class MyOrderActivity : CKBaseActivity() , View.OnClickListener{
fun getData() {
showProgeassDialog()
TTHttpClient.get(this, "我的订单", TTRequestParam().apply {
add(
TTRequestData("pageNum", page)
@@ -172,10 +173,10 @@ class MyOrderActivity : CKBaseActivity() , View.OnClickListener{
override fun onSuccess(data: String) {
var model = Gson().fromJson<OrderModel>(data, OrderModel::class.java)
model.rows?.let{
if (page == 1) {
this@MyOrderActivity.data.clear()
}
model.rows?.let{
if (this@MyOrderActivity.data.size != model.total){
this@MyOrderActivity.data.addAll(model.rows!!)
}
@@ -184,11 +185,17 @@ class MyOrderActivity : CKBaseActivity() , View.OnClickListener{
orderAdapter.data = this@MyOrderActivity.data
orderAdapter.notifyDataSetChanged()
val isEmpty = this@MyOrderActivity.data.isEmpty()
binding.relNoresult.visibility = if (isEmpty) View.VISIBLE else View.GONE
binding.recyclerView.visibility = if (isEmpty) View.GONE else View.VISIBLE
binding.refreshLayout.finishRefresh()
binding.refreshLayout.finishLoadMore(true)
}
override fun onFailed(code: String, msg: String) {
binding.refreshLayout.finishRefresh()
binding.refreshLayout.finishLoadMore(false)
toast(msg)
}
})

View File

@@ -22,22 +22,28 @@ import com.ck.ckcollar.app.model.AddressModel
import com.ck.ckcollar.app.model.ConfirmOrderModel
import com.ck.ckcollar.app.model.MemberModel
import com.ck.ckcollar.app.model.OrderModel
import com.ck.ckcollar.app.model.OrderPaymentModel
import com.ck.ckcollar.app.model.PayOrderModel
import com.ck.ckcollar.app.model.PayPasswordStatus
import com.ck.ckcollar.app.model.PayResult
import com.ck.ckcollar.app.model.UserInfoModel
import com.ck.ckcollar.app.ui.act.setting.PayPsswordActivity
import com.ck.ckcollar.app.ui.act.balance.RechargeActivity
import com.ck.ckcollar.app.ui.act.shop.OrderSuccessActivity
import com.ck.ckcollar.app.ui.act.shop.PayPasswordBottomFragment
import com.ck.ckcollar.app.ui.base.CKBaseActivity
import com.ck.ckcollar.app.utils.CKUtils
import com.ck.ckcollar.app.utils.Const
import com.ck.ckcollar.app.utils.networkone.ICallback
import com.ck.ckcollar.app.utils.networkone.TTHttpClient
import com.ck.ckcollar.app.utils.networkone.model.TTRequestData
import com.ck.ckcollar.app.utils.networkone.model.TTRequestParam
import com.google.gson.Gson
import com.tencent.mm.opensdk.modelpay.PayReq
import com.tencent.mm.opensdk.openapi.WXAPIFactory
import com.tt.kit.model.Data
import com.tt.kit.model.DataCollection
import com.tt.kit.utils.LiveDataBus
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
@@ -71,6 +77,14 @@ class PayOrderActivity : CKBaseActivity() {
}
override fun initView() {
LiveDataBus.get().with(RechargeActivity.WX_PAY_RESULT, Int::class.java).observe(this) { result ->
if (result == 0) {
handleWeChatPaymentSuccess()
} else {
handleWeChatPaymentFailed(result == -2)
}
}
productAdapter =
ProductAdapter(this@PayOrderActivity, productDatas, object : OnItemClickListenner {
override fun onClick(pos: Int, model: Any) {
@@ -286,16 +300,25 @@ class PayOrderActivity : CKBaseActivity() {
)
}, object : ICallback {
override fun onSuccess(data: String) {
var model = Gson().fromJson<PayOrderModel>(data, PayOrderModel::class.java)
val paymentModel = Gson().fromJson(data, OrderPaymentModel::class.java)
if ("0".equals(this@PayOrderActivity.payType)) {
//微信
val weChatPayParams = paymentModel.wxMap
if (weChatPayParams == null || !weChatPayParams.isJsonObject) {
hiddenProgeassDialog()
toast("微信支付参数格式错误")
return
}
wxPay(Gson().fromJson(weChatPayParams, PayOrderModel::class.java))
}else if ("1".equals(this@PayOrderActivity.payType)) {
if (TextUtils.isEmpty(model.orderStr)){
val aliPayOrderStr = paymentModel.orderStr
?.takeIf { it.isJsonPrimitive && it.asJsonPrimitive.isString }
?.asString
if (TextUtils.isEmpty(aliPayOrderStr)){
toActivity(OrderSuccessActivity::class.java, DataCollection())
finish(DataCollection(),1002)
}else{
aliPay(model.orderStr!!)
aliPay(aliPayOrderStr!!)
}
}else{
toast(getString(R.string.order_success))
@@ -314,6 +337,60 @@ class PayOrderActivity : CKBaseActivity() {
})
}
private fun wxPay(model: PayOrderModel) {
val requiredValues = listOf(
model.appId,
model.partnerId,
model.prepayId,
model.packageVal,
model.nonceStr,
model.timeStamp,
model.paySign
)
if (requiredValues.any { it.isNullOrBlank() }) {
hiddenProgeassDialog()
toast("微信支付参数不完整,请检查商户号等支付参数")
return
}
if (model.appId != Const.WX_APP_ID) {
hiddenProgeassDialog()
toast("微信支付 AppID 不匹配")
return
}
val api = WXAPIFactory.createWXAPI(this, Const.WX_APP_ID, true)
api.registerApp(Const.WX_APP_ID)
if (!api.isWXAppInstalled) {
hiddenProgeassDialog()
toast("请先安装微信")
return
}
val request = PayReq().apply {
appId = model.appId
partnerId = model.partnerId
prepayId = model.prepayId
packageValue = model.packageVal
nonceStr = model.nonceStr
timeStamp = model.timeStamp
sign = model.paySign
extData = model.orderNo
}
hiddenProgeassDialog()
if (!api.sendReq(request)) {
toast("微信支付拉起失败")
}
}
private fun handleWeChatPaymentSuccess() {
toast(getString(R.string.payment_success))
finish(DataCollection(), 1002)
}
private fun handleWeChatPaymentFailed(cancelled: Boolean) {
toast(if (cancelled) "已取消微信支付" else getString(R.string.payment_faild))
}
private fun canPointsCoverPayAmount(): Boolean {
if (!selectPoints) return false
val pointsDeduction = calculatePointsDeduction() ?: return false

View File

@@ -2,6 +2,7 @@ package com.ck.ckcollar.app.ui.act.petmanager
import android.net.wifi.ScanResult
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.widget.PopupWindow
import androidx.recyclerview.widget.LinearLayoutManager
@@ -64,7 +65,7 @@ class PetManagerActivity : CKBaseActivity() {
}
fun getData() {
//showProgeassDialog(getString(R.string.search))
showProgeassDialog(getString(R.string.search))
TTHttpClient.get(this, "宠物列表", TTRequestParam().apply {
add(
TTRequestData("pageNum", 1)
@@ -81,6 +82,10 @@ class PetManagerActivity : CKBaseActivity() {
petAdapter.data = this@PetManagerActivity.data
petAdapter.notifyDataSetChanged()
val isEmpty = this@PetManagerActivity.data.isEmpty()
binding.relNoresult.visibility = if (isEmpty) View.VISIBLE else View.GONE
binding.recyclerView.visibility = if (isEmpty) View.GONE else View.VISIBLE
}
override fun onFailed(code: String, msg: String) {

View File

@@ -23,6 +23,7 @@ import com.ck.ckcollar.app.model.AddressModel
import com.ck.ckcollar.app.model.ConfirmOrderModel
import com.ck.ckcollar.app.model.CreateOrderModel
import com.ck.ckcollar.app.model.MemberModel
import com.ck.ckcollar.app.model.OrderPaymentModel
import com.ck.ckcollar.app.model.PayOrderModel
import com.ck.ckcollar.app.model.PayPasswordStatus
import com.ck.ckcollar.app.model.PayResult
@@ -312,15 +313,24 @@ class OrderActivity : CKBaseActivity() {
TTHttpClient.postJson(this, "下单", param.toString(), object : ICallback {
override fun onSuccess(data: String) {
var model = Gson().fromJson<PayOrderModel>(data, PayOrderModel::class.java)
val paymentModel = Gson().fromJson(data, OrderPaymentModel::class.java)
if ("0".equals(this@OrderActivity.payType)) {
wxPay(model)
val weChatPayParams = paymentModel.wxMap
if (weChatPayParams == null || !weChatPayParams.isJsonObject) {
hiddenProgeassDialog()
toast("微信支付参数格式错误")
return
}
wxPay(Gson().fromJson(weChatPayParams, PayOrderModel::class.java))
}else if ("1".equals(this@OrderActivity.payType)) {
if (TextUtils.isEmpty(model.orderStr)){
val aliPayOrderStr = paymentModel.orderStr
?.takeIf { it.isJsonPrimitive && it.asJsonPrimitive.isString }
?.asString
if (TextUtils.isEmpty(aliPayOrderStr)){
toActivity(OrderSuccessActivity::class.java, DataCollection())
finish()
}else{
aliPay(model.orderStr!!)
aliPay(aliPayOrderStr!!)
}
}else{
toast(getString(R.string.order_success))

View File

@@ -4,6 +4,7 @@ import android.content.Context
import android.os.Bundle
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
@@ -223,6 +224,7 @@ class ShopCarActivity : CKLHBaseActionBarActivity() {
})
}
fun getData(){
showProgeassDialog()
TTHttpClient.get(this,"购物车列表", TTRequestParam(),object : ICallback{
override fun onSuccess(data: String) {
this@ShopCarActivity.productDatas = Gson().fromJson<List<ShopCarModel>>(data, object : TypeToken<List<ShopCarModel>>(){}.type)
@@ -230,6 +232,10 @@ class ShopCarActivity : CKLHBaseActionBarActivity() {
shopCarAdapter.data = this@ShopCarActivity.productDatas
shopCarAdapter.notifyDataSetChanged()
val isEmpty = this@ShopCarActivity.productDatas.isEmpty()
binding.relNoresult.visibility = if (isEmpty) View.VISIBLE else View.GONE
binding.recyclerView.visibility = if (isEmpty) View.GONE else View.VISIBLE
var flag = true
for (model in productDatas){
if ("0".equals(model.selected)){
@@ -251,7 +257,7 @@ class ShopCarActivity : CKLHBaseActionBarActivity() {
}
override fun onFailed(code: String, msg: String) {
toast(msg)
}
})
}

View File

@@ -3,6 +3,7 @@ package com.ck.ckcollar.app.ui.act.shop
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
@@ -88,6 +89,7 @@ class TypeActivity : CKLHBaseActionBarActivity() {
fun getData() {
showProgeassDialog()
TTHttpClient.get(this, "商品列表", TTRequestParam().apply {
add(
TTRequestData("pageNum", page)
@@ -109,12 +111,18 @@ class TypeActivity : CKLHBaseActionBarActivity() {
productAdapter.data = productDatas
productAdapter.notifyDataSetChanged()
val isEmpty = productDatas.isEmpty()
binding.relNoresult.visibility = if (isEmpty) View.VISIBLE else View.GONE
binding.recyclerView.visibility = if (isEmpty) View.GONE else View.VISIBLE
binding.refreshLayout.finishLoadMore(true)
binding.refreshLayout.finishRefresh()
}
override fun onFailed(code: String, msg: String) {
binding.refreshLayout.finishLoadMore(true)
binding.refreshLayout.finishLoadMore(false)
binding.refreshLayout.finishRefresh()
toast(msg)
}
})

View File

@@ -0,0 +1,44 @@
package com.ck.ckcollar.app.wxapi
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import com.ck.ckcollar.app.ui.act.balance.RechargeActivity
import com.ck.ckcollar.app.utils.Const
import com.tencent.mm.opensdk.modelbase.BaseReq
import com.tencent.mm.opensdk.modelbase.BaseResp
import com.tencent.mm.opensdk.openapi.IWXAPI
import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler
import com.tencent.mm.opensdk.openapi.WXAPIFactory
import com.tt.kit.utils.LiveDataBus
class WXPayEntryActivity : Activity(), IWXAPIEventHandler {
private lateinit var api: IWXAPI
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
api = WXAPIFactory.createWXAPI(this, Const.WX_APP_ID, false)
api.handleIntent(intent, this)
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
setIntent(intent)
api.handleIntent(intent, this)
}
override fun onReq(req: BaseReq?) = Unit
override fun onResp(resp: BaseResp?) {
val resultCode = resp?.errCode ?: -1
val message = when (resultCode) {
BaseResp.ErrCode.ERR_OK -> "微信支付成功"
BaseResp.ErrCode.ERR_USER_CANCEL -> "已取消微信支付"
else -> "微信支付失败"
}
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
LiveDataBus.get().with(RechargeActivity.WX_PAY_RESULT).value = resultCode
finish()
}
}

View File

@@ -80,18 +80,34 @@
android:layout_height="match_parent">
<com.scwang.smartrefresh.layout.header.ClassicsHeader
android:layout_width="match_parent"
android:layout_height="wrap_content"></com.scwang.smartrefresh.layout.header.ClassicsHeader>
android:layout_height="wrap_content"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingHorizontal="20dp"
android:layout_marginVertical="12dp"
></androidx.recyclerview.widget.RecyclerView>
android:layout_marginVertical="12dp" />
<RelativeLayout
android:id="@+id/rel_noresult"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<include
android:id="@+id/include_noresult"
layout="@layout/include_no_result_layout" />
</RelativeLayout>
</FrameLayout>
<com.scwang.smartrefresh.layout.footer.ClassicsFooter
android:layout_width="match_parent"
android:layout_height="wrap_content"></com.scwang.smartrefresh.layout.footer.ClassicsFooter>
android:layout_height="wrap_content"/>
</com.scwang.smartrefresh.layout.SmartRefreshLayout>
</com.ck.ckcollar.app.widget.CKLinearLayout>

View File

@@ -14,12 +14,27 @@
android:padding="20dp"
>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<RelativeLayout
android:id="@+id/rel_noresult"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
></androidx.recyclerview.widget.RecyclerView>
android:visibility="gone">
<include
android:id="@+id/include_noresult"
layout="@layout/include_no_result_layout" />
</RelativeLayout>
</FrameLayout>
<com.ck.ckcollar.app.widget.CKButton

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<com.ck.ckcollar.app.widget.CKLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:background="@color/backgroundColor">
<include layout="@layout/action_bar" />
<WebView android:id="@+id/webView" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_weight="1" />
</com.ck.ckcollar.app.widget.CKLinearLayout>

View File

@@ -11,13 +11,29 @@
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_marginHorizontal="20dp"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_marginHorizontal="20dp"
android:layout_height="match_parent"></androidx.recyclerview.widget.RecyclerView>
android:layout_height="match_parent" />
<RelativeLayout
android:id="@+id/rel_noresult"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<include
android:id="@+id/include_noresult"
layout="@layout/include_no_result_layout" />
</RelativeLayout>
</FrameLayout>
<com.ck.ckcollar.app.widget.CKLinearLayout

View File

@@ -20,16 +20,32 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
</com.scwang.smartrefresh.layout.header.ClassicsHeader>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_marginHorizontal="12dp"
android:layout_height="match_parent"></androidx.recyclerview.widget.RecyclerView>
android:layout_height="match_parent"/>
<RelativeLayout
android:id="@+id/rel_noresult"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<include
android:id="@+id/include_noresult"
layout="@layout/include_no_result_layout" />
</RelativeLayout>
</FrameLayout>
<com.scwang.smartrefresh.layout.footer.ClassicsFooter
android:layout_width="match_parent"
android:layout_height="wrap_content"></com.scwang.smartrefresh.layout.footer.ClassicsFooter>
android:layout_height="wrap_content"/>
</com.scwang.smartrefresh.layout.SmartRefreshLayout>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/rel_noresult"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="200dp">
<ImageView
android:id="@+id/img_noresult"
android:layout_width="120dp"
android:layout_height="120dp"
android:src="@mipmap/icon_no_result"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"/>
<TextView
android:id="@+id/tv_noresult"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textColor="@color/color_999999"
android:text="暂无结果"
android:layout_below="@+id/img_noresult"
android:layout_centerHorizontal="true"/>
</RelativeLayout>
</RelativeLayout>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_permission_top_dialog"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="12dp">
<ImageView
android:layout_width="25dp"
android:layout_height="25dp"
android:contentDescription="@string/camera"
android:src="@android:drawable/ic_dialog_info" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/permissionTopTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#FF222222"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="@+id/permissionTopContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:textColor="#FF555555"
android:textSize="14sp" />
</LinearLayout>
</LinearLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -274,6 +274,7 @@
<string name="confirm_recharge">确认充值</string>
<string name="recharge_amount_not_empty">充值金额不能为空</string>
<string name="withdraw_amount_not_empty">提现金额不能为空</string>
<string name="withdraw_amount_minimum">提现金额不能小于0.1元</string>
<string name="withdraw_amount_alert">提现金额不能大于可提现余额</string>
<!-- 收支明细模块 -->