Przeglądaj źródła

首页代码调整

zhangzf 1 dzień temu
rodzic
commit
84eaea38d7

+ 25 - 7
src/app/(public)/_components/HomeContent.tsx

@@ -9,6 +9,8 @@ import HomeNewArrival from "./HomeNewArrival";
 import MiddleImageSwiper from "./MiddleImageSwiper";
 import Trending from "./Trending";
 import RecommendedProducts from "./RecommendedProducts";
+import Image from "next/image";
+import Link from "next/link";
 // import CategoryTabSwiper  from "./CategoryTabSwiper ";
 import type {HomeApiData,HomeProduct } from "@/types/home/type"
 import {CustomerService} from "@/components/common/CustomerService/CustomerService";
@@ -114,16 +116,18 @@ export default function HomeContent({ homeData }: HomeContentProps) {
    // 3. 筛选new Arrival板块
   const newArrivalSection = sections.find(sec => sec.sort_order === 6);
    // 4. 筛选7板块
-  const zeroWearImageSection = sections.find(sec => sec.sort_order === 8);
+  const zeroWearImageSection = sections.find(sec => sec.sort_order === 7);
   const zeroWearImage= zeroWearImageSection?.images ?? [];
    // 4. 筛选7板块
-  const zeroWearSection = sections.find(sec => sec.name === "7");
+  const zeroWearSection = sections.find(sec => sec.sort_order === 8);
   const zeroWear: HomeProduct[] = zeroWearSection?.products ?? [];
    // 4. 筛选trendingSection板块
-  const trendingSection = sections.find(sec => sec.name === "Trending_Now");
- 
+  const trendingSection = sections.find(sec => sec.sort_order === 9);
+   // 4. 筛选7板块
+  const bottomBannerSection = sections.find(sec => sec.sort_order === 10);
+  const bottomBanner= bottomBannerSection?.images ?? [];
    // 4. Recommended
-  const recommendedSection = sections.find(sec => sec.name === "Recommended_For_You");
+  const recommendedSection = sections.find(sec => sec.sort_order === 11);
   // const recommended: HomeProduct[] = recommendedSection?.products ?? [];
 
   return (<>
@@ -132,8 +136,6 @@ export default function HomeContent({ homeData }: HomeContentProps) {
       <div className="w-full relative">
         <TopImageSwiper  bannerImages={bannerImages}  />
       </div>
-
-      {/* 服务标签栏 */}
       <div className="flex justify-center items-center gap-[200px]  p-4 bg-[#EAE9E1]">
         {MOCK_DATA.services.map((item, idx) => (
           <div key={idx} className="flex items-center gap-2">
@@ -142,6 +144,9 @@ export default function HomeContent({ homeData }: HomeContentProps) {
           </div>
         ))}
       </div>
+      {/* 服务标签栏 */}
+      <div className="w-full max-w-480 m-auto">
+      
       {/* 分类快捷入口 */}
       <JinGangSwiper jinGangSection={jinGangSection} />
       {/* 热销商品区 */}
@@ -150,7 +155,20 @@ export default function HomeContent({ homeData }: HomeContentProps) {
       <HomeNewArrival newArrivalSection={newArrivalSection} />
       <MiddleImageSwiper zeroWear={zeroWear}  zeroWearImage={zeroWearImage} />
       <Trending trendingSection={trendingSection}/>
+       {
+        (bottomBanner && bottomBanner.length !== 0) ? (
+          <Link href={bottomBanner[0].link} className="relative w-full aspect-[3/4] mt-8">
+            <Image
+              src={bottomBanner[0].image}
+              alt={bottomBanner[0].title}
+              fill
+              className="object-cover rounded-md"
+            />
+          </Link>
+        ) : null
+      }
       <RecommendedProducts recommendedSection={recommendedSection} />
+      </div>
       {/* <CategoryTabSwiper /> */}
     </div>
     <CustomerService />

+ 16 - 6
src/app/(public)/_components/MiddleImageSwiper.tsx

@@ -137,10 +137,19 @@ const MiddleImageSwiper = ({ zeroWear,zeroWearImage }: zeroWearProps) => {
   if (!zeroWear || zeroWear.length === 0) return null;
   const  productList = zeroWear
   const WearImage = zeroWearImage;
+  const bgImage = WearImage?.[0]?.image;
   console.log(WearImage);
   
   return (
-    <div className="w-full pr-4 pl-4 mx-auto flex  rounded-lg  ">
+    <div className={`w-full px-12 mx-auto   `}     
+   >
+      <div className="w-full flex  rounded-lg   bg-no-repeat bg-size-[100%_100%]  " 
+         style={{
+      backgroundImage: bgImage
+        ? `url(${bgImage})`
+        : undefined,
+    }}
+      >
       <div className="w-[777px] h-full">
         {/* <img
           src={WearImage[0].image || 'https://cdn.asteriahair.com/uploads/202602/11/20260211095330_7ec9031a4ab36e44.gif'}
@@ -148,7 +157,7 @@ const MiddleImageSwiper = ({ zeroWear,zeroWearImage }: zeroWearProps) => {
           className="w-full h-auto object-cover block"
         /> */}
       </div>
-      <div className="py-4 px-4 pl-0 relative max-w-[960px] ">
+      <div className="py-4 px-4 pl-0 relative max-w-[1080px] ">
         <div className="w-full relative">
           <Swiper
             // modules={[Pagination]}
@@ -159,10 +168,10 @@ const MiddleImageSwiper = ({ zeroWear,zeroWearImage }: zeroWearProps) => {
             //   el: ".my-progress-bar",
             // }}
             className="mySwiper middle-image-swiper"
-            breakpoints={{
-              480: { slidesPerView: 1 },
-              768: { slidesPerView: 2 },
-            }}
+            // breakpoints={{
+            //   480: { slidesPerView: 1 },
+            //   768: { slidesPerView: 2 },
+            // }}
           >
             {productList.map((item) => (
               <SwiperSlide key={item.id}>
@@ -258,6 +267,7 @@ const MiddleImageSwiper = ({ zeroWear,zeroWearImage }: zeroWearProps) => {
           {/* <div className="my-progress-bar mt-5 w-full h-1 bg-gray-200 rounded-full bottom-0 [top:unset]"></div> */}
         </div>
       </div>
+      </div>
     </div>
   );
 };

+ 1 - 11
src/app/(public)/_components/Trending.tsx

@@ -113,7 +113,7 @@ const Trending = ({ trendingSection }: newArrivalSectionProps) => {
   return (
     <div className=" relative w-full mx-auto">
       <h2 className="text-4xl text-center font-bold leading-ly-46 mt-12 mb-8">{trendingSection?.title}</h2>
-      <div className="pl-12">
+      <div className="px-12">
         <Swiper
           slidesPerView={SLIDES_PER_VIEW}
           slidesPerGroup={SLIDES_PER_GROUP}
@@ -382,16 +382,6 @@ const Trending = ({ trendingSection }: newArrivalSectionProps) => {
           ))}
         </div>
       )}
-      <div className="relative w-full aspect-[4/3] mt-8">
-        <Image
-          src={
-            "https://cdn.asteriahair.com/uploads/202607/01/20260701165110_3fff435adf276b89.jpg"
-          }
-          alt={"cscscs"}
-          fill
-          className="object-cover rounded-md"
-        />
-      </div>
     </div>
   );
 };

+ 31 - 21
src/components/layout/navbar/TopSwiperBanner.tsx

@@ -1,27 +1,31 @@
 "use client";
 
 import { useEffect, useState } from "react";
-
+import Link from "next/link";
 const ITEM_HEIGHT = 40; // h-10 = 40px
 const INTERVAL = 3000;
 const TRANSITION_DURATION = 500;
+export interface AnnouncementItem {
+  link: string;
+  image?: string;
+  title: string;
+}
+interface AnnouncementBarProps {
+  items?: AnnouncementItem[];
+}
 
-const messages = [
-  "Tax Refund Season, Straight to The Lowest Price! As Low As $99!",
-  "Free Shipping On Orders Over $99",
-  "30 Days Easy Return & Exchange",
-];
-
-export default function AnnouncementBar() {
+export default function AnnouncementBar({ items = [] }: AnnouncementBarProps) {
   const [index, setIndex] = useState(0);
+
   const [enableTransition, setEnableTransition] = useState(true);
 
-  // 最后复制第一条,实现无缝循环
-  const loopMessages = [...messages, messages[0]];
+  const loopItems = [...items, ...(items.length ? [items[0]] : [])];
 
-  // 每隔 3 秒向上滚动一条
+  // 自动滚动
   useEffect(() => {
-    if (messages.length <= 1) return;
+    if (items.length <= 1) {
+      return;
+    }
 
     const timer = window.setInterval(() => {
       setIndex((prev) => prev + 1);
@@ -30,20 +34,19 @@ export default function AnnouncementBar() {
     return () => {
       window.clearInterval(timer);
     };
-  }, []);
+  }, [items.length]);
 
-  // 滚动到复制出来的第一条后,瞬间重置到真正第一条
+  // 无缝循环重置
   useEffect(() => {
-    if (index !== messages.length) return;
+    if (index !== items.length) {
+      return;
+    }
 
     const timer = window.setTimeout(() => {
-      // 先关闭 transition
       setEnableTransition(false);
 
-      // 瞬间回到第一条
       setIndex(0);
 
-      // 下一帧重新开启 transition
       requestAnimationFrame(() => {
         requestAnimationFrame(() => {
           setEnableTransition(true);
@@ -54,7 +57,10 @@ export default function AnnouncementBar() {
     return () => {
       window.clearTimeout(timer);
     };
-  }, [index]);
+  }, [index, items.length]);
+  if (!items.length) {
+    return null;
+  }
 
   return (
     <div className="h-10 w-full overflow-hidden bg-[#036141]">
@@ -68,7 +74,7 @@ export default function AnnouncementBar() {
           transform: `translateY(-${index * ITEM_HEIGHT}px)`,
         }}
       >
-        {loopMessages.map((message, messageIndex) => (
+        {loopItems.map((item, messageIndex) => (
           <div
             key={messageIndex}
             className="
@@ -83,7 +89,11 @@ export default function AnnouncementBar() {
               text-white
             "
           >
-            {message}
+            {item.link ? (
+              <Link href={item.link}>{item.title}</Link>
+            ) : (
+              <span>{item.title}</span>
+            )}
           </div>
         ))}
       </div>

+ 26 - 3
src/components/layout/navbar/index.tsx

@@ -14,11 +14,34 @@ import type { GetTreefrontMenusResult } from "@/types/theme/menus";
 import { authOptions } from "@utils/auth";
 import { getServerSession } from "next-auth";
 import TopSwiperBanner from "./TopSwiperBanner"
+import type { AnnouncementItem } from "./TopSwiperBanner";
+import { restApiFetch } from "@utils/bagisto/index";
 export default async function Navbar() {
-
+    // 2. 服务端 fetch 请求我们自己的 Next.js API
+  const res = await restApiFetch({
+    api: `/shop/theme-customizations?name=Top_Bar`,
+    method: "GET",
+    isRoute: false,
+    takeAuthorization: false,
+  
+  });
+   console.log('topbar-res----------------------------:',res);
+  let topBarData: AnnouncementItem[] = [];
+    try {
+    // 安全取值链
+    const themeItem = res?.body?.[0];
+    const optionsStr = themeItem?.translation?.options;
+    if (optionsStr) {
+      const parsed = JSON.parse(optionsStr);
+      topBarData = parsed?.images ?? [];
+    }
+  } catch (err) {
+    console.error("解析 translation.options 失败", err);
+    topBarData = [];
+  }
+ 
     const session = await getServerSession(authOptions);// 游客是null
     const isGuest = session === null;
-
     const { data: menudata } = await serverGraphqlFetch<
       GetTreefrontMenusResult
     >({
@@ -30,7 +53,7 @@ export default async function Navbar() {
   return (
     <NavbarErrorBoundary>
       <header className="sticky top-0 z-10">
-        <TopSwiperBanner /> 
+        <TopSwiperBanner items={topBarData} /> 
         <nav className="relative flex flex-col items-center justify-between gap-4 bg-neutral-50 p-4 pt-3 pb-3 dark:bg-neutral-900 md:flex-row lg:px-6 lg:py-4">
           <div className="flex w-full items-center justify-between gap-0 sm:gap-4">
             {/* 1. THE STATIC SHELL (Visible Instantly) */}