修复用户未/授权购买套餐价格计算 & 发布v1.6.0版本
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "lanhu-web",
|
"name": "lanhu-web",
|
||||||
"version": "1.5.0",
|
"version": "1.6.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev -H 0.0.0.0 --turbopack",
|
"dev": "next dev -H 0.0.0.0 --turbopack",
|
||||||
|
|||||||
@@ -89,6 +89,14 @@ export async function payClose(props: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getPrice(props: CreateResourceReq) {
|
export async function getPrice(props: CreateResourceReq) {
|
||||||
|
return callByUser<{
|
||||||
|
price: string
|
||||||
|
actual?: string
|
||||||
|
discounted?: string
|
||||||
|
}>('/api/resource/price', props)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getPriceHome(props: CreateResourceReq) {
|
||||||
return callByDevice<{
|
return callByDevice<{
|
||||||
price: string
|
price: string
|
||||||
actual?: string
|
actual?: string
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import {useContext, useState} from 'react'
|
import {useContext, useEffect, useState} from 'react'
|
||||||
import {useRouter} from 'next/navigation'
|
import {useRouter} from 'next/navigation'
|
||||||
import {X} from 'lucide-react'
|
import {X} from 'lucide-react'
|
||||||
import {HeaderContext} from './common'
|
import {HeaderContext} from './common'
|
||||||
@@ -21,6 +21,8 @@ import h03 from '@/assets/header/help/03.svg'
|
|||||||
import {merge} from '@/lib/utils'
|
import {merge} from '@/lib/utils'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import logo from '@/assets/logo.webp'
|
import logo from '@/assets/logo.webp'
|
||||||
|
import {Product} from '@/lib/models/product'
|
||||||
|
import {listProductHome} from '@/actions/product'
|
||||||
|
|
||||||
export type MobileMenuProps = {}
|
export type MobileMenuProps = {}
|
||||||
|
|
||||||
@@ -37,7 +39,18 @@ export default function MobileMenu(props: MobileMenuProps) {
|
|||||||
ctx.setMenu(false)
|
ctx.setMenu(false)
|
||||||
router.push(href)
|
router.push(href)
|
||||||
}
|
}
|
||||||
|
const [productList, setProductList] = useState<Product[]>([])
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchProducts = async () => {
|
||||||
|
const res = await listProductHome({})
|
||||||
|
if (res.success) {
|
||||||
|
setProductList(res.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fetchProducts()
|
||||||
|
}, [])
|
||||||
|
const shortProduct = productList.find(p => p.name?.includes('短效') || p.code === 'short')
|
||||||
|
const longProduct = productList.find(p => p.name?.includes('长效') || p.code === 'long')
|
||||||
return (
|
return (
|
||||||
<div className="h-full flex flex-col bg-white">
|
<div className="h-full flex flex-col bg-white">
|
||||||
<div className="flex items-center justify-between px-4 h-16 border-b border-gray-100">
|
<div className="flex items-center justify-between px-4 h-16 border-b border-gray-100">
|
||||||
@@ -87,20 +100,24 @@ export default function MobileMenu(props: MobileMenuProps) {
|
|||||||
|
|
||||||
{productTab === 'domestic' && (
|
{productTab === 'domestic' && (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
|
{shortProduct && (
|
||||||
<ProductItem
|
<ProductItem
|
||||||
icon={prod}
|
icon={prod}
|
||||||
label="短效动态IP"
|
label="短效动态IP"
|
||||||
badge="最低4.5折"
|
badge="最低4.5折"
|
||||||
href="/product?type=short"
|
href={`/product?type=${shortProduct.code}`}
|
||||||
onNavigate={navigate}
|
onNavigate={navigate}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
{longProduct && (
|
||||||
<ProductItem
|
<ProductItem
|
||||||
icon={prod}
|
icon={prod}
|
||||||
label="长效静态IP"
|
label="长效静态IP"
|
||||||
badge="最低4.5折"
|
badge="最低4.5折"
|
||||||
href="/product?type=long"
|
href={`/product?type=${longProduct.code}`}
|
||||||
onNavigate={navigate}
|
onNavigate={navigate}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
<ProductItem
|
<ProductItem
|
||||||
icon={custom}
|
icon={custom}
|
||||||
label="优质/企业/精选IP"
|
label="优质/企业/精选IP"
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import {ReactNode, useEffect, useState} from 'react'
|
import {ReactNode, use, useEffect, useState} from 'react'
|
||||||
import {merge} from '@/lib/utils'
|
import {merge} from '@/lib/utils'
|
||||||
import {Tabs, TabsContent, TabsList, TabsTrigger} from '@/components/ui/tabs'
|
import {Tabs, TabsContent, TabsList, TabsTrigger} from '@/components/ui/tabs'
|
||||||
import LongForm from '@/components/composites/purchase/long/form'
|
import LongForm from '@/components/composites/purchase/long/form'
|
||||||
import ShortForm from '@/components/composites/purchase/short/form'
|
import ShortForm from '@/components/composites/purchase/short/form'
|
||||||
import {usePathname, useRouter, useSearchParams} from 'next/navigation'
|
import {usePathname, useRouter, useSearchParams} from 'next/navigation'
|
||||||
import SelfDesc from '@/components/features/self-desc'
|
import SelfDesc from '@/components/features/self-desc'
|
||||||
import {listProduct, ProductItem} from '@/actions/product'
|
import {listProduct, listProductHome, ProductItem} from '@/actions/product'
|
||||||
|
import {useProfileStore} from '@/components/stores/profile'
|
||||||
export type TabType = 'short' | 'long' | 'fixed' | 'custom'
|
export type TabType = 'short' | 'long' | 'fixed' | 'custom'
|
||||||
|
|
||||||
export default function Purchase() {
|
export default function Purchase() {
|
||||||
@@ -22,19 +23,21 @@ export default function Purchase() {
|
|||||||
newParams.set('type', tab)
|
newParams.set('type', tab)
|
||||||
router.push(`${path}?${newParams.toString()}`)
|
router.push(`${path}?${newParams.toString()}`)
|
||||||
}
|
}
|
||||||
|
const profile = use(useProfileStore(store => store.profile))
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchProducts = async () => {
|
const fetchProducts = async () => {
|
||||||
const res = await listProduct({})
|
const res = profile
|
||||||
|
? await listProduct({})
|
||||||
|
: await listProductHome({})
|
||||||
|
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
setProductList(res.data)
|
setProductList(res.data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fetchProducts()
|
fetchProducts()
|
||||||
}, [])
|
}, [profile])
|
||||||
|
|
||||||
const currentProduct = productList.find(item => item.code === tab)
|
|
||||||
const currentSkuList = currentProduct?.skus || []
|
|
||||||
const componentMap: Record<string, React.FC<{skuList: ProductItem['skus']}>> = {
|
const componentMap: Record<string, React.FC<{skuList: ProductItem['skus']}>> = {
|
||||||
short: ShortForm,
|
short: ShortForm,
|
||||||
long: LongForm,
|
long: LongForm,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {merge} from '@/lib/utils'
|
|||||||
import {useFormContext, useWatch} from 'react-hook-form'
|
import {useFormContext, useWatch} from 'react-hook-form'
|
||||||
import {Schema} from '@/components/composites/purchase/long/form'
|
import {Schema} from '@/components/composites/purchase/long/form'
|
||||||
import {Card} from '@/components/ui/card'
|
import {Card} from '@/components/ui/card'
|
||||||
import {getPrice} from '@/actions/resource'
|
import {getPrice, getPriceHome} from '@/actions/resource'
|
||||||
import {ExtraResp} from '@/lib/api'
|
import {ExtraResp} from '@/lib/api'
|
||||||
import {FieldPayment} from '../shared/field-payment'
|
import {FieldPayment} from '../shared/field-payment'
|
||||||
|
|
||||||
@@ -25,11 +25,13 @@ export default function Right() {
|
|||||||
actual: '0.00',
|
actual: '0.00',
|
||||||
discounted: '0.00',
|
discounted: '0.00',
|
||||||
})
|
})
|
||||||
|
const profile = use(useProfileStore(store => store.profile))
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const price = async () => {
|
const price = async () => {
|
||||||
try {
|
try {
|
||||||
const resp = await getPrice({
|
const resp = profile
|
||||||
|
? await getPrice({
|
||||||
type: 2,
|
type: 2,
|
||||||
long: {
|
long: {
|
||||||
live: Number(live),
|
live: Number(live),
|
||||||
@@ -37,6 +39,14 @@ export default function Right() {
|
|||||||
quota: mode === '1' ? Number(dailyLimit) : Number(quota),
|
quota: mode === '1' ? Number(dailyLimit) : Number(quota),
|
||||||
expire: mode === '1' ? Number(expire) : undefined,
|
expire: mode === '1' ? Number(expire) : undefined,
|
||||||
},
|
},
|
||||||
|
}) : await getPriceHome({
|
||||||
|
type: 1,
|
||||||
|
short: {
|
||||||
|
live: Number(live),
|
||||||
|
mode: Number(mode),
|
||||||
|
quota: mode === '1' ? Number(dailyLimit) : Number(quota),
|
||||||
|
expire: mode === '1' ? Number(expire) : undefined,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
if (!resp.success) {
|
if (!resp.success) {
|
||||||
throw new Error('获取价格失败')
|
throw new Error('获取价格失败')
|
||||||
@@ -57,7 +67,7 @@ export default function Right() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
price()
|
price()
|
||||||
}, [dailyLimit, expire, live, quota, mode])
|
}, [dailyLimit, expire, live, quota, mode, profile])
|
||||||
|
|
||||||
const {price, actual: discountedPrice = ''} = priceData
|
const {price, actual: discountedPrice = ''} = priceData
|
||||||
// 计算总折扣价(原价 - 实付价格)
|
// 计算总折扣价(原价 - 实付价格)
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export default function ShortForm({skuList}: {skuList: ProductItem['skus']}) {
|
|||||||
return (
|
return (
|
||||||
<Form form={form} className="flex flex-col lg:flex-row gap-4">
|
<Form form={form} className="flex flex-col lg:flex-row gap-4">
|
||||||
<Center {...{priceMap, liveList, expireList}}/>
|
<Center {...{priceMap, liveList, expireList}}/>
|
||||||
<Right {...{skuList, priceMap}}/>
|
<Right/>
|
||||||
</Form>
|
</Form>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ import {merge} from '@/lib/utils'
|
|||||||
import Pay from '@/components/composites/purchase/pay'
|
import Pay from '@/components/composites/purchase/pay'
|
||||||
import {useFormContext, useWatch} from 'react-hook-form'
|
import {useFormContext, useWatch} from 'react-hook-form'
|
||||||
import {Card} from '@/components/ui/card'
|
import {Card} from '@/components/ui/card'
|
||||||
import {getPrice} from '@/actions/resource'
|
import {getPrice, getPriceHome} from '@/actions/resource'
|
||||||
import {ExtraResp} from '@/lib/api'
|
import {ExtraResp} from '@/lib/api'
|
||||||
import {FieldPayment} from '../shared/field-payment'
|
import {FieldPayment} from '../shared/field-payment'
|
||||||
import {ProductItem} from '@/actions/product'
|
import {ProductItem} from '@/actions/product'
|
||||||
|
|
||||||
export default function Right({skuList}: {skuList: ProductItem['skus']}) {
|
export default function Right() {
|
||||||
const {control} = useFormContext<Schema>()
|
const {control} = useFormContext<Schema>()
|
||||||
const method = useWatch({control, name: 'pay_type'})
|
const method = useWatch({control, name: 'pay_type'})
|
||||||
const live = useWatch({control, name: 'live'})
|
const live = useWatch({control, name: 'live'})
|
||||||
@@ -26,11 +26,13 @@ export default function Right({skuList}: {skuList: ProductItem['skus']}) {
|
|||||||
actual: '0.00',
|
actual: '0.00',
|
||||||
discounted: '0.00',
|
discounted: '0.00',
|
||||||
})
|
})
|
||||||
|
const profile = use(useProfileStore(store => store.profile))
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const price = async () => {
|
const price = async () => {
|
||||||
try {
|
try {
|
||||||
const priceResponse = await getPrice({
|
const priceResponse = profile
|
||||||
|
? await getPrice({
|
||||||
type: 1,
|
type: 1,
|
||||||
short: {
|
short: {
|
||||||
live: Number(live),
|
live: Number(live),
|
||||||
@@ -39,6 +41,16 @@ export default function Right({skuList}: {skuList: ProductItem['skus']}) {
|
|||||||
expire: mode === '1' ? Number(expire) : undefined,
|
expire: mode === '1' ? Number(expire) : undefined,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
: await getPriceHome({
|
||||||
|
type: 1,
|
||||||
|
short: {
|
||||||
|
live: Number(live),
|
||||||
|
mode: Number(mode),
|
||||||
|
quota: mode === '1' ? Number(dailyLimit) : Number(quota),
|
||||||
|
expire: mode === '1' ? Number(expire) : undefined,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
if (!priceResponse.success) {
|
if (!priceResponse.success) {
|
||||||
throw new Error('获取价格失败')
|
throw new Error('获取价格失败')
|
||||||
}
|
}
|
||||||
@@ -60,7 +72,7 @@ export default function Right({skuList}: {skuList: ProductItem['skus']}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
price()
|
price()
|
||||||
}, [expire, live, quota, mode, dailyLimit])
|
}, [expire, live, quota, mode, dailyLimit, profile])
|
||||||
|
|
||||||
const {price, actual: discountedPrice = ''} = priceData
|
const {price, actual: discountedPrice = ''} = priceData
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user