3 Commits

Author SHA1 Message Date
db8119e1ae 调整帮助中心文档 2026-01-12 18:28:50 +08:00
91add59393 屏蔽余额功能 2025-12-23 17:12:09 +08:00
a3588fd1be 重构首页,优化组件结构 2025-12-23 17:11:46 +08:00
39 changed files with 379 additions and 321 deletions

View File

@@ -1,7 +1,13 @@
## TODO ## TODO
分离公共 api 接口 env 定义
统一前端基础库类型api
购买页固定套餐 购买页固定套餐
优惠问题
### 禁止直接依赖 form ### 禁止直接依赖 form
`\[(.*,)?form(,.*)?\]` `\[(.*,)?form(,.*)?\]`

View File

@@ -74,5 +74,5 @@
"typescript": "^5.9.3", "typescript": "^5.9.3",
"babel-plugin-react-compiler": "^1.0.0" "babel-plugin-react-compiler": "^1.0.0"
}, },
"packageManager": "bun@1.2.19" "packageManager": "bun@1.3.2"
} }

View File

Before

Width:  |  Height:  |  Size: 186 KiB

After

Width:  |  Height:  |  Size: 186 KiB

View File

Before

Width:  |  Height:  |  Size: 169 KiB

After

Width:  |  Height:  |  Size: 169 KiB

View File

Before

Width:  |  Height:  |  Size: 176 KiB

After

Width:  |  Height:  |  Size: 176 KiB

View File

Before

Width:  |  Height:  |  Size: 142 KiB

After

Width:  |  Height:  |  Size: 142 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 540 KiB

After

Width:  |  Height:  |  Size: 540 KiB

View File

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 97 KiB

View File

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 110 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

View File

@@ -0,0 +1,50 @@
import Image, {StaticImageData} from 'next/image'
import {PageSection} from './page-section'
import s4_1_main from './_assets/s4-1-main.webp'
import s4_2_main from './_assets/s4-2-main.webp'
import s4_1_1 from './_assets/s4-1-1.webp'
import s4_1_2 from './_assets/s4-1-2.webp'
import s4_1_3 from './_assets/s4-1-3.webp'
import s4_2_1 from './_assets/s4-2-1.webp'
import s4_2_2 from './_assets/s4-2-2.webp'
import s4_2_3 from './_assets/s4-2-3.webp'
export function AdvantagesSection() {
return (
<PageSection title="HTTP 产品优势">
<div className="flex gap-36">
<ul className="flex-1 flex flex-col gap-6">
<AdvantageItem icon={s4_1_1} title="安全合规" description="国内三大运营商支持"/>
<AdvantageItem icon={s4_1_2} title="稳定链接" description="IP纯净度高达99.9%"/>
<AdvantageItem icon={s4_1_3} title="超匿名性" description="稳定传输,保护隐私安全"/>
</ul>
<Image src={s4_1_main} alt="产品优势展示" className="w-0 flex-1 object-contain max-lg:hidden"/>
</div>
<div className="flex gap-36">
<Image src={s4_2_main} alt="技术优势展示" className="w-0 flex-1 object-contain max-lg:hidden"/>
<ul className="flex-1 flex flex-col gap-6">
<AdvantageItem icon={s4_2_1} title="API接口文档" description="与第三方软件轻松集成"/>
<AdvantageItem icon={s4_2_2} title="多种编程语言代码" description="C语言、GO语言、Python..."/>
<AdvantageItem icon={s4_2_3} title="双重认证方式" description="API提取+账密认证"/>
</ul>
</div>
</PageSection>
)
}
function AdvantageItem(props: {
icon: StaticImageData
title: string
description: string
}) {
return (
<li className="flex gap-8 items-center p-4 lg:p-8 shadow-[4px_4px_20px_4px] shadow-blue-50 rounded-lg">
<Image src={props.icon} alt={props.title} aria-hidden className="w-24 h-24 object-contain"/>
<div className="flex flex-col gap-3">
<h3 className="text-xl">{props.title}</h3>
<p>{props.description}</p>
</div>
</li>
)
}

View File

@@ -0,0 +1,70 @@
import {ReactNode} from 'react'
import Link from 'next/link'
import {PageSection} from './page-section'
import {BookOpen, Smartphone, HelpCircle} from 'lucide-react'
export function ArticlesSection() {
return (
<PageSection title="推荐文章">
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
<ArticleCard
icon={<BookOpen className="w-12 h-12"/>}
title="浏览器设置代理教程"
description="快速上手5分钟学会在浏览器中配置代理服务器"
href="/docs/browser-proxy"
/>
<ArticleCard
icon={<Smartphone className="w-12 h-12"/>}
title="Windows10 代理配置"
description="详细图文教程,帮助你在 Windows 系统中设置代理"
href="/docs/windows10-proxy"
/>
<ArticleCard
icon={<HelpCircle className="w-12 h-12"/>}
title="常见问题总览"
description="解决使用过程中遇到的各类问题,快速找到答案"
href="/docs/faq-general"
/>
</div>
</PageSection>
)
}
function ArticleCard(props: {
icon: ReactNode
title: string
description: string
href: string
}) {
return (
<Link
href={props.href}
className={[
`group block p-8 shadow-[4px_4px_20px_4px] shadow-blue-50 rounded-lg bg-white`,
`transition-all duration-200`,
].join(' ')}
>
<div className="flex flex-col items-center text-center gap-6">
<div className="p-4 rounded-xl bg-linear-to-br from-blue-500 to-cyan-400 text-white group-hover:scale-110 transition-transform">
{props.icon}
</div>
<div>
<h3 className="text-xl font-semibold mb-3 group-hover:text-blue-600 transition-colors">
{props.title}
</h3>
<p className="text-gray-500 text-sm leading-relaxed">
{props.description}
</p>
</div>
<div className="mt-2 text-blue-500 text-sm flex items-center gap-2 group-hover:gap-3 transition-all">
<span></span>
<span className="text-lg"></span>
</div>
</div>
</Link>
)
}

View File

@@ -0,0 +1,37 @@
import Image from 'next/image'
import Wrap from '@/components/wrap'
import FreeTrial from '@/components/free-trial'
import banner from '../_assets/banner.webp'
import check_main from '@/assets/check-main.svg'
export function HeroSection() {
return (
<section className="w-full relative">
<Image src={banner} alt="banner" className="absolute inset-0 h-full object-cover"/>
<Wrap className="relative pt-64 pb-48 max-md:pt-32 max-md:pb-24">
<h1 className="text-4xl"></h1>
<p className="mt-10 text-gray-500">IP代理服务</p>
<div className="mt-24 max-md:mt-14 flex gap-8 max-md:flex-col">
<p className="flex gap-4 items-center">
<Image src={check_main} alt="checkbox" width={24} height={24}/>
<span className="lg:text-lg">200+</span>
</p>
<p className="flex gap-4 items-center">
<Image src={check_main} alt="checkbox" width={24} height={24}/>
<span className="lg:text-lg">300+</span>
</p>
<p className="flex gap-4 items-center">
<Image src={check_main} alt="checkbox" width={24} height={24}/>
<span className="lg:text-lg">&</span>
</p>
</div>
<FreeTrial className={[
`mt-32 max-md:mt-20 w-96 max-md:w-full h-16 md:h-24 rounded-lg shadow-lg`,
`bg-linear-to-r from-blue-500 to-cyan-400 text-white text-xl lg:text-4xl`,
].join(' ')}/>
</Wrap>
</section>
)
}

View File

@@ -0,0 +1,15 @@
import {ReactNode} from 'react'
export function PageSection(props: {
title: string
children: ReactNode
}) {
return (
<section>
<div className="max-w-[1232px] mx-auto px-4 flex flex-col items-stretch">
<h2 className="text-center text-3xl mb-8 lg:mb-24">{props.title}</h2>
{props.children}
</div>
</section>
)
}

View File

@@ -0,0 +1,17 @@
import {HeroSection} from './hero-section'
import {StatsSection} from './stats-section'
import {ProductTypesSection} from './product-types-section'
import {AdvantagesSection} from './advantages-section'
import {ArticlesSection} from './articles-section'
export default function Home() {
return (
<main className="flex flex-col gap-16 lg:gap-32 pb-16 lg:pb-32 bg-white">
<HeroSection/>
<StatsSection/>
<ProductTypesSection/>
<AdvantagesSection/>
<ArticlesSection/>
</main>
)
}

View File

@@ -0,0 +1,78 @@
import Image, {StaticImageData} from 'next/image'
import {PageSection} from './page-section'
import s1_1 from './_assets/s1-1.webp'
import s1_2 from './_assets/s1-2.webp'
import s1_3 from './_assets/s1-3.webp'
import s1_4 from './_assets/s1-4.webp'
import s1_check from './_assets/s1-check.svg'
export function ProductTypesSection() {
return (
<PageSection title="HTTP安全合规的代理IP资源池">
<ul className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
<ProductTypeCard
icon={s1_1}
title="短期动态IP池"
features={[
{icon: s1_check, text: 'IP时效3-30分钟(可定制)'},
{icon: s1_check, text: '支持高并发提取'},
]}
/>
<ProductTypeCard
icon={s1_2}
title="长期静态IP池"
features={[
{icon: s1_check, text: 'IP覆盖全国各地'},
{icon: s1_check, text: '平均响应时长0.03s'},
]}
/>
<ProductTypeCard
icon={s1_3}
title="固定IP池"
features={[
{icon: s1_check, text: '稳定长输不掉线'},
{icon: s1_check, text: '全国热门静态IP线路'},
]}
/>
<ProductTypeCard
icon={s1_4}
title="企业级定制池"
features={[
{icon: s1_check, text: '可视化监控设计'},
{icon: s1_check, text: '技术团队现场支持'},
]}
/>
</ul>
</PageSection>
)
}
function ProductTypeCard(props: {
icon: StaticImageData
title: string
features: {
icon: StaticImageData
text: string
}[]
}) {
return (
<li
className={[
`p-8 flex flex-col gap-5 shadow-[4px_4px_20px_4px] shadow-blue-50 bg-white rounded-lg`,
`max-md:items-center`,
].join(' ')}>
<Image src={props.icon} alt={props.title} aria-hidden className="self-center w-44 h-44 object-cover"/>
<h3 className="text-xl">{props.title}</h3>
<div className="flex flex-col gap-3">
{props.features.map((item, index) => {
return (
<p key={index} className="text-sm text-gray-500 flex gap-3 items-center">
<Image src={item.icon} alt="check" aria-hidden className="w-5 h-5"/>
<span>{item.text}</span>
</p>
)
})}
</div>
</li>
)
}

View File

@@ -0,0 +1,32 @@
import Image from 'next/image'
import {PageSection} from './page-section'
import map from '../_assets/map.webp'
export function StatsSection() {
return (
<PageSection title="覆盖全国的IP资源及超大的带宽线路">
<ul className="shadow-[0_0_20px_4px] shadow-blue-50 p-8 flex max-lg:flex-col">
<li className="flex-1 flex flex-col items-center justify-center lg:border-r max-lg:mb-4 border-gray-200">
<p className="text-xl">线</p>
<p className="mt-9 max-lg:mt-2 text-5xl bg-linear-to-t from-blue-500 to-cyan-400 bg-clip-text text-transparent font-bold pb-2 -mb-2">350+</p>
<div className="lg:hidden w-24 border-b mt-4 border-gray-200"></div>
</li>
<li className="flex-1 flex flex-col items-center justify-center lg:border-r max-lg:mb-4 border-gray-200">
<p className="text-xl">IP数量</p>
<p className="mt-9 max-lg:mt-2 text-5xl bg-linear-to-t from-blue-500 to-cyan-400 bg-clip-text text-transparent font-bold pb-2 -mb-2">1,350,129</p>
<div className="lg:hidden w-24 border-b mt-4 border-gray-200"></div>
</li>
<li className="flex-1 flex flex-col items-center justify-center lg:border-r max-lg:mb-4 border-gray-200">
<p className="text-xl"></p>
<p className="mt-9 max-lg:mt-2 text-5xl bg-linear-to-t from-blue-500 to-cyan-400 bg-clip-text text-transparent font-bold pb-2 -mb-2">26,578</p>
<div className="lg:hidden w-24 border-b mt-4 border-gray-200"></div>
</li>
<li className="flex-1 flex flex-col items-center justify-center">
<p className="text-xl">IP可用率</p>
<p className="mt-9 max-lg:mt-2 text-5xl bg-linear-to-t from-blue-500 to-cyan-400 bg-clip-text text-transparent font-bold pb-2 -mb-2">99%</p>
</li>
</ul>
<Image src={map} alt="map" className="w-[1200px]"/>
</PageSection>
)
}

View File

@@ -0,0 +1,3 @@
# IP提取接口文档
暂无内容,敬请期待。

View File

@@ -0,0 +1,3 @@
# 如何选择产品
暂无内容,敬请期待。

View File

@@ -0,0 +1,3 @@
# 有哪些城市线路
暂无内容,敬请期待。

View File

@@ -0,0 +1,3 @@
# 如何生成提取链接
暂无内容,敬请期待。

View File

@@ -0,0 +1,3 @@
# 查看支付和使用记录
暂无内容,敬请期待。

View File

@@ -0,0 +1,3 @@
# 修改个人信息和重置密码
暂无内容,后期会补充,敬请期待。

View File

@@ -8,41 +8,36 @@ type Props = {
collapsed?: boolean collapsed?: boolean
} }
// 菜单配置 - 扁平结构,支持分组 // 菜单配置
const MENU_ITEMS = [ const MENU_ITEMS = [
{ {
group: '官网教程', group: '产品文档',
items: [ items: [
{key: 'browser-proxy', label: '浏览器设置代理教程'}, {key: 'product-overview', label: '产品介绍'},
{key: 'package-operations', label: '套餐续费、合并、修改时效、补重操作'}, {key: 'choose-product', label: '如何选择产品'},
{key: 'fixed-package', label: '长效固定套餐操作手册'}, {key: 'why-verify', label: '为什么需要实名认证'},
], {key: 'city-lines', label: '有哪些城市线路'},
}, {key: 'api-docs', label: 'ip提取接口文档'},
{ // 服务条款
group: '客户端教程',
items: [
{key: 'ios-proxy', label: 'iOS设置代理教程'},
{key: 'windows10-proxy', label: 'Windows10电脑设置代理教程'},
{key: 'android-proxy', label: '安卓手机设置代理教程'},
], ],
}, },
{ {
group: '操作指南', group: '操作指南',
items: [ items: [
{key: 'win7-proxy', label: 'Windows7电脑设置代理教程'}, {key: 'profile-settings', label: '修改个人信息和重置密码'},
{key: 'mac-proxy', label: 'MAC设置代理教程'}, {key: 'whitelist-guide', label: '如何添加白名单'},
{key: 'firefox-proxy', label: '火狐浏览器设置代理'}, {key: 'verify-guide', label: '如何进行实名认证'},
{key: 'socks5-usage', label: 'Socks5代理使用教程'}, {key: 'extract-link', label: '如何生成提取链接'},
{key: 'http-notes', label: '使用 HTTP 代理注意事项'}, {key: 'payment-records', label: '查看支付和使用记录'},
{key: 'official-tutorial', label: '浏览器设置代理教程'},
], ],
}, },
{ {
group: '产品介绍', group: '客户端教程',
items: [ items: [
{key: 'product-overview', label: '产品概述'}, {key: 'browser-proxy', label: '浏览器设置代理教程'},
{key: 'product-features', label: '产品功能'}, {key: 'ios-proxy', label: 'iOS设置代理教程'},
{key: 'product-cert', label: '实名认证与证书'}, {key: 'android-proxy', label: '安卓手机设置代理教程'},
{key: 'windows10-proxy', label: 'Windows10电脑设置代理教程'},
], ],
}, },
{ {
@@ -50,19 +45,15 @@ const MENU_ITEMS = [
items: [ items: [
{key: 'faq-general', label: '常见问题总览'}, {key: 'faq-general', label: '常见问题总览'},
{key: 'faq-billing', label: '计费与套餐问题'}, {key: 'faq-billing', label: '计费与套餐问题'},
// 业务场景集成方案
// 故障排查
], ],
}, },
{ {
group: '新闻资讯', group: '新闻资讯',
items: [ items: [
{key: 'news-latest', label: '了解代理服务器的工作原理'}, {key: 'news-latest', label: '了解代理服务器的工作原理'},
{key: 'news-announce', label: '公告'}, {key: 'news-announce', label: '网站公告'},
],
},
{
group: '其他',
items: [
{key: 'online-ip-proxy', label: '在线 IP 代理地址'},
], ],
}, },
] ]

View File

@@ -0,0 +1,3 @@
# 如何进行实名认证
暂无内容,敬请期待。

View File

@@ -0,0 +1,3 @@
# 如何添加白名单
暂未添加内容,敬请期待。

View File

@@ -0,0 +1,3 @@
# 为什么需要实名认证
暂无内容,后期会补充,敬请期待。

View File

@@ -1,266 +0,0 @@
import {ReactNode} from 'react'
import Wrap from '@/components/wrap'
import Image, {StaticImageData} from 'next/image'
import Link from 'next/link'
import check_main from '@/assets/check-main.svg'
import banner from './_assets/banner.webp'
import map from './_assets/map.webp'
import s1_1 from './_assets/s1-1.webp'
import s1_2 from './_assets/s1-2.webp'
import s1_3 from './_assets/s1-3.webp'
import s1_4 from './_assets/s1-4.webp'
import s1_check from './_assets/s1-check.svg'
import s4_1_main from './_assets/s4-1-main.webp'
import s4_2_main from './_assets/s4-2-main.webp'
import s4_1_1 from './_assets/s4-1-1.webp'
import s4_1_2 from './_assets/s4-1-2.webp'
import s4_1_3 from './_assets/s4-1-3.webp'
import s4_2_1 from './_assets/s4-2-1.webp'
import s4_2_2 from './_assets/s4-2-2.webp'
import s4_2_3 from './_assets/s4-2-3.webp'
import FreeTrial from '@/components/free-trial'
import {BookOpen, Smartphone, Settings, HelpCircle, Newspaper, FileText} from 'lucide-react'
export default function Home() {
return (
<main className="flex flex-col gap-16 lg:gap-32 pb-16 lg:pb-32 bg-white">
{/* banner */}
<section className="w-full relative">
<Image src={banner} alt="banner" className="absolute inset-0 h-full object-cover"/>
<Wrap className="relative pt-64 pb-48 max-md:pt-32 max-md:pb-24">
<h1 className="text-4xl"></h1>
<p className="mt-10 text-gray-500">IP代理服务</p>
<div className="mt-24 max-md:mt-14 flex gap-8 max-md:flex-col">
<p className="flex gap-4 items-center">
<Image src={check_main} alt="checkbox" width={24} height={24}/>
<span className={`lg:text-lg `}>200+</span>
</p>
<p className="flex gap-4 items-center">
<Image src={check_main} alt="checkbox" width={24} height={24}/>
<span className={`lg:text-lg `}>300+</span>
</p>
<p className="flex gap-4 items-center">
<Image src={check_main} alt="checkbox" width={24} height={24}/>
<span className={`lg:text-lg `}>&</span>
</p>
</div>
<FreeTrial className={[
`mt-32 max-md:mt-20 w-96 max-md:w-full h-16 md:h-24 rounded-lg shadow-lg`,
`bg-linear-to-r from-blue-500 to-cyan-400 text-white text-xl lg:text-4xl`,
].join(' ')}/>
</Wrap>
</section>
{/* 数据展示 */}
<Section title="覆盖全国的IP资源及超大的带宽线路">
<ul className="shadow-[0_0_20px_4px] shadow-blue-50 p-8 flex max-lg:flex-col">
<li className="flex-1 flex flex-col items-center justify-center lg:border-r max-lg:mb-4 border-gray-200">
<p className="text-xl">线</p>
<p className="mt-9 max-lg:mt-2 text-5xl bg-linear-to-t from-blue-500 to-cyan-400 bg-clip-text text-transparent font-bold pb-2 -mb-2">350+</p>
<div className="lg:hidden w-24 border-b mt-4 border-gray-200"></div>
</li>
<li className="flex-1 flex flex-col items-center justify-center lg:border-r max-lg:mb-4 border-gray-200">
<p className="text-xl">IP数量</p>
<p className="mt-9 max-lg:mt-2 text-5xl bg-linear-to-t from-blue-500 to-cyan-400 bg-clip-text text-transparent font-bold pb-2 -mb-2">1,350,129</p>
<div className="lg:hidden w-24 border-b mt-4 border-gray-200"></div>
</li>
<li className="flex-1 flex flex-col items-center justify-center lg:border-r max-lg:mb-4 border-gray-200">
<p className="text-xl"></p>
<p className="mt-9 max-lg:mt-2 text-5xl bg-linear-to-t from-blue-500 to-cyan-400 bg-clip-text text-transparent font-bold pb-2 -mb-2">26,578</p>
<div className="lg:hidden w-24 border-b mt-4 border-gray-200"></div>
</li>
<li className="flex-1 flex flex-col items-center justify-center">
<p className="text-xl">IP可用率</p>
<p className="mt-9 max-lg:mt-2 text-5xl bg-linear-to-t from-blue-500 to-cyan-400 bg-clip-text text-transparent font-bold pb-2 -mb-2">99%</p>
</li>
</ul>
<Image src={map} alt="map" className="w-[1200px]"/>
</Section>
{/* 优势 1 */}
<Section title="HTTP安全合规的代理IP资源池">
<ul
className={[
`grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8`,
].join(' ')}>
<Sec3Item
icon={s1_1}
title="短期动态IP池"
terms={[
{icon: s1_check, text: `IP时效3-30分钟(可定制)`},
{icon: s1_check, text: `支持高并发提取`},
]}/>
<Sec3Item
icon={s1_2}
title="长期静态IP池"
terms={[
{icon: s1_check, text: `IP覆盖全国各地`},
{icon: s1_check, text: `平均响应时长0.03s`},
]}/>
<Sec3Item
icon={s1_3}
title="固定IP池"
terms={[
{icon: s1_check, text: `稳定长输不掉线`},
{icon: s1_check, text: `全国热门静态IP线路`},
]}/>
<Sec3Item
icon={s1_4}
title="企业级定制池"
terms={[
{icon: s1_check, text: `可视化监控设计`},
{icon: s1_check, text: `技术团队现场支持`},
]}/>
</ul>
</Section>
{/* 优势 2 */}
<Section title="HTTP 产品优势">
<div className="flex gap-36">
<ul className="flex-1 flex flex-col gap-6">
<Sec4Item icon={s4_1_1} title="安全合规" description="国内三大运营商支持"/>
<Sec4Item icon={s4_1_2} title="稳定链接" description="IP纯净度高达99.9%"/>
<Sec4Item icon={s4_1_3} title="超匿名性" description="稳定传输,保护隐私安全"/>
</ul>
<Image src={s4_1_main} alt="s2-1-main" className="w-0 flex-1 object-contain max-lg:hidden"/>
</div>
<div className="flex gap-36">
<Image src={s4_2_main} alt="s2-1-main" className="w-0 flex-1 object-contain max-lg:hidden"/>
<ul className="flex-1 flex flex-col gap-6">
<Sec4Item icon={s4_2_1} title="API接口文档" description="与第三方软件轻松集成"/>
<Sec4Item icon={s4_2_2} title="多种编程语言代码" description="C语言、GO语言、Python..."/>
<Sec4Item icon={s4_2_3} title="双重认证方式" description="API提取+账密认证"/>
</ul>
</div>
</Section>
{/* 推荐文章 */}
<Section title="推荐文章">
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
<ArticleCard
icon={<BookOpen className="w-12 h-12"/>}
title="浏览器设置代理教程"
description="快速上手5分钟学会在浏览器中配置代理服务器"
href="/docs/browser-proxy"
/>
<ArticleCard
icon={<Smartphone className="w-12 h-12"/>}
title="Windows10 代理配置"
description="详细图文教程,帮助你在 Windows 系统中设置代理"
href="/docs/windows10-proxy"
/>
<ArticleCard
icon={<HelpCircle className="w-12 h-12"/>}
title="常见问题总览"
description="解决使用过程中遇到的各类问题,快速找到答案"
href="/docs/faq-general"
/>
</div>
</Section>
</main>
)
}
function Section(props: {
title: string
children: ReactNode
}) {
return (
<section>
<div className="max-w-[1232px] mx-auto px-4 flex flex-col items-stretch">
<h2 className="text-center text-3xl mb-8 lg:mb-24">{props.title}</h2>
{props.children}
</div>
</section>
)
}
function Sec3Item(props: {
icon: StaticImageData
title: string
terms: {
icon: StaticImageData
text: string
}[]
}) {
return (
<li
className={[
`p-8 flex flex-col gap-5 shadow-[4px_4px_20px_4px] shadow-blue-50 bg-white rounded-lg`,
`max-md:items-center`,
].join(' ')}>
<Image src={props.icon} alt="s1-1" aria-hidden className="self-center w-44 h-44 object-cover"/>
<h3 className="text-xl">{props.title}</h3>
<div className="flex flex-col gap-3">
{props.terms.map((item, index) => {
return (
<p key={index} className="text-sm text-gray-500 flex gap-3 items-center">
<Image src={item.icon} alt="check" aria-hidden className="w-5 h-5"/>
<span>{item.text}</span>
</p>
)
})}
</div>
</li>
)
}
function ArticleCard(props: {
icon: ReactNode
title: string
description: string
href: string
}) {
return (
<Link
href={props.href}
className={[
`group block p-8 shadow-[4px_4px_20px_4px] shadow-blue-50 rounded-lg bg-white`,
`transition-all duration-200`,
].join(' ')}
>
<div className="flex flex-col items-center text-center gap-6">
<div className="p-4 rounded-xl bg-linear-to-br from-blue-500 to-cyan-400 text-white group-hover:scale-110 transition-transform">
{props.icon}
</div>
<div>
<h3 className="text-xl font-semibold mb-3 group-hover:text-blue-600 transition-colors">
{props.title}
</h3>
<p className="text-gray-500 text-sm leading-relaxed">
{props.description}
</p>
</div>
<div className="mt-2 text-blue-500 text-sm flex items-center gap-2 group-hover:gap-3 transition-all">
<span></span>
<span className="text-lg"></span>
</div>
</div>
</Link>
)
}
function Sec4Item(props: {
icon: StaticImageData
title: string
description: string
}) {
return (
<li className="flex gap-8 items-center p-4 lg:p-8 shadow-[4px_4px_20px_4px] shadow-blue-50 rounded-lg">
<Image src={props.icon} alt="s2-1-1" aria-hidden className="w-24 h-24 object-contain"/>
<div className="flex flex-col gap-3">
<h3 className="text-xl">{props.title}</h3>
<p>{props.description}</p>
</div>
</li>
)
}

View File

@@ -59,7 +59,7 @@ export default async function UserCenter() {
</> </>
)} )}
</div> </div>
<div className="flex flex-col gap-1"> {/* <div className="flex flex-col gap-1">
<h4 className="text-sm text-weak">账户余额</h4> <h4 className="text-sm text-weak">账户余额</h4>
<div className="flex justify-between items-baseline"> <div className="flex justify-between items-baseline">
<p className="text-xl text-accent"> <p className="text-xl text-accent">
@@ -68,7 +68,7 @@ export default async function UserCenter() {
</p> </p>
<RechargeModal/> <RechargeModal/>
</div> </div>
</div> </div> */}
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3">
<h4 className="text-sm text-weak"></h4> <h4 className="text-sm text-weak"></h4>
<div className="flex justify-around gap-2"> <div className="flex justify-around gap-2">

View File

@@ -35,9 +35,9 @@ export default async function ProfilePage(props: ProfilePageProps) {
{/* 块信息 */} {/* 块信息 */}
<div className="flex gap-4 max-md:flex-col max-sm:flex-col"> <div className="flex gap-4 max-md:flex-col max-sm:flex-col">
<Card className="flex-1 "> {/* <Card className="flex-1 ">
<CardHeader> <CardHeader>
<CardTitle className="font-normal"></CardTitle> <CardTitle className="font-normal">账户余额(元)</CardTitle>
</CardHeader> </CardHeader>
<CardContent className="flex-auto flex justify-between items-center px-8"> <CardContent className="flex-auto flex justify-between items-center px-8">
<p className="text-xl">{user.balance}</p> <p className="text-xl">{user.balance}</p>
@@ -45,6 +45,16 @@ export default async function ProfilePage(props: ProfilePageProps) {
trigger: `h-10 px-6`, trigger: `h-10 px-6`,
}}/> }}/>
</CardContent> </CardContent>
</Card> */}
<Card className="flex-1 ">
<CardHeader>
<CardTitle className="font-normal"></CardTitle>
</CardHeader>
<CardContent className="flex-auto flex justify-between items-center px-8">
<p>{user.phone}</p>
<ChangePasswordDialog triggerClassName="w-24 h-9"/>
</CardContent>
</Card> </Card>
<Card className="flex-1"> <Card className="flex-1">
@@ -79,17 +89,6 @@ export default async function ProfilePage(props: ProfilePageProps) {
</div> </div>
<div className="flex-none rounded-lg bg-white p-4 flex max-sm:flex-col flex-col gap-8"> <div className="flex-none rounded-lg bg-white p-4 flex max-sm:flex-col flex-col gap-8">
{/* 安全信息 */}
<div className="flex flex-col gap-4">
<h3 className="font-normal"></h3>
<div className="flex gap-4 items-center">
<p>{user.phone}</p>
<ChangePasswordDialog triggerClassName="w-24 h-9"/>
</div>
</div>
{/* 基本信息 */}
<BasicForm profile={user}/> <BasicForm profile={user}/>
</div> </div>
</div> </div>

View File

@@ -7,6 +7,7 @@ import {ProfileStoreProvider} from '@/components/stores/profile'
import {LayoutStoreProvider} from '@/components/stores/layout' import {LayoutStoreProvider} from '@/components/stores/layout'
import {ClientStoreProvider} from '@/components/stores/client' import {ClientStoreProvider} from '@/components/stores/client'
import {getProfile} from '@/actions/auth' import {getProfile} from '@/actions/auth'
import Script from 'next/script'
export async function generateMetadata(): Promise<Metadata> { export async function generateMetadata(): Promise<Metadata> {
return { return {
@@ -24,6 +25,7 @@ export default async function RootLayout(props: Readonly<{
<Effects>{props.children}</Effects> <Effects>{props.children}</Effects>
</StoreProviders> </StoreProviders>
<Toaster position="top-center" richColors expand/> <Toaster position="top-center" richColors expand/>
<Script id="qd2852138148beb7882a4a6a3e5ff5b569436003e7dc" src="https://wp.qiye.qq.com/qidian/2852138148/beb7882a4a6a3e5ff5b569436003e7dc" charset="utf-8" async defer></Script>
</body> </body>
</html> </html>
) )

View File

@@ -172,7 +172,7 @@ function BalanceOrLogin(props: {
onValueChange={field.onChange} onValueChange={field.onChange}
className="flex flex-col gap-3"> className="flex flex-col gap-3">
<div className="w-full p-3 flex flex-col gap-4 bg-gray-100 rounded-md"> {/* <div className="w-full p-3 flex flex-col gap-4 bg-gray-100 rounded-md">
<p className="flex items-center gap-3"> <p className="flex items-center gap-3">
<Image src={balance} alt="余额icon"/> <Image src={balance} alt="余额icon"/>
<span className="text-sm text-gray-500">账户余额</span> <span className="text-sm text-gray-500">账户余额</span>
@@ -181,16 +181,16 @@ function BalanceOrLogin(props: {
<span className="text-xl">{profile?.balance}</span> <span className="text-xl">{profile?.balance}</span>
<RechargeModal/> <RechargeModal/>
</p> </p>
</div> </div> */}
<FormOption {/* <FormOption
id={`${id}-balance`} id={`${id}-balance`}
value="balance" value="balance"
compare={field.value} compare={field.value}
className="p-3 w-full flex-row gap-2 justify-center"> className="p-3 w-full flex-row gap-2 justify-center">
<Image src={balance} alt="余额 icon"/> <Image src={balance} alt="余额 icon"/>
<span>余额</span> <span>余额</span>
</FormOption> </FormOption> */}
<FormOption <FormOption
id={`${id}-wechat`} id={`${id}-wechat`}
value="wechat" value="wechat"

View File

@@ -173,7 +173,7 @@ function BalanceOrLogin(props: {
onValueChange={field.onChange} onValueChange={field.onChange}
className="flex flex-col gap-3"> className="flex flex-col gap-3">
<div className="w-full p-3 flex flex-col gap-4 bg-gray-100 rounded-md"> {/* <div className="w-full p-3 flex flex-col gap-4 bg-gray-100 rounded-md">
<p className="flex items-center gap-3"> <p className="flex items-center gap-3">
<Image src={balance} alt="余额icon"/> <Image src={balance} alt="余额icon"/>
<span className="text-sm text-gray-500">账户余额</span> <span className="text-sm text-gray-500">账户余额</span>
@@ -182,16 +182,16 @@ function BalanceOrLogin(props: {
<span className="text-xl">{profile.balance}</span> <span className="text-xl">{profile.balance}</span>
<RechargeModal/> <RechargeModal/>
</p> </p>
</div> </div> */}
<FormOption {/* <FormOption
id={`${id}-balance`} id={`${id}-balance`}
value="balance" value="balance"
compare={field.value} compare={field.value}
className="p-3 w-full flex-row gap-2 justify-center"> className="p-3 w-full flex-row gap-2 justify-center">
<Image src={balance} alt="余额 icon"/> <Image src={balance} alt="余额 icon"/>
<span>余额</span> <span>余额</span>
</FormOption> </FormOption> */}
<FormOption <FormOption
id={`${id}-wechat`} id={`${id}-wechat`}
value="wechat" value="wechat"