更新底部服务保障跳转链接 & 购买套餐添加折扣字段 & 用户总览添加长效动态图表
This commit is contained in:
@@ -19,7 +19,7 @@ export default function Footer(props: FooterProps) {
|
|||||||
<p className="text-sm text-gray-400">QQ: 70177252</p>
|
<p className="text-sm text-gray-400">QQ: 70177252</p>
|
||||||
<h3 className="hidden sm:block">服务保障</h3>
|
<h3 className="hidden sm:block">服务保障</h3>
|
||||||
<a
|
<a
|
||||||
href="https://weixin.qq.com/r/mp/AxYMFAzErFHTrUh390MR"
|
href="https://work.weixin.qq.com/kfid/kfc458bc58e79e5093f"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="text-sm text-gray-400 hidden sm:block cursor-pointer hover:text-white transition-colors"
|
className="text-sm text-gray-400 hidden sm:block cursor-pointer hover:text-white transition-colors"
|
||||||
@@ -27,7 +27,7 @@ export default function Footer(props: FooterProps) {
|
|||||||
售前服务
|
售前服务
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
href="https://weixin.qq.com/r/mp/AxYMFAzErFHTrUh390MR"
|
href="https://work.weixin.qq.com/kfid/kfc458bc58e79e5093f"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="text-sm text-gray-400 hidden sm:block cursor-pointer hover:text-white transition-colors"
|
className="text-sm text-gray-400 hidden sm:block cursor-pointer hover:text-white transition-colors"
|
||||||
@@ -41,7 +41,7 @@ export default function Footer(props: FooterProps) {
|
|||||||
items={[
|
items={[
|
||||||
{name: `产品订购`, href: `/product`},
|
{name: `产品订购`, href: `/product`},
|
||||||
{name: `获取代理`, href: `/collect`},
|
{name: `获取代理`, href: `/collect`},
|
||||||
{name: `帮助中心`, href: `/docs`},
|
{name: `帮助中心`, href: `/docs/faq-general`},
|
||||||
{name: `企业服务`, href: `/custom`},
|
{name: `企业服务`, href: `/custom`},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
@@ -56,14 +56,14 @@ export default function Footer(props: FooterProps) {
|
|||||||
<SiteNavList
|
<SiteNavList
|
||||||
title="使用案例"
|
title="使用案例"
|
||||||
items={[
|
items={[
|
||||||
{name: `数据抓取`, href: `/data-capture`},
|
{name: `数据采集`, href: `/data-capture`},
|
||||||
{name: `媒体矩阵`, href: `#`},
|
{name: `电商运营`, href: `/e-commerce`},
|
||||||
{name: `广告验证`, href: `#`},
|
{name: `市场调研`, href: `/market-research`},
|
||||||
{name: `价格监控`, href: `#`},
|
{name: `SEO优化`, href: `/seo-optimization`},
|
||||||
{name: `市场调研`, href: `#`},
|
{name: `社交媒体`, href: `/social-media`},
|
||||||
{name: `金融数据`, href: `#`},
|
{name: `广告投放`, href: `/advertising`},
|
||||||
{name: `SEO优化`, href: `#`},
|
{name: `账号管理`, href: `/account-management`},
|
||||||
{name: `网站测试`, href: `#`},
|
{name: `网络测试`, href: `/network-testing`},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<SiteNavList
|
<SiteNavList
|
||||||
|
|||||||
@@ -123,8 +123,7 @@ export default function Charts({initialData}: ChartsProps) {
|
|||||||
{submittedData && <DashboardChart data={submittedData}/>}
|
{submittedData && <DashboardChart data={submittedData}/>}
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
<TabsContent value="static" className="flex flex-col items-center justify-center gap-2">
|
<TabsContent value="static" className="flex flex-col items-center justify-center gap-2">
|
||||||
<Image alt="coming soon" src={soon}/>
|
<LongChart/>
|
||||||
<p>敬请期待</p>
|
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
@@ -184,3 +183,33 @@ function DashboardChart(props: DashboardChartProps) {
|
|||||||
</ChartContainer>
|
</ChartContainer>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function LongChart() {
|
||||||
|
return (
|
||||||
|
<ChartContainer config={config} className="w-full h-full">
|
||||||
|
<AreaChart margin={{top: 0, right: 20, left: 0, bottom: 0}}>
|
||||||
|
<CartesianGrid vertical={false}/>
|
||||||
|
<XAxis
|
||||||
|
dataKey="formattedTime"
|
||||||
|
tickLine={false}
|
||||||
|
/>
|
||||||
|
<YAxis tickLine={false}/>
|
||||||
|
<Tooltip
|
||||||
|
animationDuration={100}
|
||||||
|
// labelFormatter={value => `日期: ${chartData.find(item => item.formattedTime === value)?.fullDate || value}`}
|
||||||
|
formatter={value => [`${value}`, '套餐使用量']}
|
||||||
|
/>
|
||||||
|
<Area
|
||||||
|
type="monotone"
|
||||||
|
dataKey="count"
|
||||||
|
stroke="#8884d8"
|
||||||
|
fill="#8884d8"
|
||||||
|
fillOpacity={0.2}
|
||||||
|
strokeWidth={2}
|
||||||
|
name="套餐使用量"
|
||||||
|
/>
|
||||||
|
<Legend/>
|
||||||
|
</AreaChart>
|
||||||
|
</ChartContainer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ 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 FixedForm from '@/components/composites/purchase/fixed/form'
|
|
||||||
import Custom from '@/components/composites/purchase/custom/page'
|
|
||||||
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'
|
||||||
export type TabType = 'short' | 'long' | 'fixed' | 'custom'
|
export type TabType = 'short' | 'long' | 'fixed' | 'custom'
|
||||||
|
|||||||
@@ -19,6 +19,12 @@ import {Schema} from '@/components/composites/purchase/long/form'
|
|||||||
import {Card} from '@/components/ui/card'
|
import {Card} from '@/components/ui/card'
|
||||||
import {getPrice, CreateResourceReq} from '@/actions/resource'
|
import {getPrice, CreateResourceReq} from '@/actions/resource'
|
||||||
|
|
||||||
|
interface PriceData {
|
||||||
|
price: string
|
||||||
|
discounted_price?: string
|
||||||
|
discounted?: number
|
||||||
|
}
|
||||||
|
|
||||||
export default function Right() {
|
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'})
|
||||||
@@ -27,7 +33,11 @@ export default function Right() {
|
|||||||
const quota = useWatch({control, name: 'quota'})
|
const quota = useWatch({control, name: 'quota'})
|
||||||
const expire = useWatch({control, name: 'expire'})
|
const expire = useWatch({control, name: 'expire'})
|
||||||
const dailyLimit = useWatch({control, name: 'daily_limit'})
|
const dailyLimit = useWatch({control, name: 'daily_limit'})
|
||||||
const [price, setPrice] = useState<string>('')
|
const [priceData, setPriceData] = useState<PriceData>({
|
||||||
|
price: '0.00',
|
||||||
|
discounted_price: '0.00',
|
||||||
|
discounted: 0,
|
||||||
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const price = async () => {
|
const price = async () => {
|
||||||
@@ -42,17 +52,31 @@ export default function Right() {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const priceValue = await getPrice(params)
|
const priceValue = await getPrice(params)
|
||||||
|
console.log(priceValue, 'priceValue')
|
||||||
|
|
||||||
if (priceValue.success && priceValue.data?.price) {
|
if (priceValue.success && priceValue.data?.price) {
|
||||||
setPrice(priceValue.data.price)
|
const data: PriceData = priceValue.data
|
||||||
|
setPriceData({
|
||||||
|
price: data.price,
|
||||||
|
discounted_price: data.discounted_price ?? data.price ?? '',
|
||||||
|
discounted: data.discounted,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error('获取价格失败:', error)
|
console.error('获取价格失败:', error)
|
||||||
setPrice('0.00')
|
setPriceData({
|
||||||
|
price: '0.00',
|
||||||
|
discounted_price: '0.00',
|
||||||
|
discounted: 0,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
price()
|
price()
|
||||||
}, [dailyLimit, expire, live, quota, mode])
|
}, [dailyLimit, expire, live, quota, mode])
|
||||||
|
|
||||||
|
const {price, discounted_price: discountedPrice = '', discounted} = priceData
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className={merge(
|
<Card className={merge(
|
||||||
`flex-none basis-90 p-6 flex flex-col gap-6 relative`,
|
`flex-none basis-90 p-6 flex flex-col gap-6 relative`,
|
||||||
@@ -74,13 +98,21 @@ export default function Right() {
|
|||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
{mode === '2' ? (
|
{mode === '2' ? (
|
||||||
<li className="flex justify-between items-center">
|
<>
|
||||||
<span className="text-sm text-gray-500">购买 IP 量</span>
|
<li className="flex justify-between items-center">
|
||||||
<span className="text-sm">
|
<span className="text-sm text-gray-500">购买 IP 量</span>
|
||||||
{quota}
|
<span className="text-sm">
|
||||||
个
|
{quota}
|
||||||
</span>
|
个
|
||||||
</li>
|
</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">
|
<li className="flex justify-between items-center">
|
||||||
@@ -97,19 +129,30 @@ export default function Right() {
|
|||||||
个
|
个
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</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">
|
||||||
|
-¥{discounted}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
<div className="border-b border-gray-200"></div>
|
<div className="border-b border-gray-200"></div>
|
||||||
<p className="flex justify-between items-center">
|
<p className="flex justify-between items-center">
|
||||||
<span>价格</span>
|
<span>实付价格</span>
|
||||||
<span className="text-xl text-orange-500">
|
<span className="text-xl text-orange-500">
|
||||||
¥
|
¥{discountedPrice}
|
||||||
{price}
|
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<Suspense>
|
<Suspense>
|
||||||
<BalanceOrLogin {...{method, price, mode, live, quota, expire, dailyLimit}}/>
|
<BalanceOrLogin {...{method, discountedPrice, mode, live, quota, expire, dailyLimit}}/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</Card>
|
</Card>
|
||||||
)
|
)
|
||||||
@@ -117,7 +160,7 @@ export default function Right() {
|
|||||||
|
|
||||||
function BalanceOrLogin(props: {
|
function BalanceOrLogin(props: {
|
||||||
method: 'wechat' | 'alipay' | 'balance'
|
method: 'wechat' | 'alipay' | 'balance'
|
||||||
price: string
|
discountedPrice: string
|
||||||
mode: string
|
mode: string
|
||||||
live: string
|
live: string
|
||||||
quota: number
|
quota: number
|
||||||
@@ -176,7 +219,7 @@ function BalanceOrLogin(props: {
|
|||||||
<Pay
|
<Pay
|
||||||
method={props.method}
|
method={props.method}
|
||||||
balance={profile.balance}
|
balance={profile.balance}
|
||||||
amount={props.price}
|
amount={props.discountedPrice}
|
||||||
resource={{
|
resource={{
|
||||||
type: 2,
|
type: 2,
|
||||||
long: {
|
long: {
|
||||||
|
|||||||
@@ -17,6 +17,13 @@ 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 {CreateResourceReq, getPrice} from '@/actions/resource'
|
import {CreateResourceReq, getPrice} from '@/actions/resource'
|
||||||
|
|
||||||
|
interface PriceData {
|
||||||
|
price: string
|
||||||
|
discounted_price?: string
|
||||||
|
discounted?: number
|
||||||
|
}
|
||||||
|
|
||||||
export default function Right() {
|
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'})
|
||||||
@@ -25,7 +32,11 @@ export default function Right() {
|
|||||||
const expire = useWatch({control, name: 'expire'})
|
const expire = useWatch({control, name: 'expire'})
|
||||||
const quota = useWatch({control, name: 'quota'})
|
const quota = useWatch({control, name: 'quota'})
|
||||||
const dailyLimit = useWatch({control, name: 'daily_limit'})
|
const dailyLimit = useWatch({control, name: 'daily_limit'})
|
||||||
const [price, setPrice] = useState<string>('')
|
const [priceData, setPriceData] = useState<PriceData>({
|
||||||
|
price: '0.00',
|
||||||
|
discounted_price: '0.00',
|
||||||
|
discounted: 0,
|
||||||
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const price = async () => {
|
const price = async () => {
|
||||||
@@ -40,18 +51,31 @@ export default function Right() {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const priceResponse = await getPrice(params)
|
const priceResponse = await getPrice(params)
|
||||||
if (priceResponse.success && priceResponse.data?.price) {
|
console.log(priceResponse, 'priceResponse')
|
||||||
setPrice(priceResponse.data.price)
|
|
||||||
|
if (priceResponse.success && priceResponse.data) {
|
||||||
|
const data: PriceData = priceResponse.data
|
||||||
|
setPriceData({
|
||||||
|
price: data.price,
|
||||||
|
discounted_price: data.discounted_price ?? data.price ?? '',
|
||||||
|
discounted: data.discounted,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error('获取价格失败:', error)
|
console.error('获取价格失败:', error)
|
||||||
setPrice('0.00')
|
setPriceData({
|
||||||
|
price: '0.00',
|
||||||
|
discounted_price: '0.00',
|
||||||
|
discounted: 0,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
price()
|
price()
|
||||||
}, [expire, live, quota, mode, dailyLimit])
|
}, [expire, live, quota, mode, dailyLimit])
|
||||||
|
|
||||||
|
const {price, discounted_price: discountedPrice = '', discounted} = priceData
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className={merge(
|
<Card className={merge(
|
||||||
`flex-none basis-90 p-6 flex flex-col gap-6 relative`,
|
`flex-none basis-90 p-6 flex flex-col gap-6 relative`,
|
||||||
@@ -73,13 +97,21 @@ export default function Right() {
|
|||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
{mode === '2' ? (
|
{mode === '2' ? (
|
||||||
<li className="flex justify-between items-center">
|
<>
|
||||||
<span className="text-sm text-gray-500">购买 IP 量</span>
|
<li className="flex justify-between items-center">
|
||||||
<span className="text-sm">
|
<span className="text-sm text-gray-500">购买 IP 量</span>
|
||||||
{quota}
|
<span className="text-sm">
|
||||||
个
|
{quota}
|
||||||
</span>
|
个
|
||||||
</li>
|
</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">
|
<li className="flex justify-between items-center">
|
||||||
@@ -96,19 +128,32 @@ export default function Right() {
|
|||||||
个
|
个
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</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 === 1 ? '' : discounted}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
<div className="border-b border-gray-200"></div>
|
<div className="border-b border-gray-200"></div>
|
||||||
<p className="flex justify-between items-center">
|
<p className="flex justify-between items-center">
|
||||||
<span>价格</span>
|
<span>实付价格</span>
|
||||||
<span className="text-xl text-orange-500">
|
<span className="text-xl text-orange-500">
|
||||||
¥
|
¥{discountedPrice}
|
||||||
{price}
|
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<Suspense>
|
<Suspense>
|
||||||
<BalanceOrLogin {...{method, price, mode, live, quota, expire, dailyLimit}}/>
|
<BalanceOrLogin {...{method, discountedPrice, mode, live, quota, expire, dailyLimit}}/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</Card>
|
</Card>
|
||||||
)
|
)
|
||||||
@@ -116,7 +161,7 @@ export default function Right() {
|
|||||||
|
|
||||||
function BalanceOrLogin(props: {
|
function BalanceOrLogin(props: {
|
||||||
method: 'wechat' | 'alipay' | 'balance'
|
method: 'wechat' | 'alipay' | 'balance'
|
||||||
price: string
|
discountedPrice: string
|
||||||
mode: string
|
mode: string
|
||||||
live: string
|
live: string
|
||||||
quota: number
|
quota: number
|
||||||
@@ -175,7 +220,7 @@ function BalanceOrLogin(props: {
|
|||||||
<Pay
|
<Pay
|
||||||
method={props.method}
|
method={props.method}
|
||||||
balance={profile.balance}
|
balance={profile.balance}
|
||||||
amount={props.price}
|
amount={props.discountedPrice}
|
||||||
resource={{
|
resource={{
|
||||||
type: 1,
|
type: 1,
|
||||||
short: {
|
short: {
|
||||||
|
|||||||
Reference in New Issue
Block a user