完善微信支付二维码生成机制

This commit is contained in:
2025-05-09 16:37:05 +08:00
parent 0665a4e13c
commit ea211e85a9
3 changed files with 88 additions and 81 deletions

View File

@@ -5,7 +5,7 @@ import alipay from '../_assets/alipay.svg'
import wechat from '../_assets/wechat.svg'
import balance from '../_assets/balance.svg'
import Image from 'next/image'
import {useContext, useRef, useState} from 'react'
import {useContext, useEffect, useRef, useState} from 'react'
import {StoreContext, useProfileStore} from '@/components/providers/StoreProvider'
import {Alert, AlertDescription} from '@/components/ui/alert'
import {
@@ -38,6 +38,14 @@ export default function Pay(props: PayProps) {
const [open, setOpen] = useState(false)
const [payInfo, setPayInfo] = useState<CreateResourceResp | undefined>()
const canvas = useRef<HTMLCanvasElement>(null)
useEffect(() => {
if (canvas.current && payInfo) {
qrcode.toCanvas(canvas.current, payInfo.pay_url, {
width: 200,
margin: 0,
})
}
}, [payInfo])
const onOpen = async () => {
setOpen(true)
@@ -48,12 +56,12 @@ export default function Pay(props: PayProps) {
let resp: ApiResponse<CreateResourceResp>
switch (props.method) {
case 'alipay':
resp = await prepareResourceByAlipay(props.resource)
break
case 'wechat':
resp = await prepareResourceByWechat(props.resource)
break
case 'alipay':
resp = await prepareResourceByAlipay(props.resource)
break
case 'wechat':
resp = await prepareResourceByWechat(props.resource)
break
}
if (!resp.success) {
toast.error(`创建订单失败: ${resp.message}`)
@@ -62,7 +70,6 @@ export default function Pay(props: PayProps) {
}
setPayInfo(resp.data)
await qrcode.toCanvas(canvas.current, resp.data.pay_url)
}
const router = useRouter()
@@ -70,19 +77,19 @@ export default function Pay(props: PayProps) {
let resp: ApiResponse
try {
switch (props.method) {
case 'alipay':
resp = await createResourceByAlipay({
trade_no: payInfo!.trade_no,
})
break
case 'wechat':
resp = await createResourceByWechat({
trade_no: payInfo!.trade_no,
})
break
case 'balance':
resp = await createResourceByBalance(props.resource)
break
case 'alipay':
resp = await createResourceByAlipay({
trade_no: payInfo!.trade_no,
})
break
case 'wechat':
resp = await createResourceByWechat({
trade_no: payInfo!.trade_no,
})
break
case 'balance':
resp = await createResourceByBalance(props.resource)
break
}
if (!resp.success) {
@@ -175,14 +182,10 @@ export default function Pay(props: PayProps) {
) : (
<div className="flex flex-col items-center gap-4">
<div className="flex flex-col items-center gap-3">
<div className="bg-gray-100 w-52 h-52 flex items-center justify-center">
<div className="bg-gray-100 size-50 flex items-center justify-center">
{payInfo ? (
props.method === 'alipay'
? <iframe
src={payInfo.pay_url}
className="w-full h-full"
title="支付二维码"
/>
? <iframe src={payInfo.pay_url} className="w-full h-full" />
: <canvas ref={canvas} className="w-full h-full"/>
) : (
<Loader size={40} className={`animate-spin text-weak`}/>

View File

@@ -17,7 +17,7 @@ import {zodResolver} from '@hookform/resolvers/zod'
import {toast} from 'sonner'
import wechat from '@/components/composites/purchase/_assets/wechat.svg'
import alipay from '@/components/composites/purchase/_assets/alipay.svg'
import {useRef, useState} from 'react'
import {useEffect, useRef, useState} from 'react'
import {Loader} from 'lucide-react'
import {RechargeByAlipay, RechargeByAlipayConfirm, RechargeByWechat, RechargeByWechatConfirm} from '@/actions/user'
import * as qrcode from 'qrcode'
@@ -52,50 +52,60 @@ export default function RechargeModal(props: RechargeModelProps) {
const method = form.watch('method')
const amount = form.watch('amount')
const canvas = useRef<HTMLCanvasElement>(null)
const [step, setStep] = useState(0)
const [payInfo, setPayInfo] = useState<{
trade_no: string
pay_url: string
}>()
const canvas = useRef<HTMLCanvasElement>(null)
useEffect(() => {
if (canvas.current && payInfo) {
qrcode.toCanvas(canvas.current, payInfo.pay_url, {
width: 200,
margin: 0,
})
}
}, [payInfo])
const refreshProfile = useProfileStore(store => store.refreshProfile)
const createRecharge = async (data: Schema) => {
try {
switch (data.method) {
case 'alipay':
const aliRes = await RechargeByAlipay({
amount: data.amount,
case 'alipay':
const aliRes = await RechargeByAlipay({
amount: data.amount,
})
if (aliRes.success) {
setStep(1)
setPayInfo(aliRes.data)
}
else {
toast.error(`创建订单失败`, {
description: aliRes.message,
})
if (aliRes.success) {
setStep(1)
setPayInfo(aliRes.data)
}
else {
toast.error(`充值失败`, {
description: aliRes.message,
})
}
break
case 'wechat':
const weRes = await RechargeByWechat({
amount: data.amount,
}
break
case 'wechat':
const weRes = await RechargeByWechat({
amount: data.amount,
})
if (weRes.success) {
setStep(1)
setPayInfo(weRes.data)
}
else {
toast.error(`创建订单失败`, {
description: weRes.message,
})
if (weRes.success) {
setStep(1)
setPayInfo(weRes.data)
await qrcode.toCanvas(canvas.current, weRes.data.pay_url)
}
else {
toast.error(`充值失败`, {
description: weRes.message,
})
}
break
}
break
}
}
catch (e) {
toast.error(`充值失败`, {
console.error(e)
toast.error(`创建订单失败`, {
description: (e as Error).message,
})
}
@@ -110,22 +120,22 @@ export default function RechargeModal(props: RechargeModelProps) {
}
try {
switch (method) {
case 'alipay':
const aliRes = await RechargeByAlipayConfirm({
trade_no: payInfo.trade_no,
})
if (!aliRes.success) {
throw new Error(aliRes.message)
}
break
case 'wechat':
const weRes = await RechargeByWechatConfirm({
trade_no: payInfo.trade_no,
})
if (!weRes.success) {
throw new Error(weRes.message)
}
break
case 'alipay':
const aliRes = await RechargeByAlipayConfirm({
trade_no: payInfo.trade_no,
})
if (!aliRes.success) {
throw new Error(aliRes.message)
}
break
case 'wechat':
const weRes = await RechargeByWechatConfirm({
trade_no: payInfo.trade_no,
})
if (!weRes.success) {
throw new Error(weRes.message)
}
break
}
toast.success(`充值成功`)
closeDialog()
@@ -144,7 +154,6 @@ export default function RechargeModal(props: RechargeModelProps) {
setStep(0)
}
const [step, setStep] = useState(0)
return (
<Dialog open={open} onOpenChange={setOpen}>
@@ -242,14 +251,10 @@ export default function RechargeModal(props: RechargeModelProps) {
{step == 1 && <>
<div className="flex flex-col items-center gap-4">
<div className="flex flex-col items-center gap-3">
<div className="bg-gray-100 w-52 h-52 flex items-center justify-center">
<div className="bg-gray-100 size-50 flex items-center justify-center">
{payInfo ?
method === 'alipay'
? <iframe
src={payInfo.pay_url}
className="w-full h-full"
title="支付二维码"
/>
? <iframe src={payInfo.pay_url} className="w-full h-full"/>
: <canvas ref={canvas} className="w-full h-full"/>
: (
<Loader size={40} className={`animate-spin text-weak`}/>