优化页头样式与操控 & 优化首页推荐文章部分 & 修复后台未正确流式加载问题

This commit is contained in:
2025-12-18 17:10:20 +08:00
parent fe5a9d2d48
commit e2c9ea7fbf
6 changed files with 97 additions and 82 deletions

View File

@@ -1,23 +1,17 @@
## TODO ## TODO
长效动态统计 提取记录,长效动态统计
页头产品订购 - 网站公告
页尾服务保障跳转企业微信
首页推荐文章
购买页固定套餐 购买页固定套餐
价格展示原价和折扣价
### 禁止直接依赖 form ### 禁止直接依赖 form
`\[(.*,)?form(,.*)?\]` `\[(.*,)?form(,.*)?\]`
### 次要 ### 次要
页头高度降低
帮助中心文档优化 帮助中心文档优化
考虑重新组织导航栏 考虑重新组织导航栏

View File

@@ -1,7 +1,6 @@
'use client' 'use client'
import {ReactNode, useContext, useState} from 'react' import {ReactNode, useContext, useState} from 'react'
import Wrap from '@/components/wrap' import Wrap from '@/components/wrap'
import anno from '@/assets/header/product/anno.svg'
import Link from 'next/link' import Link from 'next/link'
import {merge} from '@/lib/utils' import {merge} from '@/lib/utils'
import prod from '@/assets/header/product/prod.svg' import prod from '@/assets/header/product/prod.svg'
@@ -27,20 +26,7 @@ export default function ProductMenu() {
<Oversea/> <Oversea/>
) )
} }
<aside className="w-full lg:w-64 hidden lg:block">
<FragmentTitle img={anno} text="网站公告"/>
<div className="flex flex-col gap-2 p-4">
<p>线</p>
<p className="text-gray-400 text-sm">
1.使使
使
</p>
<p className="text-gray-400 text-sm">
2.使使
使
</p>
</div>
</aside>
</Wrap> </Wrap>
) )
} }
@@ -69,27 +55,24 @@ export function Domestic(props: {}) {
return ( return (
<section role="tabpanel" className="flex-auto flex flex-col lg:flex-row justify-evenly gap-3 lg:gap-0"> <section role="tabpanel" className="flex-auto flex flex-col lg:flex-row justify-evenly gap-3 lg:gap-0">
<div className="w-full lg:w-64 flex flex-col"> <div className="w-full lg:w-64 flex flex-col">
<FragmentTitle img={prod} text="代理产品"/> <FragmentTitle img={prod} text="短效 IP"/>
<DomesticLink <DomesticLink
label="短效动态 IP" label="短效动态 IP"
desc="全国300+城市级定位节点" desc="全国 300+ 城市级定位节点IP 池资源充足自动高频切换。适用于数据采集、市场调研、SEO 优化等高并发场景。稳定可靠,响应迅速,助力业务高效运转。"
href="/product?type=short" href="/product?type=short"
discount={45} discount={45}
/> />
</div>
<div className="w-full lg:w-64 flex flex-col">
<FragmentTitle img={prod} text="长效 IP"/>
<DomesticLink <DomesticLink
label="长效动态 IP" label="长效动态 IP"
desc="IP 资源覆盖全国" desc="IP 存活时长可达数小时至数天,连接稳定不掉线。适用于账号养号、社交运营、电商管理等需要持续在线的场景。优质线路保障,为您的长期业务保驾护航。"
href="/product?type=long" href="/product?type=long"
discount={45} discount={45}
/> />
<DomesticLink
label="静态 IP"
desc="全国300+城市级定位节点"
href="/product?type=fixed"
discount={45}
/>
</div> </div>
<div className="w-full lg:w-64 flex flex-col lg:max-lg:hidden"> <div className="w-full lg:w-64 flex flex-col">
<FragmentTitle img={custom} text="业务定制"/> <FragmentTitle img={custom} text="业务定制"/>
<DomesticLink <DomesticLink
label="优质/企业/精选IP" label="优质/企业/精选IP"

View File

@@ -1,5 +1,5 @@
'use client' 'use client'
import {useMemo, useState, PointerEvent, ComponentProps, useSyncExternalStore, use, Suspense} from 'react' import {useMemo, useState, PointerEvent, ComponentProps, useSyncExternalStore, use, Suspense, MouseEvent} from 'react'
import Link from 'next/link' import Link from 'next/link'
import Image from 'next/image' import Image from 'next/image'
import {HeaderContext} from './_components/header/common' import {HeaderContext} from './_components/header/common'
@@ -43,10 +43,20 @@ export default function Header(props: HeaderProps) {
<MobileMenu key="mobile"/>, <MobileMenu key="mobile"/>,
], []) ], [])
const toggleMobileMenu = () => {
if (menu) {
setMenu(false)
}
else {
setPage(3)
setMenu(true)
}
}
const enterMenu = (i: number) => { const enterMenu = (i: number) => {
return (e: PointerEvent) => { return (e: PointerEvent) => {
setPage(i) setPage(i)
if (e.pointerType === 'mouse' || page !== i) { if (page !== i) {
setMenu(true) setMenu(true)
} }
else { else {
@@ -55,18 +65,16 @@ export default function Header(props: HeaderProps) {
} }
} }
const exitMenu = (e: PointerEvent) => { const leaveMenu = (e: PointerEvent) => {
if (e.pointerType === 'mouse') { setMenu(false)
setMenu(false)
}
} }
const enterMenuContent = (e: PointerEvent) => { const enterMenuContent = (e: PointerEvent) => {
setMenu(true) setMenu(true)
} }
const exitMenuContent = (e: PointerEvent) => { const leaveMenuContent = (e: PointerEvent) => {
if (e.pointerType === 'mouse') { if (page != 3) {
setMenu(false) setMenu(false)
} }
} }
@@ -115,19 +123,19 @@ export default function Header(props: HeaderProps) {
text="产品订购" text="产品订购"
active={menu && page === 0} active={menu && page === 0}
onPointerEnter={enterMenu(0)} onPointerEnter={enterMenu(0)}
onPointerLeave={exitMenu} onPointerLeave={leaveMenu}
/> />
<MenuItem <MenuItem
text="业务场景" text="业务场景"
active={menu && page === 1} active={menu && page === 1}
onPointerEnter={enterMenu(1)} onPointerEnter={enterMenu(1)}
onPointerLeave={exitMenu} onPointerLeave={leaveMenu}
/> />
<MenuItem <MenuItem
text="帮助中心" text="帮助中心"
active={menu && page === 2} active={menu && page === 2}
onPointerEnter={enterMenu(2)} onPointerEnter={enterMenu(2)}
onPointerLeave={exitMenu} onPointerLeave={leaveMenu}
/> />
<LinkItem <LinkItem
text="业务定制" text="业务定制"
@@ -138,8 +146,7 @@ export default function Header(props: HeaderProps) {
<Button <Button
theme="ghost" theme="ghost"
className="lg:hidden size-10" className="lg:hidden size-10"
onPointerEnter={enterMenu(3)} onClick={toggleMobileMenu}
onPointerLeave={exitMenu}
> >
<MenuIcon/> <MenuIcon/>
</Button> </Button>
@@ -168,7 +175,7 @@ export default function Header(props: HeaderProps) {
: `delay-[0s,0s] opacity-0 py-0 pointer-events-none`, : `delay-[0s,0s] opacity-0 py-0 pointer-events-none`,
)} )}
onPointerEnter={enterMenuContent} onPointerEnter={enterMenuContent}
onPointerLeave={exitMenuContent} onPointerLeave={leaveMenuContent}
> >
{pages[page]} {pages[page]}
</div> </div>

View File

@@ -1,16 +1,15 @@
import {ReactNode} from 'react' import {ReactNode} from 'react'
import Wrap from '@/components/wrap' import Wrap from '@/components/wrap'
import Image, {StaticImageData} from 'next/image' import Image, {StaticImageData} from 'next/image'
import Link from 'next/link'
import check_main from '@/assets/check-main.svg' import check_main from '@/assets/check-main.svg'
import banner from './_assets/banner.webp' import banner from './_assets/banner.webp'
import map from './_assets/map.webp' import map from './_assets/map.webp'
import next from './_assets/next.svg'
import s1_1 from './_assets/s1-1.webp' import s1_1 from './_assets/s1-1.webp'
import s1_2 from './_assets/s1-2.webp' import s1_2 from './_assets/s1-2.webp'
import s1_3 from './_assets/s1-3.webp' import s1_3 from './_assets/s1-3.webp'
import s1_4 from './_assets/s1-4.webp' import s1_4 from './_assets/s1-4.webp'
import s1_check from './_assets/s1-check.svg' import s1_check from './_assets/s1-check.svg'
import s3_main from './_assets/s3-main.webp'
import s4_1_main from './_assets/s4-1-main.webp' import s4_1_main from './_assets/s4-1-main.webp'
import s4_2_main from './_assets/s4-2-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_1 from './_assets/s4-1-1.webp'
@@ -20,6 +19,7 @@ import s4_2_1 from './_assets/s4-2-1.webp'
import s4_2_2 from './_assets/s4-2-2.webp' import s4_2_2 from './_assets/s4-2-2.webp'
import s4_2_3 from './_assets/s4-2-3.webp' import s4_2_3 from './_assets/s4-2-3.webp'
import FreeTrial from '@/components/free-trial' import FreeTrial from '@/components/free-trial'
import {BookOpen, Smartphone, Settings, HelpCircle, Newspaper, FileText} from 'lucide-react'
export default function Home() { export default function Home() {
return ( return (
@@ -141,37 +141,27 @@ export default function Home() {
{/* 推荐文章 */} {/* 推荐文章 */}
<Section title="推荐文章"> <Section title="推荐文章">
<div className="flex gap-8 max-md:gap-4"> <div className="grid grid-cols-1 md:grid-cols-3 gap-8">
<button className="px-4 max-md:-mx-4"> <ArticleCard
<Image src={next} alt="prev" className="rotate-180"/> icon={<BookOpen className="w-12 h-12"/>}
</button> title="浏览器设置代理教程"
description="快速上手5分钟学会在浏览器中配置代理服务器"
href="/docs/browser-proxy"
/>
<div <ArticleCard
className={[ icon={<Smartphone className="w-12 h-12"/>}
`shadow-[4px_4px_20px_4px] shadow-blue-50 rounded-lg`, title="Windows10 代理配置"
`flex p-14 md:gap-14 max-md:flex-col max-md:p-4`, description="详细图文教程,帮助你在 Windows 系统中设置代理"
].join(' ')}> href="/docs/windows10-proxy"
<Image src={s3_main} alt="tumb" className="w-2/3 md:flex-1 md:w-0 object-cover max-md:self-center"/> />
<div className="flex-2 flex flex-col justify-between gap-4">
<h3 className="flex justify-between">
<span className="text-xl"></span>
<sub className="text-sm text-gray-500">2025-03-04</sub>
</h3>
<p className="text-gray-400 md:leading-12">
...
</p>
<div className="flex justify-end">
<a href="#" className="text-sm text-gray-500 flex items-center gap-4">
<Image src={next} alt="more" className="h-4 fill-gray-400"/>
</a>
</div>
</div>
</div>
<button className="px-4 max-md:-mx-4"> <ArticleCard
<Image src={next} alt="prev"/> icon={<HelpCircle className="w-12 h-12"/>}
</button> title="常见问题总览"
description="解决使用过程中遇到的各类问题,快速找到答案"
href="/docs/faq-general"
/>
</div> </div>
</Section> </Section>
</main> </main>
@@ -222,6 +212,43 @@ function Sec3Item(props: {
) )
} }
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: { function Sec4Item(props: {
icon: StaticImageData icon: StaticImageData
title: string title: string

View File

@@ -1,4 +1,4 @@
import {ReactNode} from 'react' import {ReactNode, Suspense} from 'react'
import {Metadata} from 'next' import {Metadata} from 'next'
export async function generateMetadata(): Promise<Metadata> { export async function generateMetadata(): Promise<Metadata> {
@@ -12,5 +12,9 @@ export type BillsLayoutProps = {
} }
export default async function BillsLayout(props: BillsLayoutProps) { export default async function BillsLayout(props: BillsLayoutProps) {
return props.children return (
<Suspense>
{props.children}
</Suspense>
)
} }

View File

@@ -18,7 +18,7 @@ export default async function DashboardPage(props: DashboardPageProps) {
if (!resp.success) { if (!resp.success) {
return ( return (
<div className="col-start-4 row-start-3 row-span-2 flex justify-center items-center"> <div className="col-start-4 row-start-3 row-span-2 flex justify-center items-center">
</div> </div>
) )
} }