240 lines
7.9 KiB
TypeScript
240 lines
7.9 KiB
TypeScript
'use client'
|
|
import {Suspense, use, useContext, useEffect, useMemo, useState} from 'react'
|
|
import {PurchaseFormContext} from '@/components/composites/purchase/short/form'
|
|
import {RadioGroup} from '@/components/ui/radio-group'
|
|
import {FormField} from '@/components/ui/form'
|
|
import FormOption from '@/components/composites/purchase/option'
|
|
import Image from 'next/image'
|
|
import alipay from '../_assets/alipay.svg'
|
|
import wechat from '../_assets/wechat.svg'
|
|
import balance from '../_assets/balance.svg'
|
|
import {useProfileStore} from '@/components/stores/profile'
|
|
import RechargeModal from '@/components/composites/recharge'
|
|
import Pay from '@/components/composites/purchase/pay'
|
|
import {buttonVariants} from '@/components/ui/button'
|
|
import Link from 'next/link'
|
|
import {merge} from '@/lib/utils'
|
|
import {useFormContext, useWatch} from 'react-hook-form'
|
|
import {Schema} from '@/components/composites/purchase/long/form'
|
|
import {Card} from '@/components/ui/card'
|
|
import {getPrice, CreateResourceReq} from '@/actions/resource'
|
|
|
|
interface PriceData {
|
|
price: string
|
|
discounted_price?: string
|
|
discounted?: number
|
|
}
|
|
|
|
export default function Right() {
|
|
const {control} = useFormContext<Schema>()
|
|
const method = useWatch({control, name: 'pay_type'})
|
|
const mode = useWatch({control, name: 'type'})
|
|
const live = useWatch({control, name: 'live'})
|
|
const quota = useWatch({control, name: 'quota'})
|
|
const expire = useWatch({control, name: 'expire'})
|
|
const dailyLimit = useWatch({control, name: 'daily_limit'})
|
|
const [priceData, setPriceData] = useState<PriceData>({
|
|
price: '0.00',
|
|
discounted_price: '0.00',
|
|
discounted: 0,
|
|
})
|
|
|
|
useEffect(() => {
|
|
const price = async () => {
|
|
const params: CreateResourceReq = {
|
|
type: 2,
|
|
long: {
|
|
live: Number(live),
|
|
mode: Number(mode),
|
|
quota: Number(mode) === 1 ? Number(dailyLimit) : Number(quota),
|
|
expire: Number(mode) === 1 ? Number(expire) : undefined,
|
|
},
|
|
}
|
|
try {
|
|
const priceValue = await getPrice(params)
|
|
|
|
if (priceValue.success && priceValue.data?.price) {
|
|
const data: PriceData = priceValue.data
|
|
setPriceData({
|
|
price: data.price,
|
|
discounted_price: data.discounted_price ?? data.price ?? '',
|
|
discounted: data.discounted,
|
|
})
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('获取价格失败:', error)
|
|
setPriceData({
|
|
price: '0.00',
|
|
discounted_price: '0.00',
|
|
discounted: 0,
|
|
})
|
|
}
|
|
}
|
|
price()
|
|
}, [dailyLimit, expire, live, quota, mode])
|
|
|
|
const {price, discounted_price: discountedPrice = '', discounted} = priceData
|
|
|
|
return (
|
|
<Card className={merge(
|
|
`flex-none basis-90 p-6 flex flex-col gap-6 relative`,
|
|
)}>
|
|
<h3>订单详情</h3>
|
|
<ul className="flex flex-col gap-3">
|
|
<li className="flex justify-between items-center">
|
|
<span className="text-sm text-gray-500">套餐名称</span>
|
|
<span className="text-sm">
|
|
{mode === '2' ? `包量套餐` : `包时套餐`}
|
|
</span>
|
|
</li>
|
|
<li className="flex justify-between items-center">
|
|
<span className="text-sm text-gray-500">IP 时效</span>
|
|
<span className="text-sm">
|
|
{live}
|
|
{' '}
|
|
小时
|
|
</span>
|
|
</li>
|
|
{mode === '2' ? (
|
|
<>
|
|
<li className="flex justify-between items-center">
|
|
<span className="text-sm text-gray-500">购买 IP 量</span>
|
|
<span className="text-sm">
|
|
{quota}
|
|
个
|
|
</span>
|
|
</li>
|
|
<li className="flex justify-between items-center">
|
|
<span className="text-sm text-gray-500">实价</span>
|
|
<span className="text-sm">
|
|
¥{price}
|
|
</span>
|
|
</li>
|
|
</>
|
|
) : (
|
|
<>
|
|
<li className="flex justify-between items-center">
|
|
<span className="text-sm text-gray-500">套餐时长</span>
|
|
<span className="text-sm">
|
|
{expire}
|
|
天
|
|
</span>
|
|
</li>
|
|
<li className="flex justify-between items-center">
|
|
<span className="text-sm text-gray-500">每日限额</span>
|
|
<span className="text-sm">
|
|
{dailyLimit}
|
|
个
|
|
</span>
|
|
</li>
|
|
<li className="flex justify-between items-center">
|
|
<span className="text-sm text-gray-500">原价</span>
|
|
<span className="text-sm">
|
|
¥{price}
|
|
</span>
|
|
</li>
|
|
{discounted === 1 ? '' : (
|
|
<li className="flex justify-between items-center">
|
|
<span className="text-sm text-gray-500">总折扣</span>
|
|
<span className="text-sm">
|
|
-¥{discounted}
|
|
</span>
|
|
</li>
|
|
)}
|
|
</>
|
|
)}
|
|
</ul>
|
|
<div className="border-b border-gray-200"></div>
|
|
<p className="flex justify-between items-center">
|
|
<span>实付价格</span>
|
|
<span className="text-xl text-orange-500">
|
|
¥{discountedPrice}
|
|
</span>
|
|
</p>
|
|
<Suspense>
|
|
<BalanceOrLogin {...{method, discountedPrice, mode, live, quota, expire, dailyLimit}}/>
|
|
</Suspense>
|
|
</Card>
|
|
)
|
|
}
|
|
|
|
function BalanceOrLogin(props: {
|
|
method: 'wechat' | 'alipay' | 'balance'
|
|
discountedPrice: string
|
|
mode: string
|
|
live: string
|
|
quota: number
|
|
expire: string
|
|
dailyLimit: number
|
|
}) {
|
|
const profile = use(useProfileStore(store => store.profile))
|
|
return profile ? (
|
|
<>
|
|
<FormField name="pay_type" label="支付方式" className="flex flex-col gap-6">
|
|
{({id, field}) => (
|
|
<RadioGroup
|
|
id={id}
|
|
defaultValue={field.value}
|
|
onValueChange={field.onChange}
|
|
className="flex flex-col gap-3">
|
|
|
|
<div className="w-full p-3 flex flex-col gap-4 bg-gray-100 rounded-md">
|
|
<p className="flex items-center gap-3">
|
|
<Image src={balance} alt="余额icon"/>
|
|
<span className="text-sm text-gray-500">账户余额</span>
|
|
</p>
|
|
<p className="flex justify-between items-center">
|
|
<span className="text-xl">{profile?.balance}</span>
|
|
<RechargeModal/>
|
|
</p>
|
|
</div>
|
|
|
|
<FormOption
|
|
id={`${id}-balance`}
|
|
value="balance"
|
|
compare={field.value}
|
|
className="p-3 w-full flex-row gap-2 justify-center">
|
|
<Image src={balance} alt="余额 icon"/>
|
|
<span>余额</span>
|
|
</FormOption>
|
|
<FormOption
|
|
id={`${id}-wechat`}
|
|
value="wechat"
|
|
compare={field.value}
|
|
className="p-3 w-full flex-row gap-2 justify-center">
|
|
<Image src={wechat} alt="微信 logo"/>
|
|
<span>微信</span>
|
|
</FormOption>
|
|
<FormOption
|
|
id={`${id}-alipay`}
|
|
value="alipay"
|
|
compare={field.value}
|
|
className="p-3 w-full flex-row gap-2 justify-center">
|
|
<Image src={alipay} alt="支付宝 logo"/>
|
|
<span>支付宝</span>
|
|
</FormOption>
|
|
</RadioGroup>
|
|
)}
|
|
</FormField>
|
|
<Pay
|
|
method={props.method}
|
|
balance={profile.balance}
|
|
amount={props.discountedPrice}
|
|
resource={{
|
|
type: 2,
|
|
long: {
|
|
mode: Number(props.mode),
|
|
live: Number(props.live),
|
|
expire: Number(props.expire),
|
|
quota: props.mode === '1' ? props.dailyLimit : props.quota,
|
|
},
|
|
}}/>
|
|
</>
|
|
) : (
|
|
<Link href="/login" className={buttonVariants()}>
|
|
登录后支付
|
|
</Link>
|
|
)
|
|
}
|