diff --git a/app/[...slug]/page.jsx b/app/[...slug]/page.jsx index df784b1..1229260 100644 --- a/app/[...slug]/page.jsx +++ b/app/[...slug]/page.jsx @@ -12,8 +12,7 @@ const LoadingSpinner = () => ( ); -export const revalidate = 10; -export const dynamicParams = true; +export const revalidate = Number(process.env.JSITE_REVALIDATE_SECONDS) || 3600; export async function generateStaticParams() { const slugs = await getAllSlugs(); diff --git a/app/page.jsx b/app/page.jsx index eec91d9..d600861 100644 --- a/app/page.jsx +++ b/app/page.jsx @@ -4,7 +4,7 @@ import CategoryItems from "@/components/homes/home-15/CategoryItems"; import React from "react"; import { getSiteSettings } from "@/utils/siteSettings"; -export const revalidate = 3600; +export const revalidate = Number(process.env.JSITE_REVALIDATE_SECONDS) || 3600; export async function generateMetadata() { const siteUrl = process.env.SITE_URL; @@ -36,7 +36,7 @@ export default function Page() {
- +
{" "} diff --git a/components/banner/Banner.jsx b/components/banner/Banner.jsx index 67cb2fd..e002a7d 100644 --- a/components/banner/Banner.jsx +++ b/components/banner/Banner.jsx @@ -1,35 +1,13 @@ -"use client"; -import React, { useEffect, useState } from "react"; -import Image from "next/image"; -import axios from "axios"; +import { fetchComponentData, downloadToLocal } from "@/utils/data"; -export default function Banner({ componentName = "Banner", className = "" }) { - const [data, setData] = useState(null); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); +export default async function Banner({ componentName = "Banner", className = "" }) { + const res = await fetchComponentData(componentName); + const data = res.data; - useEffect(() => { - async function fetchData() { - try { - setLoading(true); - const res = await axios.get("/api/get-component-data", { - params: { component_name: componentName }, - }); - setData(res.data.data); - } catch (err) { - setError(`Failed to fetch ${componentName} data`); - } finally { - setLoading(false); - } - } - fetchData(); - }, [componentName]); - - if (loading) return null; - if (error) return null; if (!data) return null; - const bannerImg = data.image; + // 仅针对背景图片进行本地化处理 + const bannerImg = data.image ? await downloadToLocal(data.image) : ""; return (
-
+

{data.title}

diff --git a/components/homes/home-15/Hero.jsx b/components/homes/home-15/Hero/HeroUI.jsx similarity index 89% rename from components/homes/home-15/Hero.jsx rename to components/homes/home-15/Hero/HeroUI.jsx index c491545..fcc52cb 100644 --- a/components/homes/home-15/Hero.jsx +++ b/components/homes/home-15/Hero/HeroUI.jsx @@ -1,37 +1,12 @@ "use client"; -import React, { useEffect, useState } from "react"; import Image from "next/image"; import AnimatedText from "@/components/common/AnimatedText"; import Link from "next/link"; -import axios from "axios"; -export default function Hero() { - const [data, setData] = useState(null); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); - - useEffect(() => { - async function fetchData() { - try { - setLoading(true); - const res = await axios.get("/api/get-component-data", { - params: { component_name: "Hero" }, - }); - setData(res.data.data); - } catch (err) { - setError("获取Features数据失败"); - } finally { - setLoading(false); - } - } - fetchData(); - }, []); - - if (loading) return
加载中...
; - if (error) return null; +export default function HeroUI({ data }) { if (!data) return null; - const bgImage = data.bg_image || "/assets/img/photos/blurry.png"; + const bgImage = data.image || "/assets/img/photos/blurry.png"; const title = data.title || ""; const subtitle = data.subtitle || ""; const buttonText = data.button_text || "MORE"; @@ -39,7 +14,6 @@ export default function Hero() { const buttonText2 = data.button_2_text || "MORE"; const buttonLink2 = data.button_2_link || "#"; - return (
); -} +} \ No newline at end of file diff --git a/components/homes/home-15/Hero/index.jsx b/components/homes/home-15/Hero/index.jsx new file mode 100644 index 0000000..cbdef0d --- /dev/null +++ b/components/homes/home-15/Hero/index.jsx @@ -0,0 +1,13 @@ +import { fetchComponentData } from "@/utils/data"; +import HeroUI from "./HeroUI"; + +export default async function Hero() { + const result = await fetchComponentData("Hero"); + + if (result.error || !result.data) { + if(result.error) console.error("Failed to fetch Hero data:", result.error); + return null; + } + + return ; +} \ No newline at end of file diff --git a/components/sidebar/Category.jsx b/components/sidebar/Category.jsx index ed5df50..4dd76be 100644 --- a/components/sidebar/Category.jsx +++ b/components/sidebar/Category.jsx @@ -1,88 +1,52 @@ -"use client"; -import React, { useEffect, useState } from "react"; -import axios from "axios"; +import { fetchComponentData, fetchCategoryData } from "@/utils/data"; /** * Product category sidebar component * @param {string} componentName - component name * @param {string} className - additional class names */ -export default function Category({ +export default async function Category({ componentName = "Category", className = "", }) { - const [data, setData] = useState(null); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); - const [activeCategory, setActiveCategory] = useState(null); + // 1. 获取组件元数据 + const metaRes = await fetchComponentData(componentName); + const metaData = metaRes.data; - useEffect(() => { - async function fetchData() { - try { - setLoading(true); - // 1. 获取组件元数据 - const metaRes = await axios.get("/api/get-component-data", { - params: { component_name: componentName }, - }); - const metaData = metaRes.data.data || {}; - // 2. 获取分类树 - if (metaData.p1 && metaData.p2) { - const catRes = await axios.get("/api/get-category", { - params: { pagetype: metaData.p1, name: metaData.p2 }, - }); - const categoryData = catRes.data.message?.data || {}; - setData({ - title: metaData.title || "Product Categories", - subtitle: metaData.subtitle || "", - slug: categoryData.slug, - items: categoryData.children || [], - }); - } - } catch (err) { - console.error("获取分类数据失败:", err); - setError("Failed to fetch category data"); - } finally { - setLoading(false); - } - } - fetchData(); - }, [componentName]); + // 如果按 componentName 未找到组件数据,或数据未有效配置分类,则不渲染组件 + if (!metaData || !metaData.p1 || !metaData.p2) { + return null; + } - if (loading) return null; - if (error) return null; - if (!data) return null; - - const handleCategoryClick = (categorySlug) => { - if (activeCategory === categorySlug) { - setActiveCategory(null); - } else { - setActiveCategory(categorySlug); - } + // 2. 获取分类树 + let data = { + title: metaData.title || "Product Categories", + subtitle: metaData.subtitle || "", + slug: "", + items: [], + }; + const catRes = await fetchCategoryData({ pagetype: metaData.p1, name: metaData.p2 }); + const categoryData = catRes.data || {}; + data = { + ...data, + slug: categoryData.slug, + items: categoryData.children || [], }; // 渲染分类列表 const renderCategories = (items, parentSlugs = []) => { if (!items || !items.length) return null; - return (
    {items.map((item) => { const hasChildren = Array.isArray(item.children) && item.children.length > 0; - const isActive = activeCategory === item.slug; const currentPath = [...parentSlugs, item.slug]; - return (
  • -
    { - if (hasChildren) handleCategoryClick(item.slug); - }} - > +
    e.stopPropagation()} // 阻止冒泡,点击a只跳转 > {item.name} @@ -90,8 +54,7 @@ export default function Category({ {'>'} )}
    - - {hasChildren && isActive && ( + {hasChildren && (
      {item.children.map((child) => ( @@ -99,7 +62,6 @@ export default function Category({ e.stopPropagation()} > {child.name} diff --git a/public/files/banner-about.jpg b/public/files/banner-about.jpg new file mode 100644 index 0000000..d08416e Binary files /dev/null and b/public/files/banner-about.jpg differ diff --git a/utils/data.js b/utils/data.js index 28d1eff..693a3a0 100644 --- a/utils/data.js +++ b/utils/data.js @@ -9,7 +9,7 @@ if (!fs.existsSync(PUBLIC_FILES_DIR)) { fs.mkdirSync(PUBLIC_FILES_DIR, { recursive: true }); } -async function downloadToLocal(fileUrl) { +export async function downloadToLocal(fileUrl) { if (!fileUrl) return fileUrl; try { let fullUrl = fileUrl; @@ -51,7 +51,7 @@ function extractImageUrlsFromHtml(html) { return urls; } -async function processDataItem(item, downloadFiles) { +export async function processDataItem(item, downloadFiles) { if (!downloadFiles) return item; if (item.image) { @@ -174,38 +174,67 @@ export async function getAllSlugs() { export async function fetchComponentData(componentName) { try { - // We use no-store to ensure data is fresh, suitable for dynamic component settings. - // For more static data, you might adjust the cache policy. - const res = await fetch(`${JINGROW_SERVER_URL}/api/method/jsite.api.v1.get_component_data?component_name=${componentName}`, { cache: 'no-store' }); - if (!res.ok) { - const errorText = await res.text(); - console.error(`Failed to fetch component data for ${componentName}: ${res.statusText}`, errorText); + const res = await axios.get( + `${JINGROW_SERVER_URL}/api/method/jsite.api.v1.get_component_data`, + { + params: { component_name: componentName }, + } + ); + return { data: res.data.message?.data || null }; + } catch (error) { + if ( + error.response && + (error.response.status === 403 || error.response.status === 404) + ) { return { data: null }; } - const result = await res.json(); - return { data: result.message?.data || null }; - } catch (error) { - console.error(`Error fetching component data for ${componentName}:`, error); + console.error( + `Error fetching component data for ${componentName}:`, + error.message + ); return { data: null }; } } export async function fetchListViewData({ pagetype, category, count }) { try { - const queryParams = new URLSearchParams({ pagetype }); - if (category) queryParams.append("category", category); - if (count !== undefined && count !== null) queryParams.append("count", String(count)); - - const res = await fetch(`${JINGROW_SERVER_URL}/api/method/jsite.api.v1.get_listview_data?${queryParams.toString()}`, { cache: 'no-store' }); - if (!res.ok) { - const errorText = await res.text(); - console.error(`Failed to fetch list view data: ${res.statusText}`, errorText); + const params = { pagetype }; + if (category) params.category = category; + if (count !== undefined && count !== null) params.count = String(count); + + const res = await axios.get( + `${JINGROW_SERVER_URL}/api/method/jsite.api.v1.get_listview_data`, + { params } + ); + + return { data: res.data.message?.data || [] }; + } catch (error) { + if ( + error.response && + (error.response.status === 403 || error.response.status === 404) + ) { return { data: [] }; } - const result = await res.json(); - return { data: result.message?.data || [] }; - } catch (error) { - console.error(`Error fetching list view data:`, error); + console.error(`Error fetching list view data:`, error.message); return { data: [] }; } +} + +export async function fetchCategoryData({ pagetype, name }) { + try { + const res = await axios.get( + `${JINGROW_SERVER_URL}/api/method/jsite.api.v1.get_category`, + { params: { pagetype, name } } + ); + return { data: res.data.message?.data || null }; + } catch (error) { + if ( + error.response && + (error.response.status === 403 || error.response.status === 404) + ) { + return { data: null }; + } + console.error(`Error fetching category data:`, error.message); + return { data: null }; + } } \ No newline at end of file