Browse Source

充值,和查询重置状态接口

master
DU 2 months ago
parent
commit
1e332d8d08
  1. 56
      src/api/recharge.ts
  2. 4
      src/pagesOrder/recharge/index.scss
  3. 127
      src/pagesOrder/recharge/index.tsx
  4. 61
      src/types/recharge.ts

56
src/api/recharge.ts

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
/**
* API
*/
import { get, post } from '../services/request'
import {
CreateRechargePaymentDto,
RechargePaymentResponseDto,
RechargeWechatPayParameters,
PaymentChannel,
} from '../types/recharge'
/** 小程序 JSAPI 支付固定交易类型 */
const MINI_PROGRAM_TRADE_TYPE = 1
/**
*
* @param dto
* @returns
*/
export const createRechargeOrder = (dto: CreateRechargePaymentDto) => {
return post<RechargePaymentResponseDto>('/Recharge/create', {
tradeType: MINI_PROGRAM_TRADE_TYPE,
...dto,
}, {
showLoading: true,
loadingText: '创建订单中...',
})
}
/**
*
* @param outTradeNo
* @param channel
* @returns
*/
export const queryPaymentStatus = (outTradeNo: string, channel?: PaymentChannel) => {
return get<boolean>(`/Recharge/query/${outTradeNo}`, channel ? { channel } : undefined)
}
/**
*
* @param payParams
*/
export const invokeWechatPayForRecharge = (payParams: RechargeWechatPayParameters): Promise<void> => {
return new Promise((resolve, reject) => {
wx.requestPayment({
timeStamp: payParams.timeStamp,
nonceStr: payParams.nonceStr,
package: payParams.package,
signType: payParams.signType as 'MD5' | 'HMAC-SHA256' | 'RSA',
paySign: payParams.paySign,
success: () => resolve(),
fail: (err) => reject(err),
})
})
}

4
src/pagesOrder/recharge/index.scss

@ -182,6 +182,10 @@ @@ -182,6 +182,10 @@
font-size: 33px;
color: #844614;
}
&.disabled {
opacity: 0.6;
}
}
}
}

127
src/pagesOrder/recharge/index.tsx

@ -4,14 +4,17 @@ @@ -4,14 +4,17 @@
import { View, Text } from '@tarojs/components'
import Taro, { useLoad } from '@tarojs/taro'
import { useState } from 'react'
import './index.scss'
import { observer } from 'mobx-react'
import { Arrow } from '@taroify/icons'
import { createRechargeOrder, invokeWechatPayForRecharge, queryPaymentStatus } from '@/api/recharge'
import { userStore } from '@/store'
import './index.scss'
// 充值套餐数据
// 充值套餐数据(套餐内容需与后端确认是否动态配置)
interface RechargePackage {
id: number
amount: number // 充值金额
bonus: number // 赠送金额
amount: number
bonus: number
}
const RechargePackages: RechargePackage[] = [
@ -23,14 +26,18 @@ const RechargePackages: RechargePackage[] = [ @@ -23,14 +26,18 @@ const RechargePackages: RechargePackage[] = [
{ id: 6, amount: 1000, bonus: 700 },
]
const RechargePage = () => {
const RechargePage = observer(() => {
const [selectedPackageId, setSelectedPackageId] = useState<number | null>(null)
const [currentBalance] = useState(28.8) // 当前余额
const [loading, setLoading] = useState(false)
useLoad(() => {
console.log('余额充值页面加载')
})
// 当前余额和门店名称从 userStore 读取
const currentBalance = userStore.balance
const storeName = userStore.userInfo?.bpInfoName || '--'
// 选择套餐
const handleSelectPackage = (id: number) => {
setSelectedPackageId(id)
@ -43,25 +50,100 @@ const RechargePage = () => { @@ -43,25 +50,100 @@ const RechargePage = () => {
})
}
// 轮询查询支付状态,最多查 5 次,每次间隔 2 秒
const pollPaymentStatus = async (outTradeNo: string): Promise<boolean> => {
for (let i = 0; i < 5; i++) {
await new Promise(resolve => setTimeout(resolve, 2000))
try {
const res = await queryPaymentStatus(outTradeNo, 'WechatPay')
if (res.data === true) {
return true
}
} catch (e) {
console.warn('查询支付状态异常:', e)
}
}
return false
}
// 立即充值
const handleRecharge = () => {
const handleRecharge = async () => {
if (loading) return
if (!selectedPackageId) {
Taro.showToast({
title: '请选择充值套餐',
icon: 'none',
duration: 2000
})
Taro.showToast({ title: '请选择充值套餐', icon: 'none', duration: 2000 })
return
}
const selectedPackage = RechargePackages.find(pkg => pkg.id === selectedPackageId)
if (selectedPackage) {
Taro.showToast({
title: `充值 ¥${selectedPackage.amount}`,
icon: 'none',
duration: 2000
if (!selectedPackage) return
const openId = userStore.userInfo?.wxOpenId
if (!openId) {
Taro.showToast({ title: '请先登录', icon: 'none', duration: 2000 })
return
}
setLoading(true)
try {
// 创建充值订单
const result = await createRechargeOrder({
userId: String(userStore.userInfo?.id || ''),
customerSn: userStore.userInfo?.bpSn,
amount: selectedPackage.amount,
giftAmount: selectedPackage.bonus,
bpSn: userStore.userInfo?.bpSn,
instSn: userStore.userInfo?.instSn,
openId,
subject: '账户余额充值',
body: `充值 ¥${selectedPackage.amount},赠送 ¥${selectedPackage.bonus}`,
})
const payData = result.data
if (!payData?.payParameters) {
Taro.showToast({ title: '获取支付参数失败', icon: 'none', duration: 2000 })
return
}
// 调起微信支付
try {
await invokeWechatPayForRecharge(payData.payParameters)
// 微信支付成功回调后,查询服务端支付状态确认
Taro.showLoading({ title: '确认支付中...', mask: true })
const paid = await pollPaymentStatus(payData.outTradeNo)
Taro.hideLoading()
if (paid) {
// 更新本地余额(充值金额 + 赠送金额)
const newBalance = currentBalance + selectedPackage.amount + selectedPackage.bonus
userStore.setBalance(newBalance)
Taro.showToast({ title: '充值成功', icon: 'success', duration: 2000 })
setSelectedPackageId(null)
} else {
Taro.showModal({
title: '支付确认',
content: '支付结果暂未到账,请稍后刷新余额查看。如有疑问请联系店长。',
showCancel: false,
confirmText: '知道了',
})
// TODO: 调用充值接口
}
} catch (payError: any) {
console.log('支付错误:', payError)
if (payError.errMsg?.includes('cancel')) {
Taro.showToast({ title: '已取消支付', icon: 'none', duration: 2000 })
} else {
Taro.showToast({ title: payError.errMsg || '支付失败', icon: 'none', duration: 2000 })
}
}
} catch (error: any) {
console.error('创建充值订单失败:', error)
// 错误提示由 request 拦截器统一处理
} finally {
setLoading(false)
}
}
@ -69,7 +151,7 @@ const RechargePage = () => { @@ -69,7 +151,7 @@ const RechargePage = () => {
<View className="recharge-page">
{/* 上部分:余额卡片区域 */}
<View className="balance-card-area">
<Text className="store-name"></Text>
<Text className="store-name">{storeName}</Text>
<View className="balance-card">
<View className="card-row">
@ -100,7 +182,6 @@ const RechargePage = () => { @@ -100,7 +182,6 @@ const RechargePage = () => {
{/* 下部分:套餐和提示区域 */}
<View className="packages-area">
{/* 余额充值标题 */}
<Text className="section-title"></Text>
{/* 充值套餐列表 */}
@ -132,12 +213,12 @@ const RechargePage = () => { @@ -132,12 +213,12 @@ const RechargePage = () => {
{/* 底部固定按钮 */}
<View className="footer-bar">
<View className="recharge-btn" onClick={handleRecharge}>
<Text className="recharge-btn-text"></Text>
<View className={`recharge-btn ${loading ? 'disabled' : ''}`} onClick={handleRecharge}>
<Text className="recharge-btn-text">{loading ? '处理中...' : '立即充值'}</Text>
</View>
</View>
</View>
)
}
})
export default RechargePage

61
src/types/recharge.ts

@ -0,0 +1,61 @@ @@ -0,0 +1,61 @@
/**
*
*/
/**
*
*/
export interface CreateRechargePaymentDto {
/** 用户ID */
userId?: string
/** 客户编码(充值对象) */
customerSn?: string
/** 充值金额 */
amount?: number
/** 赠送金额 */
giftAmount?: number
/** 充值类型 */
rcgType?: number
/** 交易类型:1-JSAPI/小程序 */
tradeType?: number
/** 店铺编码 */
bpSn?: string
/** 机构编码 */
instSn?: string
/** OpenId(微信支付必传) */
openId?: string
/** 支付标题 */
subject?: string
/** 支付描述 */
body?: string
}
/**
* data
*/
export interface RechargePaymentResponseDto {
/** 商户订单号 */
outTradeNo: string
/** 支付渠道:1-微信、2-支付宝等 */
channel: number
/** 调起微信支付所需参数 */
payParameters: RechargeWechatPayParameters | null
/** 支付链接(Native扫码支付用) */
payUrl: string
}
/**
*
*/
export interface RechargeWechatPayParameters {
timeStamp: string
nonceStr: string
package: string
signType: string
paySign: string
}
/**
*
*/
export type PaymentChannel = 'WechatPay' | 'Alipay' | 'UnionPay' | 'Balance' | 'BankCard'
Loading…
Cancel
Save