增加getComponentName.js,fetchComponentData默认开启自动下载文件到本地功能,重构Features组件
This commit is contained in:
parent
03f3bd679c
commit
9345e8fc3c
@ -1,94 +0,0 @@
|
|||||||
"use client";
|
|
||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import Image from "next/image";
|
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
export default function Features() {
|
|
||||||
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: "Features" },
|
|
||||||
});
|
|
||||||
setData(res.data.data);
|
|
||||||
} catch (err) {
|
|
||||||
setError("获取Features数据失败");
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fetchData();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
if (loading) return <div className="text-center py-20">Loading...</div>;
|
|
||||||
if (error) return null;
|
|
||||||
if (!data) return null;
|
|
||||||
|
|
||||||
// 主图
|
|
||||||
const mainImage = data.image || "/assets/img/photos/about2.jpg";
|
|
||||||
// 标题/副标题/描述
|
|
||||||
const title = data.title || "";
|
|
||||||
const subtitle = data.subtitle || "";
|
|
||||||
const description = data.description || "";
|
|
||||||
const icon = data.icon || "/files/icon.svg";
|
|
||||||
const htmlCode = data.html_code || "";
|
|
||||||
const buttonText = data.button_text || "MORE";
|
|
||||||
const buttonLink = data.button_link || "#";
|
|
||||||
// items 子表
|
|
||||||
// const items = data.items || [];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex flex-wrap items-center justify-between mx-[-15px] xl:mx-[-35px] lg:mx-[-20px] !mt-[-50px]">
|
|
||||||
{/* 左侧内容区 */}
|
|
||||||
<div className="xl:w-6/12 lg:w-6/12 w-full flex-[0_0_auto] xl:!px-[35px] lg:!px-[20px] !px-[15px] !mt-[50px] max-w-full flex flex-col justify-center">
|
|
||||||
{htmlCode ? (
|
|
||||||
<div
|
|
||||||
style={{ display: "inline-block", width: "2.6rem", height: "2.6rem", marginBottom: "1rem" }}
|
|
||||||
dangerouslySetInnerHTML={{ __html: htmlCode }}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<img
|
|
||||||
src={icon}
|
|
||||||
alt="icon"
|
|
||||||
style={{ display: "inline-block", width: "2.6rem", height: "2.6rem", marginBottom: "1rem" }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<h2 className="!text-[calc(1.305rem_+_0.66vw)] font-bold xl:!text-[1.8rem] !leading-[1.3] !mb-3">
|
|
||||||
{title}
|
|
||||||
</h2>
|
|
||||||
<div className="lead !text-[1.05rem] !leading-[1.6] font-medium !mb-4" dangerouslySetInnerHTML={{ __html: subtitle }} />
|
|
||||||
<div className="!mb-6" dangerouslySetInnerHTML={{ __html: description }} />
|
|
||||||
<div className="mt-4">
|
|
||||||
<a
|
|
||||||
href={buttonLink}
|
|
||||||
className="inline-flex items-center px-6 py-2 bg-[#1fc76f] rounded shadow hover:bg-[#1e9e4a] transition-colors duration-200 text-base font-medium"
|
|
||||||
style={{ color: "#f8fafc" }}
|
|
||||||
>
|
|
||||||
{buttonText}
|
|
||||||
<span className="ml-2">
|
|
||||||
<svg width="18" height="18" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7 13l5-4-5-4" stroke="#f8fafc" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/* 右侧图片区 */}
|
|
||||||
<div className="xl:w-6/12 lg:w-6/12 w-full flex-[0_0_auto] xl:!px-[35px] lg:!px-[20px] !px-[15px] !mt-[50px] max-w-full flex justify-center">
|
|
||||||
<figure className="!rounded-[.4rem] shadow-[0_0_1.25rem_rgba(30,34,40,0.04)] relative">
|
|
||||||
<Image
|
|
||||||
className="!rounded-[.4rem]"
|
|
||||||
src={mainImage}
|
|
||||||
alt="image"
|
|
||||||
width={550}
|
|
||||||
height={400}
|
|
||||||
style={{ objectFit: "cover", maxWidth: "100%", height: "auto" }}
|
|
||||||
/>
|
|
||||||
</figure>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
94
components/homes/home-15/Features/UI.jsx
Normal file
94
components/homes/home-15/Features/UI.jsx
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
"use client";
|
||||||
|
import React from "react";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
|
export default function UI({ data }) {
|
||||||
|
if (!data) return null;
|
||||||
|
|
||||||
|
// 主图
|
||||||
|
const mainImage = data.image || "/assets/img/photos/about2.jpg";
|
||||||
|
const secondImage = data.image_1 || "/assets/img/photos/about3.jpg";
|
||||||
|
// 标题/副标题/描述
|
||||||
|
const title = data.title || "";
|
||||||
|
const subtitle = data.subtitle || "";
|
||||||
|
const description = data.description || "";
|
||||||
|
const icon = data.icon || "/files/icon.svg";
|
||||||
|
const htmlCode = data.html_code || "";
|
||||||
|
const buttonText = data.button_text || "MORE";
|
||||||
|
const buttonLink = data.button_link || "#";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-wrap mx-[-15px] xl:mx-[-35px] lg:mx-[-20px] !mt-[-50px] !mb-[4.5rem] xl:!mb-[7rem] lg:!mb-[7rem] md:!mb-[7rem] items-center">
|
||||||
|
{/* 右侧图片区 - 错开叠放 */}
|
||||||
|
<div className="xl:w-6/12 lg:w-6/12 w-full flex-[0_0_auto] xl:!px-[35px] lg:!px-[20px] !px-[15px] !mt-[50px] max-w-full !relative xl:!order-2 lg:!order-2">
|
||||||
|
{/* 装饰性背景点 */}
|
||||||
|
<div
|
||||||
|
className="shape bg-dot primary bg-[radial-gradient(#3f78e0_2px,transparent_2.5px)] rellax !w-[6rem] !h-[10rem] absolute z-[1] opacity-50"
|
||||||
|
data-rellax-speed={1}
|
||||||
|
style={{ top: "3rem", left: "5.5rem" }}
|
||||||
|
/>
|
||||||
|
{/* 错开叠放的图片容器 */}
|
||||||
|
<div className="flex flex-wrap !relative overlap-grid-2">
|
||||||
|
{/* 第一张图片 - 较大,位置偏右 */}
|
||||||
|
<div className="item xl:w-[70%] xl:z-[3] xl:ml-[30%] xl:!mt-0 lg:w-[70%] lg:z-[3] lg:ml-[30%] lg:!mt-0 md:w-[70%] md:z-[3] md:ml-[30%] md:!mt-0">
|
||||||
|
<figure className="!rounded-[.4rem] shadow-[0_0_1.25rem_rgba(30,34,40,0.04)] relative">
|
||||||
|
<Image
|
||||||
|
className="!rounded-[.4rem]"
|
||||||
|
src={mainImage}
|
||||||
|
alt="image"
|
||||||
|
width={450}
|
||||||
|
height={450}
|
||||||
|
style={{ objectFit: "cover" }}
|
||||||
|
/>
|
||||||
|
</figure>
|
||||||
|
</div>
|
||||||
|
{/* 第二张图片 - 较小,位置偏左,覆盖第一张图片 */}
|
||||||
|
<div className="item xl:w-[55%] xl:!mt-[-45%] xl:z-[4] xl:ml-0 lg:w-[55%] lg:!mt-[-45%] lg:z-[4] lg:ml-0 md:w-[55%] md:!mt-[-45%] md:z-[4] md:ml-0">
|
||||||
|
<figure className="!rounded-[.4rem] shadow-[0_0_1.25rem_rgba(30,34,40,0.04)] relative">
|
||||||
|
<Image
|
||||||
|
className="!rounded-[.4rem]"
|
||||||
|
src={secondImage}
|
||||||
|
alt="image"
|
||||||
|
width={450}
|
||||||
|
height={450}
|
||||||
|
style={{ objectFit: "cover" }}
|
||||||
|
/>
|
||||||
|
</figure>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* 左侧内容区 */}
|
||||||
|
<div className="xl:w-6/12 lg:w-6/12 w-full flex-[0_0_auto] xl:!px-[35px] lg:!px-[20px] !px-[15px] !mt-[50px] max-w-full">
|
||||||
|
{htmlCode ? (
|
||||||
|
<div
|
||||||
|
style={{ display: "inline-block", width: "2.6rem", height: "2.6rem", marginBottom: "1rem" }}
|
||||||
|
dangerouslySetInnerHTML={{ __html: htmlCode }}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<img
|
||||||
|
src={icon}
|
||||||
|
alt="icon"
|
||||||
|
style={{ display: "inline-block", width: "2.6rem", height: "2.6rem", marginBottom: "1rem" }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<h2 className="!text-[calc(1.305rem_+_0.66vw)] font-bold xl:!text-[1.8rem] !leading-[1.3] !mb-3">
|
||||||
|
{title}
|
||||||
|
</h2>
|
||||||
|
<div className="lead !text-[1.05rem] !leading-[1.6] font-medium !mb-4" dangerouslySetInnerHTML={{ __html: subtitle }} />
|
||||||
|
<div className="!mb-6" dangerouslySetInnerHTML={{ __html: description }} />
|
||||||
|
<div className="mt-4">
|
||||||
|
<a
|
||||||
|
href={buttonLink}
|
||||||
|
className="inline-flex items-center px-6 py-2 bg-[#1fc76f] rounded shadow hover:bg-[#1e9e4a] transition-colors duration-200 text-base font-medium"
|
||||||
|
style={{ color: "#f8fafc" }}
|
||||||
|
>
|
||||||
|
{buttonText}
|
||||||
|
<span className="ml-2">
|
||||||
|
<svg width="18" height="18" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7 13l5-4-5-4" stroke="#f8fafc" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
16
components/homes/home-15/Features/index.jsx
Normal file
16
components/homes/home-15/Features/index.jsx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { getComponentName } from "@/utils/getComponentName";
|
||||||
|
import { fetchComponentData } from "@/utils/data";
|
||||||
|
import UI from "./UI";
|
||||||
|
|
||||||
|
const componentName = getComponentName(import.meta.url);
|
||||||
|
|
||||||
|
export default async function Component() {
|
||||||
|
const result = await fetchComponentData(componentName);
|
||||||
|
|
||||||
|
if (result.error || !result.data) {
|
||||||
|
if (result.error) console.error(`Failed to fetch ${componentName} data:`, result.error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <UI data={result.data} />;
|
||||||
|
}
|
||||||
@ -185,7 +185,7 @@ export async function getAllSlugs() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchComponentData(componentName) {
|
export async function fetchComponentData(componentName, downloadFiles = true) {
|
||||||
try {
|
try {
|
||||||
const res = await axios.get(
|
const res = await axios.get(
|
||||||
`${BACKEND_SERVER_URL}/api/action/jsite.api.v1.get_component_data`,
|
`${BACKEND_SERVER_URL}/api/action/jsite.api.v1.get_component_data`,
|
||||||
@ -193,7 +193,14 @@ export async function fetchComponentData(componentName) {
|
|||||||
params: { component_name: componentName, site_name: BACKEND_SITE_NAME },
|
params: { component_name: componentName, site_name: BACKEND_SITE_NAME },
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return { data: res.data.message?.data || null };
|
|
||||||
|
let data = res.data.message?.data || null;
|
||||||
|
|
||||||
|
if (data && downloadFiles) {
|
||||||
|
data = await processDataItem(data, downloadFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { data };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (
|
if (
|
||||||
error.response &&
|
error.response &&
|
||||||
|
|||||||
8
utils/getComponentName.js
Normal file
8
utils/getComponentName.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import path from "path";
|
||||||
|
import { fileURLToPath } from "url";
|
||||||
|
|
||||||
|
export function getComponentName(metaUrl) {
|
||||||
|
const __filename = fileURLToPath(metaUrl);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
return path.basename(__dirname);
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user