更新了购买套餐里的充值和立即支付的传参,增加我的账单模块待支付链接跳转和弹窗

This commit is contained in:
Eamon-meng
2025-06-18 19:05:38 +08:00
parent 36b17f1bf2
commit ba7d22168d
9 changed files with 662 additions and 136 deletions

View File

@@ -17,15 +17,20 @@ 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 {useEffect, useRef, useState} from 'react'
import {useEffect, useMemo, useRef, useState} from 'react'
import {Loader} from 'lucide-react'
import {RechargeByAlipay, RechargeByAlipayConfirm, RechargeByWechat, RechargeByWechatConfirm} from '@/actions/user'
import {RechargeByPay, RechargeByAlipayConfirm, RechargeByWechat, RechargeByWechatConfirm} from '@/actions/user'
import * as qrcode from 'qrcode'
import {useProfileStore} from '@/components/providers/StoreProvider'
import {merge} from '@/lib/utils'
import {
Platform,
PAYMENT_METHODS,
usePlatformType,
} from '@/lib/models/trade'
const schema = zod.object({
method: zod.enum(['alipay', 'wechat']),
method: zod.enum(['alipay', 'wechat', 'sft', 'sftAlipay', 'sftWeChat']),
amount: zod.number().min(1, '充值金额必须大于 0'),
})
@@ -39,7 +44,7 @@ export type RechargeModelProps = {
export default function RechargeModal(props: RechargeModelProps) {
const [open, setOpen] = useState(false)
const platform = usePlatformType()
const form = useForm<Schema>({
resolver: zodResolver(schema),
defaultValues: {
@@ -57,55 +62,66 @@ export default function RechargeModal(props: RechargeModelProps) {
pay_url: string
}>()
// 获取当前平台可用的支付方法
const availableMethods = useMemo(() => {
console.log(PAYMENT_METHODS, 'PAYMENT_METHODS')
return Object.values(PAYMENT_METHODS)
.filter(method => method.availablePlatforms.includes(platform))
.map(method => ({
value: method.formValue,
name: method.name,
icon: method.icon,
}))
}, [platform])
const canvas = useRef<HTMLCanvasElement>(null)
useEffect(() => {
if (canvas.current && payInfo) {
qrcode.toCanvas(canvas.current, payInfo.pay_url, {
width: 200,
margin: 0,
})
}
}, [payInfo])
console.log('Canvas ref:', canvas.current)
if (!payInfo || !canvas.current || method.includes('alipay')) return
qrcode.toCanvas(canvas.current, payInfo.pay_url, {
width: 200,
margin: 0,
})
}, [payInfo, method])
const refreshProfile = useProfileStore(store => store.refreshProfile)
const createRecharge = async (data: Schema) => {
try {
switch (data.method) {
case 'alipay':
const aliRes = await RechargeByAlipay({
amount: data.amount.toString(),
})
if (aliRes.success) {
setStep(1)
setPayInfo(aliRes.data)
}
else {
toast.error(`创建订单失败`, {
description: aliRes.message,
})
}
break
case 'wechat':
const weRes = await RechargeByWechat({
amount: data.amount.toString(),
})
if (weRes.success) {
setStep(1)
setPayInfo(weRes.data)
}
else {
toast.error(`创建订单失败`, {
description: weRes.message,
})
}
break
const paymentMethod = Object.entries(PAYMENT_METHODS).find(
([_, config]) => config.formValue === data.method,
)
console.log(paymentMethod, 'paymentMethod')
if (!paymentMethod) {
throw new Error('无效的支付方式')
}
const resp = {
amount: data.amount.toString(),
platform: platform,
method: paymentMethod[1].actualMethod,
}
console.log(resp, 'resp')
// const result = await RechargeByPay({
// amount: data.amount.toString(),
// platform: platform,
// method: parseInt(paymentMethod[0]) as PaymentMethod,
// })
const result = await RechargeByPay(resp)
console.log(result, 'result')
if (result.success) {
setStep(1)
setPayInfo(result.data)
}
else {
throw new Error(result.message)
}
}
catch (e) {
console.error(e)
toast.error(`创建订单失败`, {
description: (e as Error).message,
catch (error) {
toast.error('创建订单失败', {
description: error instanceof Error ? error.message : '未知错误',
})
}
}
@@ -151,6 +167,7 @@ export default function RechargeModal(props: RechargeModelProps) {
setOpen(false)
setPayInfo(undefined)
setStep(0)
form.reset()
}
return (
@@ -159,7 +176,7 @@ export default function RechargeModal(props: RechargeModelProps) {
<Button theme="accent" type="button" className={merge(`px-4 h-8`, props.classNames?.trigger)}></Button>
</DialogTrigger>
<DialogContent>
<DialogContent className={platform === Platform.Mobile ? 'max-w-[95vw]' : 'max-w-md'}>
<DialogTitle className="flex flex-col gap-2">
</DialogTitle>
@@ -235,22 +252,18 @@ export default function RechargeModal(props: RechargeModelProps) {
defaultValue={field.value}
onValueChange={field.onChange}
className="flex gap-2">
<FormOption
id={`${id}-alipay`}
value="alipay"
compare={field.value}
className="flex-1 flex-row justify-center items-center">
<Image src={alipay} alt="支付宝 logo" className="w-6 h-6"/>
<span></span>
</FormOption>
<FormOption
id={`${id}-wechat`}
value="wechat"
compare={field.value}
className="flex-1 flex-row justify-center items-center">
<Image src={wechat} alt="微信 logo" className="w-6 h-6"/>
<span></span>
</FormOption>
{availableMethods.map(({value, name, icon}) => (
<FormOption
key={value}
id={`${id}-${value}`}
value={value}
compare={field.value}
className="flex-1 flex-row justify-center items-center"
>
{icon && <Image src={icon} alt={`${name} logo`} className="w-6 h-6"/>}
<span>{name}</span>
</FormOption>
))}
</RadioGroup>
)}
</FormField>