143 lines
5.6 KiB
TypeScript
143 lines
5.6 KiB
TypeScript
import { useState } from "react"
|
||
import { useSearchParams } from "react-router-dom"
|
||
import Wrap from "@/components/wrap"
|
||
import { PRODUCT_DATA } from "@/lib/models/product"
|
||
import { cn } from "@/lib/utils"
|
||
import ProductGrid from "./productGrid"
|
||
import ProductSidebar from "./productSidebar"
|
||
import ProductTabs from "./productTabs"
|
||
import PurchaseInfo from "./purchaseInfo"
|
||
|
||
const TAB_ALIAS: Record<string, string> = {
|
||
short: "dynamic",
|
||
long: "dynamic",
|
||
http: "http",
|
||
tunnel: "dynamic",
|
||
exclusive: "static",
|
||
}
|
||
|
||
export default function ProductPage() {
|
||
const [searchParams, setSearchParams] = useSearchParams()
|
||
const [activeVersionId, setActiveVersionId] = useState<string>("v1")
|
||
|
||
const urlTab = searchParams.get("tab") || "dynamic"
|
||
const activeTabId = TAB_ALIAS[urlTab] || urlTab
|
||
const activeBrandId = searchParams.get("brand") || ""
|
||
|
||
const currentTab =
|
||
PRODUCT_DATA.find(t => t.id === activeTabId) || PRODUCT_DATA[0]
|
||
const currentBrand =
|
||
currentTab.brands.find(b => b.id === activeBrandId) || currentTab.brands[0]
|
||
|
||
const handleTabChange = (tabId: string) => {
|
||
const targetTab = PRODUCT_DATA.find(t => t.id === tabId)
|
||
const firstBrand = targetTab?.brands[0]
|
||
setSearchParams({ tab: tabId, brand: firstBrand?.id || "" })
|
||
setActiveVersionId("v1")
|
||
}
|
||
|
||
const handleBrandSelect = (brandId: string) => {
|
||
setSearchParams({ tab: activeTabId, brand: brandId })
|
||
setActiveVersionId("v1")
|
||
}
|
||
|
||
const getDisplayProducts = () => {
|
||
if (!currentBrand) return []
|
||
|
||
if (currentBrand.versions && currentBrand.versions.length > 0) {
|
||
return currentBrand.products.filter(p => p.version === activeVersionId)
|
||
}
|
||
return currentBrand.products
|
||
}
|
||
|
||
const displayProducts = getDisplayProducts()
|
||
const isPurchaseInfo = currentBrand?.id === "info"
|
||
return (
|
||
<Wrap className="flex flex-col gap-16 pt-30 bg-white">
|
||
<div className="flex flex-col">
|
||
<ProductTabs
|
||
tabs={PRODUCT_DATA}
|
||
activeId={activeTabId}
|
||
onTabChange={handleTabChange}
|
||
/>
|
||
|
||
<div className="flex mt-8 mb-8 mx-auto w-full">
|
||
<div className="shrink-0 border-r border-gray-200">
|
||
<ProductSidebar
|
||
brands={currentTab.brands}
|
||
activeId={currentBrand?.id || ""}
|
||
onSelect={handleBrandSelect}
|
||
/>
|
||
</div>
|
||
|
||
<div className="flex-1 flex flex-col">
|
||
{!isPurchaseInfo ? (
|
||
<>
|
||
{" "}
|
||
<div className="grid grid-cols-2 pl-3 text-sm gap-2 text-gray-600 leading-relaxed">
|
||
<ul className="space-y-2">
|
||
<li className="flex items-start gap-2">
|
||
<span className="w-2 h-2 mt-1.5 bg-emerald-400 rounded-full shrink-0" />
|
||
连接方式:电脑和安卓请优选客户端,苹果,路由器可通过线路表直连
|
||
</li>
|
||
<li className="flex items-start gap-2">
|
||
<span className="w-2 h-2 mt-1.5 bg-emerald-400 rounded-full shrink-0" />
|
||
本产品在个人中心签署协议后可联系客服解除限制
|
||
</li>
|
||
</ul>
|
||
<ul className="space-y-2">
|
||
<li className="flex items-start gap-2">
|
||
<span className="w-2 h-2 mt-1.5 bg-emerald-400 rounded-full shrink-0" />
|
||
IP池超大且纯净,所有线路均为三网混合,更真实有效
|
||
</li>
|
||
<li className="flex items-start gap-2">
|
||
<span className="w-2 h-2 mt-1.5 bg-emerald-400 rounded-full shrink-0" />
|
||
230+城市,500+线路,有全国混拨和省混拨
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<div className="bg-orange-50 border gap-3 border-orange-100 text-orange-400 p-3 text-center font-bold mt-3 mb-3 text-sm w-full">
|
||
需求5个以上,可以联系客服设置优惠价
|
||
</div>
|
||
{currentBrand?.versions && currentBrand.versions.length > 0 && (
|
||
<div className="w-full mt-2 pl-6">
|
||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||
{currentBrand.versions.map(v => (
|
||
<button
|
||
key={v.id}
|
||
onClick={() => setActiveVersionId(v.id)}
|
||
className={cn(
|
||
"w-full py-2 rounded-full text-sm font-medium transition-all cursor-pointer text-center",
|
||
activeVersionId === v.id
|
||
? "bg-linear-to-r from-blue-500 to-cyan-400 text-white shadow-sm"
|
||
: "bg-gray-100 text-gray-600 hover:bg-gray-200",
|
||
)}
|
||
>
|
||
{v.label}
|
||
</button>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)}
|
||
<main className="pl-6">
|
||
{displayProducts.length > 0 ? (
|
||
<ProductGrid products={displayProducts} />
|
||
) : (
|
||
<div className="text-center py-20 text-gray-400">
|
||
该版本暂无产品数据
|
||
</div>
|
||
)}
|
||
</main>
|
||
</>
|
||
) : (
|
||
<div className="pl-6 pr-6">
|
||
<PurchaseInfo />
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</Wrap>
|
||
)
|
||
}
|