完善微信支付二维码生成机制
This commit is contained in:
@@ -5,7 +5,7 @@ import alipay from '../_assets/alipay.svg'
|
|||||||
import wechat from '../_assets/wechat.svg'
|
import wechat from '../_assets/wechat.svg'
|
||||||
import balance from '../_assets/balance.svg'
|
import balance from '../_assets/balance.svg'
|
||||||
import Image from 'next/image'
|
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 {StoreContext, useProfileStore} from '@/components/providers/StoreProvider'
|
||||||
import {Alert, AlertDescription} from '@/components/ui/alert'
|
import {Alert, AlertDescription} from '@/components/ui/alert'
|
||||||
import {
|
import {
|
||||||
@@ -38,6 +38,14 @@ export default function Pay(props: PayProps) {
|
|||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const [payInfo, setPayInfo] = useState<CreateResourceResp | undefined>()
|
const [payInfo, setPayInfo] = useState<CreateResourceResp | undefined>()
|
||||||
const canvas = useRef<HTMLCanvasElement>(null)
|
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 () => {
|
const onOpen = async () => {
|
||||||
setOpen(true)
|
setOpen(true)
|
||||||
@@ -48,12 +56,12 @@ export default function Pay(props: PayProps) {
|
|||||||
|
|
||||||
let resp: ApiResponse<CreateResourceResp>
|
let resp: ApiResponse<CreateResourceResp>
|
||||||
switch (props.method) {
|
switch (props.method) {
|
||||||
case 'alipay':
|
case 'alipay':
|
||||||
resp = await prepareResourceByAlipay(props.resource)
|
resp = await prepareResourceByAlipay(props.resource)
|
||||||
break
|
break
|
||||||
case 'wechat':
|
case 'wechat':
|
||||||
resp = await prepareResourceByWechat(props.resource)
|
resp = await prepareResourceByWechat(props.resource)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (!resp.success) {
|
if (!resp.success) {
|
||||||
toast.error(`创建订单失败: ${resp.message}`)
|
toast.error(`创建订单失败: ${resp.message}`)
|
||||||
@@ -62,7 +70,6 @@ export default function Pay(props: PayProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setPayInfo(resp.data)
|
setPayInfo(resp.data)
|
||||||
await qrcode.toCanvas(canvas.current, resp.data.pay_url)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@@ -70,19 +77,19 @@ export default function Pay(props: PayProps) {
|
|||||||
let resp: ApiResponse
|
let resp: ApiResponse
|
||||||
try {
|
try {
|
||||||
switch (props.method) {
|
switch (props.method) {
|
||||||
case 'alipay':
|
case 'alipay':
|
||||||
resp = await createResourceByAlipay({
|
resp = await createResourceByAlipay({
|
||||||
trade_no: payInfo!.trade_no,
|
trade_no: payInfo!.trade_no,
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
case 'wechat':
|
case 'wechat':
|
||||||
resp = await createResourceByWechat({
|
resp = await createResourceByWechat({
|
||||||
trade_no: payInfo!.trade_no,
|
trade_no: payInfo!.trade_no,
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
case 'balance':
|
case 'balance':
|
||||||
resp = await createResourceByBalance(props.resource)
|
resp = await createResourceByBalance(props.resource)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!resp.success) {
|
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-4">
|
||||||
<div className="flex flex-col items-center gap-3">
|
<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 ? (
|
{payInfo ? (
|
||||||
props.method === 'alipay'
|
props.method === 'alipay'
|
||||||
? <iframe
|
? <iframe src={payInfo.pay_url} className="w-full h-full" />
|
||||||
src={payInfo.pay_url}
|
|
||||||
className="w-full h-full"
|
|
||||||
title="支付二维码"
|
|
||||||
/>
|
|
||||||
: <canvas ref={canvas} className="w-full h-full"/>
|
: <canvas ref={canvas} className="w-full h-full"/>
|
||||||
) : (
|
) : (
|
||||||
<Loader size={40} className={`animate-spin text-weak`}/>
|
<Loader size={40} className={`animate-spin text-weak`}/>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import {zodResolver} from '@hookform/resolvers/zod'
|
|||||||
import {toast} from 'sonner'
|
import {toast} from 'sonner'
|
||||||
import wechat from '@/components/composites/purchase/_assets/wechat.svg'
|
import wechat from '@/components/composites/purchase/_assets/wechat.svg'
|
||||||
import alipay from '@/components/composites/purchase/_assets/alipay.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 {Loader} from 'lucide-react'
|
||||||
import {RechargeByAlipay, RechargeByAlipayConfirm, RechargeByWechat, RechargeByWechatConfirm} from '@/actions/user'
|
import {RechargeByAlipay, RechargeByAlipayConfirm, RechargeByWechat, RechargeByWechatConfirm} from '@/actions/user'
|
||||||
import * as qrcode from 'qrcode'
|
import * as qrcode from 'qrcode'
|
||||||
@@ -52,50 +52,60 @@ export default function RechargeModal(props: RechargeModelProps) {
|
|||||||
const method = form.watch('method')
|
const method = form.watch('method')
|
||||||
const amount = form.watch('amount')
|
const amount = form.watch('amount')
|
||||||
|
|
||||||
const canvas = useRef<HTMLCanvasElement>(null)
|
const [step, setStep] = useState(0)
|
||||||
const [payInfo, setPayInfo] = useState<{
|
const [payInfo, setPayInfo] = useState<{
|
||||||
trade_no: string
|
trade_no: string
|
||||||
pay_url: 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 refreshProfile = useProfileStore(store => store.refreshProfile)
|
||||||
|
|
||||||
const createRecharge = async (data: Schema) => {
|
const createRecharge = async (data: Schema) => {
|
||||||
try {
|
try {
|
||||||
switch (data.method) {
|
switch (data.method) {
|
||||||
case 'alipay':
|
case 'alipay':
|
||||||
const aliRes = await RechargeByAlipay({
|
const aliRes = await RechargeByAlipay({
|
||||||
amount: data.amount,
|
amount: data.amount,
|
||||||
|
})
|
||||||
|
if (aliRes.success) {
|
||||||
|
setStep(1)
|
||||||
|
setPayInfo(aliRes.data)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
toast.error(`创建订单失败`, {
|
||||||
|
description: aliRes.message,
|
||||||
})
|
})
|
||||||
if (aliRes.success) {
|
}
|
||||||
setStep(1)
|
break
|
||||||
setPayInfo(aliRes.data)
|
case 'wechat':
|
||||||
}
|
const weRes = await RechargeByWechat({
|
||||||
else {
|
amount: data.amount,
|
||||||
toast.error(`充值失败`, {
|
})
|
||||||
description: aliRes.message,
|
if (weRes.success) {
|
||||||
})
|
setStep(1)
|
||||||
}
|
setPayInfo(weRes.data)
|
||||||
break
|
}
|
||||||
case 'wechat':
|
else {
|
||||||
const weRes = await RechargeByWechat({
|
toast.error(`创建订单失败`, {
|
||||||
amount: data.amount,
|
description: weRes.message,
|
||||||
})
|
})
|
||||||
if (weRes.success) {
|
}
|
||||||
setStep(1)
|
break
|
||||||
setPayInfo(weRes.data)
|
|
||||||
await qrcode.toCanvas(canvas.current, weRes.data.pay_url)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
toast.error(`充值失败`, {
|
|
||||||
description: weRes.message,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
toast.error(`充值失败`, {
|
console.error(e)
|
||||||
|
toast.error(`创建订单失败`, {
|
||||||
description: (e as Error).message,
|
description: (e as Error).message,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -110,22 +120,22 @@ export default function RechargeModal(props: RechargeModelProps) {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
switch (method) {
|
switch (method) {
|
||||||
case 'alipay':
|
case 'alipay':
|
||||||
const aliRes = await RechargeByAlipayConfirm({
|
const aliRes = await RechargeByAlipayConfirm({
|
||||||
trade_no: payInfo.trade_no,
|
trade_no: payInfo.trade_no,
|
||||||
})
|
})
|
||||||
if (!aliRes.success) {
|
if (!aliRes.success) {
|
||||||
throw new Error(aliRes.message)
|
throw new Error(aliRes.message)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'wechat':
|
case 'wechat':
|
||||||
const weRes = await RechargeByWechatConfirm({
|
const weRes = await RechargeByWechatConfirm({
|
||||||
trade_no: payInfo.trade_no,
|
trade_no: payInfo.trade_no,
|
||||||
})
|
})
|
||||||
if (!weRes.success) {
|
if (!weRes.success) {
|
||||||
throw new Error(weRes.message)
|
throw new Error(weRes.message)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
toast.success(`充值成功`)
|
toast.success(`充值成功`)
|
||||||
closeDialog()
|
closeDialog()
|
||||||
@@ -144,7 +154,6 @@ export default function RechargeModal(props: RechargeModelProps) {
|
|||||||
setStep(0)
|
setStep(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
const [step, setStep] = useState(0)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={open} onOpenChange={setOpen}>
|
<Dialog open={open} onOpenChange={setOpen}>
|
||||||
@@ -242,14 +251,10 @@ export default function RechargeModal(props: RechargeModelProps) {
|
|||||||
{step == 1 && <>
|
{step == 1 && <>
|
||||||
<div className="flex flex-col items-center gap-4">
|
<div className="flex flex-col items-center gap-4">
|
||||||
<div className="flex flex-col items-center gap-3">
|
<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 ?
|
{payInfo ?
|
||||||
method === 'alipay'
|
method === 'alipay'
|
||||||
? <iframe
|
? <iframe src={payInfo.pay_url} className="w-full h-full"/>
|
||||||
src={payInfo.pay_url}
|
|
||||||
className="w-full h-full"
|
|
||||||
title="支付二维码"
|
|
||||||
/>
|
|
||||||
: <canvas ref={canvas} className="w-full h-full"/>
|
: <canvas ref={canvas} className="w-full h-full"/>
|
||||||
: (
|
: (
|
||||||
<Loader size={40} className={`animate-spin text-weak`}/>
|
<Loader size={40} className={`animate-spin text-weak`}/>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import {NextRequest, NextResponse} from 'next/server'
|
import {NextRequest, NextResponse} from 'next/server'
|
||||||
import {refreshAuth} from '@/actions/auth'
|
import {refreshAuth} from '@/actions/auth'
|
||||||
import { UnauthorizedError } from './lib/api'
|
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
matcher: [
|
matcher: [
|
||||||
|
|||||||
Reference in New Issue
Block a user