Browse Source

数据联调

zq940222 6 months ago
parent
commit
49f31eab4b

+ 100 - 0
package-lock.json

@@ -16,6 +16,7 @@
         "@radix-ui/react-icons": "^1.3.0",
         "@radix-ui/react-icons": "^1.3.0",
         "@radix-ui/react-navigation-menu": "^1.2.0",
         "@radix-ui/react-navigation-menu": "^1.2.0",
         "@radix-ui/react-slot": "^1.1.0",
         "@radix-ui/react-slot": "^1.1.0",
+        "axios": "^1.7.7",
         "class-variance-authority": "^0.7.0",
         "class-variance-authority": "^0.7.0",
         "clsx": "^2.1.1",
         "clsx": "^2.1.1",
         "lucide-react": "^0.424.0",
         "lucide-react": "^0.424.0",
@@ -2417,6 +2418,12 @@
         "node": ">=8"
         "node": ">=8"
       }
       }
     },
     },
+    "node_modules/asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+      "license": "MIT"
+    },
     "node_modules/autoprefixer": {
     "node_modules/autoprefixer": {
       "version": "10.4.19",
       "version": "10.4.19",
       "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz",
       "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz",
@@ -2454,6 +2461,17 @@
         "postcss": "^8.1.0"
         "postcss": "^8.1.0"
       }
       }
     },
     },
+    "node_modules/axios": {
+      "version": "1.7.7",
+      "resolved": "https://registry.npmmirror.com/axios/-/axios-1.7.7.tgz",
+      "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
+      "license": "MIT",
+      "dependencies": {
+        "follow-redirects": "^1.15.6",
+        "form-data": "^4.0.0",
+        "proxy-from-env": "^1.1.0"
+      }
+    },
     "node_modules/balanced-match": {
     "node_modules/balanced-match": {
       "version": "1.0.2",
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -2648,6 +2666,18 @@
       "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
       "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
       "dev": true
       "dev": true
     },
     },
+    "node_modules/combined-stream": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "license": "MIT",
+      "dependencies": {
+        "delayed-stream": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/commander": {
     "node_modules/commander": {
       "version": "4.1.1",
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
       "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
@@ -2721,6 +2751,15 @@
       "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
       "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
       "dev": true
       "dev": true
     },
     },
+    "node_modules/delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
     "node_modules/detect-node-es": {
     "node_modules/detect-node-es": {
       "version": "1.1.0",
       "version": "1.1.0",
       "resolved": "https://registry.npmmirror.com/detect-node-es/-/detect-node-es-1.1.0.tgz",
       "resolved": "https://registry.npmmirror.com/detect-node-es/-/detect-node-es-1.1.0.tgz",
@@ -3226,6 +3265,26 @@
       "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
       "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
       "dev": true
       "dev": true
     },
     },
+    "node_modules/follow-redirects": {
+      "version": "1.15.9",
+      "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz",
+      "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/RubenVerborgh"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=4.0"
+      },
+      "peerDependenciesMeta": {
+        "debug": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/foreground-child": {
     "node_modules/foreground-child": {
       "version": "3.1.1",
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
       "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
@@ -3241,6 +3300,20 @@
         "url": "https://github.com/sponsors/isaacs"
         "url": "https://github.com/sponsors/isaacs"
       }
       }
     },
     },
+    "node_modules/form-data": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz",
+      "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+      "license": "MIT",
+      "dependencies": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "mime-types": "^2.1.12"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
     "node_modules/fraction.js": {
     "node_modules/fraction.js": {
       "version": "4.3.7",
       "version": "4.3.7",
       "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
       "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
@@ -3728,6 +3801,27 @@
         "node": ">=8.6"
         "node": ">=8.6"
       }
       }
     },
     },
+    "node_modules/mime-db": {
+      "version": "1.52.0",
+      "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz",
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime-types": {
+      "version": "2.1.35",
+      "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz",
+      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+      "license": "MIT",
+      "dependencies": {
+        "mime-db": "1.52.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
     "node_modules/minimatch": {
     "node_modules/minimatch": {
       "version": "9.0.4",
       "version": "9.0.4",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
@@ -4141,6 +4235,12 @@
         "node": ">= 0.8.0"
         "node": ">= 0.8.0"
       }
       }
     },
     },
+    "node_modules/proxy-from-env": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+      "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+      "license": "MIT"
+    },
     "node_modules/punycode": {
     "node_modules/punycode": {
       "version": "2.3.1",
       "version": "2.3.1",
       "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
       "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",

+ 1 - 0
package.json

@@ -34,6 +34,7 @@
     "@radix-ui/react-icons": "^1.3.0",
     "@radix-ui/react-icons": "^1.3.0",
     "@radix-ui/react-navigation-menu": "^1.2.0",
     "@radix-ui/react-navigation-menu": "^1.2.0",
     "@radix-ui/react-slot": "^1.1.0",
     "@radix-ui/react-slot": "^1.1.0",
+    "axios": "^1.7.7",
     "class-variance-authority": "^0.7.0",
     "class-variance-authority": "^0.7.0",
     "clsx": "^2.1.1",
     "clsx": "^2.1.1",
     "lucide-react": "^0.424.0",
     "lucide-react": "^0.424.0",

+ 0 - 2
src/App.tsx

@@ -7,7 +7,6 @@ import { Hero } from "./components/Hero";
 import { HowItWorks } from "./components/HowItWorks";
 import { HowItWorks } from "./components/HowItWorks";
 import { Navbar } from "./components/Navbar";
 import { Navbar } from "./components/Navbar";
 import { Newsletter } from "./components/Newsletter";
 import { Newsletter } from "./components/Newsletter";
-import { Pricing } from "./components/Pricing";
 import { ScrollToTop } from "./components/ScrollToTop";
 import { ScrollToTop } from "./components/ScrollToTop";
 import { Services } from "./components/Services";
 import { Services } from "./components/Services";
 import { Sponsors } from "./components/Sponsors";
 import { Sponsors } from "./components/Sponsors";
@@ -28,7 +27,6 @@ function App() {
       <Cta />
       <Cta />
       <Testimonials />
       <Testimonials />
       <Team />
       <Team />
-      <Pricing />
       <Newsletter />
       <Newsletter />
       <FAQ />
       <FAQ />
       <Footer />
       <Footer />

BIN
src/assets/logo.png


+ 38 - 5
src/components/About.tsx

@@ -1,7 +1,44 @@
 import { Statistics } from "./Statistics";
 import { Statistics } from "./Statistics";
 import pilot from "../assets/pilot.png";
 import pilot from "../assets/pilot.png";
+import {useEffect, useState} from "react";
+import {extractSubstring} from "@/services/api.ts";
+import axios from "axios";
 
 
 export const About = () => {
 export const About = () => {
+  const [intro, setIntro] = useState(null);
+  const [loading, setLoading] = useState(true);
+
+  useEffect(() => {
+    // 使用 axios 进行 API 调用
+    const fetchData = async () => {
+      try {
+        const websiteCode = extractSubstring(window.location.pathname);
+        const response = await axios.get('/api/website/template/getWebsiteByWebsiteCode', {
+          params: {
+            websiteCode: websiteCode
+          }
+        });
+        const userWebsiteId = response.data.data.id;
+        const response2 = await axios.get('/api/website/template/company', {
+          params: {
+            userWebsiteId: userWebsiteId
+          }
+        });
+        setIntro(response2.data.data.intro);
+      } catch (err) {
+        console.error('Error fetching data:', err);
+      } finally {
+        setLoading(false);
+      }
+    };
+
+    fetchData();
+
+  }, []);
+  // 处理加载和错误状态
+  if (loading) {
+    return <div>Loading...</div>;
+  }
   return (
   return (
     <section
     <section
       id="about"
       id="about"
@@ -23,11 +60,7 @@ export const About = () => {
                 Company
                 Company
               </h2>
               </h2>
               <p className="text-xl text-muted-foreground mt-4">
               <p className="text-xl text-muted-foreground mt-4">
-                Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
-                eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
-                enim ad minim veniam, quis nostrud exercitation ullamco laboris
-                nisi ut aliquip ex ea commodo consequat. Lorem ipsum dolor sit
-                amet, consectetur adipiscing elit.
+                {intro}
               </p>
               </p>
             </div>
             </div>
 
 

+ 65 - 21
src/components/Features.tsx

@@ -9,6 +9,9 @@ import {
 import image from "../assets/growth.png";
 import image from "../assets/growth.png";
 import image3 from "../assets/reflecting.png";
 import image3 from "../assets/reflecting.png";
 import image4 from "../assets/looking-ahead.png";
 import image4 from "../assets/looking-ahead.png";
+import {useEffect, useState} from "react";
+import {extractSubstring} from "@/services/api.ts";
+import axios from "axios";
 
 
 interface FeatureProps {
 interface FeatureProps {
   title: string;
   title: string;
@@ -16,27 +19,29 @@ interface FeatureProps {
   image: string;
   image: string;
 }
 }
 
 
-const features: FeatureProps[] = [
-  {
-    title: "Responsive Design",
-    description:
-      "Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi nesciunt est nostrum omnis ab sapiente.",
-    image: image4,
-  },
-  {
-    title: "Intuitive user interface",
-    description:
-      "Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi nesciunt est nostrum omnis ab sapiente.",
-    image: image3,
-  },
-  {
-    title: "AI-Powered insights",
-    description:
-      "Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi nesciunt est nostrum omnis ab sapiente.",
-    image: image,
-  },
-];
+let features: FeatureProps[] = [];
 
 
+// const features: FeatureProps[] = [
+//   {
+//     title: "Responsive Design",
+//     description:
+//       "Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi nesciunt est nostrum omnis ab sapiente.",
+//     image: image4,
+//   },
+//   {
+//     title: "Intuitive user interface",
+//     description:
+//       "Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi nesciunt est nostrum omnis ab sapiente.",
+//     image: image3,
+//   },
+//   {
+//     title: "AI-Powered insights",
+//     description:
+//       "Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi nesciunt est nostrum omnis ab sapiente.",
+//     image: image,
+//   },
+// ];
+const imageList = [image, image3, image4];
 const featureList: string[] = [
 const featureList: string[] = [
   "Dark/Light theme",
   "Dark/Light theme",
   "Reviews",
   "Reviews",
@@ -50,6 +55,44 @@ const featureList: string[] = [
 ];
 ];
 
 
 export const Features = () => {
 export const Features = () => {
+  const [loading, setLoading] = useState(true);
+  useEffect(() => {
+    // 使用 axios 进行 API 调用
+    const fetchData = async () => {
+      try {
+        const websiteCode = extractSubstring(window.location.pathname);
+        const response = await axios.get('/api/website/template/getWebsiteByWebsiteCode', {
+          params: {
+            websiteCode: websiteCode
+          }
+        });
+        const userWebsiteId = response.data.data.id;
+        const response2 = await axios.get('/api/website/template/products', {
+          params: {
+            userWebsiteId: userWebsiteId
+          }
+        });
+        features = response2.data.data.map((item, index) => {
+          return {
+            title: item.name,
+            description: item.description.substring(0, 200) + '...',
+            image: imageList[index % imageList.length],
+          }
+        })
+      } catch (err) {
+        console.error('Error fetching data:', err);
+      } finally {
+        setLoading(false);
+      }
+    };
+
+    fetchData();
+
+  }, []);
+  // 处理加载和错误状态
+  if (loading) {
+    return <div>Loading...</div>;
+  }
   return (
   return (
     <section
     <section
       id="features"
       id="features"
@@ -58,7 +101,7 @@ export const Features = () => {
       <h2 className="text-3xl lg:text-4xl font-bold md:text-center">
       <h2 className="text-3xl lg:text-4xl font-bold md:text-center">
         Many{" "}
         Many{" "}
         <span className="bg-gradient-to-b from-primary/60 to-primary text-transparent bg-clip-text">
         <span className="bg-gradient-to-b from-primary/60 to-primary text-transparent bg-clip-text">
-          Great Features
+          Great Products
         </span>
         </span>
       </h2>
       </h2>
 
 
@@ -97,3 +140,4 @@ export const Features = () => {
     </section>
     </section>
   );
   );
 };
 };
+

+ 3 - 3
src/components/Footer.tsx

@@ -13,7 +13,7 @@ export const Footer = () => {
             className="font-bold text-xl flex"
             className="font-bold text-xl flex"
           >
           >
             <LogoIcon />
             <LogoIcon />
-            ShadcnUI/React
+            Canary/Website
           </a>
           </a>
         </div>
         </div>
 
 
@@ -152,14 +152,14 @@ export const Footer = () => {
 
 
       <section className="container pb-14 text-center">
       <section className="container pb-14 text-center">
         <h3>
         <h3>
-          &copy; 2024 Landing page made by{" "}
+          &copy; 2024 website made by{" "}
           <a
           <a
             rel="noreferrer noopener"
             rel="noreferrer noopener"
             target="_blank"
             target="_blank"
             href="https://www.linkedin.com/in/leopoldo-miranda/"
             href="https://www.linkedin.com/in/leopoldo-miranda/"
             className="text-primary transition-all border-primary hover:border-b-2"
             className="text-primary transition-all border-primary hover:border-b-2"
           >
           >
-            Leo Miranda
+            Canary
           </a>
           </a>
         </h3>
         </h3>
       </section>
       </section>

+ 44 - 35
src/components/Hero.tsx

@@ -1,48 +1,57 @@
-import { Button } from "./ui/button";
-import { buttonVariants } from "./ui/button";
 import { HeroCards } from "./HeroCards";
 import { HeroCards } from "./HeroCards";
-import { GitHubLogoIcon } from "@radix-ui/react-icons";
+import axios from 'axios';
+import { useEffect, useState } from 'react';
+import {extractSubstring} from "./../services/api.ts";
 
 
 export const Hero = () => {
 export const Hero = () => {
+  const [title, setTitle] = useState(null);
+  const [content, setContent] = useState(null);
+  const [loading, setLoading] = useState(true);
+
+  useEffect(() => {
+    // 使用 axios 进行 API 调用
+    const fetchData = async () => {
+      try {
+        const websiteCode = extractSubstring(window.location.pathname);
+        const response = await axios.get('/api/website/template/getWebsiteByWebsiteCode', {
+          params: {
+            websiteCode: websiteCode
+          }
+        });
+        const userWebsiteId = response.data.data.id;
+        const response2 = await axios.get('/api/website/template/home', {
+          params: {
+            userWebsiteId: userWebsiteId
+          }
+        });
+        setTitle(response2.data.data.title);
+        setContent(response2.data.data.content);
+      } catch (err) {
+        console.error('Error fetching data:', err);
+      } finally {
+        setLoading(false);
+      }
+    };
+
+    fetchData();
+
+  }, []);
+  // 处理加载和错误状态
+  if (loading) {
+    return <div>Loading...</div>;
+  }
   return (
   return (
     <section className="container grid lg:grid-cols-2 place-items-center py-20 md:py-32 gap-10">
     <section className="container grid lg:grid-cols-2 place-items-center py-20 md:py-32 gap-10">
       <div className="text-center lg:text-start space-y-6">
       <div className="text-center lg:text-start space-y-6">
-        <main className="text-5xl md:text-6xl font-bold">
-          <h1 className="inline">
-            <span className="inline bg-gradient-to-r from-[#F596D3]  to-[#D247BF] text-transparent bg-clip-text">
-              Shadcn
-            </span>{" "}
-            landing page
-          </h1>{" "}
-          for{" "}
-          <h2 className="inline">
-            <span className="inline bg-gradient-to-r from-[#61DAFB] via-[#1fc0f1] to-[#03a3d7] text-transparent bg-clip-text">
-              React
-            </span>{" "}
-            developers
-          </h2>
+        <main className="text-4xl md:text-3xl font-bold">
+          <h5 className="inline">
+            {title}
+          </h5>
         </main>
         </main>
 
 
         <p className="text-xl text-muted-foreground md:w-10/12 mx-auto lg:mx-0">
         <p className="text-xl text-muted-foreground md:w-10/12 mx-auto lg:mx-0">
-          Build your React landing page effortlessly with the required sections
-          to your project.
+          {content}
         </p>
         </p>
-
-        <div className="space-y-4 md:space-y-0 md:space-x-4">
-          <Button className="w-full md:w-1/3">Get Started</Button>
-
-          <a
-            rel="noreferrer noopener"
-            href="https://github.com/leoMirandaa/shadcn-landing-page.git"
-            target="_blank"
-            className={`w-full md:w-1/3 ${buttonVariants({
-              variant: "outline",
-            })}`}
-          >
-            Github Repository
-            <GitHubLogoIcon className="ml-2 w-5 h-5" />
-          </a>
-        </div>
       </div>
       </div>
 
 
       {/* Hero cards sections */}
       {/* Hero cards sections */}

+ 54 - 129
src/components/HeroCards.tsx

@@ -1,172 +1,97 @@
-import { Avatar, AvatarFallback, AvatarImage } from "./ui/avatar";
-import { Badge } from "./ui/badge";
-import { Button, buttonVariants } from "@/components/ui/button";
 import {
 import {
   Card,
   Card,
   CardContent,
   CardContent,
   CardDescription,
   CardDescription,
   CardHeader,
   CardHeader,
   CardTitle,
   CardTitle,
-  CardFooter,
 } from "@/components/ui/card";
 } from "@/components/ui/card";
-import { Check, Linkedin } from "lucide-react";
 import { LightBulbIcon } from "./Icons";
 import { LightBulbIcon } from "./Icons";
-import { GitHubLogoIcon } from "@radix-ui/react-icons";
+import Logo from "../assets/logo.png";
+import {useEffect, useState} from "react";
+import {extractSubstring} from "@/services/api.ts";
+import axios from "axios";
 
 
 export const HeroCards = () => {
 export const HeroCards = () => {
+  const [product1, setProduct1] = useState(null);
+  const [description1, setDescription1] = useState(null);
+  const [product2, setProduct2] = useState(null);
+  const [description2, setDescription2] = useState(null);
+  useEffect(() => {
+    // 使用 axios 进行 API 调用
+    const fetchData = async () => {
+      try {
+        const websiteCode = extractSubstring(window.location.pathname);
+        const response = await axios.get('/api/website/template/getWebsiteByWebsiteCode', {
+          params: {
+            websiteCode: websiteCode
+          }
+        });
+        const userWebsiteId = response.data.data.id;
+        const response2 = await axios.get('/api/website/template/products', {
+          params: {
+            userWebsiteId: userWebsiteId
+          }
+        });
+        if (response2.data.data.length > 0) {
+          setProduct1(response2.data.data[0].name);
+          setDescription1(response2.data.data[0].description);
+          setProduct2(response2.data.data[1].name);
+          setDescription2(response2.data.data[1].description);
+        }
+      } catch (err) {
+        console.error('Error fetching data:', err);
+      }
+    };
+
+    fetchData();
+
+  }, []);
   return (
   return (
     <div className="hidden lg:flex flex-row flex-wrap gap-8 relative w-[700px] h-[500px]">
     <div className="hidden lg:flex flex-row flex-wrap gap-8 relative w-[700px] h-[500px]">
       {/* Testimonial */}
       {/* Testimonial */}
       <Card className="absolute w-[340px] -top-[15px] drop-shadow-xl shadow-black/10 dark:shadow-white/10">
       <Card className="absolute w-[340px] -top-[15px] drop-shadow-xl shadow-black/10 dark:shadow-white/10">
-        <CardHeader className="flex flex-row items-center gap-4 pb-2">
-          <Avatar>
-            <AvatarImage
-              alt=""
-              src="https://github.com/shadcn.png"
-            />
-            <AvatarFallback>SH</AvatarFallback>
-          </Avatar>
-
-          <div className="flex flex-col">
-            <CardTitle className="text-lg">John Doe React</CardTitle>
-            <CardDescription>@john_doe</CardDescription>
+        <CardHeader className="space-y-1 flex md:flex-row justify-start items-start gap-4">
+          <div className="mt-1 bg-primary/20 p-1 rounded-2xl">
+            <LightBulbIcon />
+          </div>
+          <div>
+            <CardTitle>Light & dark mode</CardTitle>
+            <CardDescription className="text-md mt-2">
+              Lorem ipsum dolor sit amet consect adipisicing elit. Consectetur
+              natusm.
+            </CardDescription>
           </div>
           </div>
         </CardHeader>
         </CardHeader>
-
-        <CardContent>This landing page is awesome!</CardContent>
       </Card>
       </Card>
 
 
       {/* Team */}
       {/* Team */}
       <Card className="absolute right-[20px] top-4 w-80 flex flex-col justify-center items-center drop-shadow-xl shadow-black/10 dark:shadow-white/10">
       <Card className="absolute right-[20px] top-4 w-80 flex flex-col justify-center items-center drop-shadow-xl shadow-black/10 dark:shadow-white/10">
         <CardHeader className="mt-8 flex justify-center items-center pb-2">
         <CardHeader className="mt-8 flex justify-center items-center pb-2">
           <img
           <img
-            src="https://i.pravatar.cc/150?img=58"
+            src={Logo}
             alt="user avatar"
             alt="user avatar"
             className="absolute grayscale-[0%] -top-12 rounded-full w-24 h-24 aspect-square object-cover"
             className="absolute grayscale-[0%] -top-12 rounded-full w-24 h-24 aspect-square object-cover"
           />
           />
-          <CardTitle className="text-center">Leo Miranda</CardTitle>
-          <CardDescription className="font-normal text-primary">
-            Frontend Developer
-          </CardDescription>
+          <CardTitle className="text-center">{product1}</CardTitle>
         </CardHeader>
         </CardHeader>
 
 
         <CardContent className="text-center pb-2">
         <CardContent className="text-center pb-2">
           <p>
           <p>
-            I really enjoy transforming ideas into functional software that
-            exceeds expectations
+            {description1}
           </p>
           </p>
         </CardContent>
         </CardContent>
-
-        <CardFooter>
-          <div>
-            <a
-              rel="noreferrer noopener"
-              href="https://github.com/leoMirandaa"
-              target="_blank"
-              className={buttonVariants({
-                variant: "ghost",
-                size: "sm",
-              })}
-            >
-              <span className="sr-only">Github icon</span>
-              <GitHubLogoIcon className="w-5 h-5" />
-            </a>
-            <a
-              rel="noreferrer noopener"
-              href="https://twitter.com/leo_mirand4"
-              target="_blank"
-              className={buttonVariants({
-                variant: "ghost",
-                size: "sm",
-              })}
-            >
-              <span className="sr-only">X icon</span>
-              <svg
-                role="img"
-                viewBox="0 0 24 24"
-                xmlns="http://www.w3.org/2000/svg"
-                className="fill-foreground w-5 h-5"
-              >
-                <title>X</title>
-                <path d="M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z" />
-              </svg>
-            </a>
-
-            <a
-              rel="noreferrer noopener"
-              href="https://www.linkedin.com/in/leopoldo-miranda/"
-              target="_blank"
-              className={buttonVariants({
-                variant: "ghost",
-                size: "sm",
-              })}
-            >
-              <span className="sr-only">Linkedin icon</span>
-              <Linkedin size="20" />
-            </a>
-          </div>
-        </CardFooter>
       </Card>
       </Card>
 
 
       {/* Pricing */}
       {/* Pricing */}
-      <Card className="absolute top-[150px] left-[50px] w-72  drop-shadow-xl shadow-black/10 dark:shadow-white/10">
+      <Card className="absolute top-[200px] left-[50px] w-72  drop-shadow-xl shadow-black/10 dark:shadow-white/10">
         <CardHeader>
         <CardHeader>
           <CardTitle className="flex item-center justify-between">
           <CardTitle className="flex item-center justify-between">
-            Free
-            <Badge
-              variant="secondary"
-              className="text-sm text-primary"
-            >
-              Most popular
-            </Badge>
+            {product2}
           </CardTitle>
           </CardTitle>
-          <div>
-            <span className="text-3xl font-bold">$0</span>
-            <span className="text-muted-foreground"> /month</span>
-          </div>
-
           <CardDescription>
           <CardDescription>
-            Lorem ipsum dolor sit, amet ipsum consectetur adipisicing elit.
+            {description2}
           </CardDescription>
           </CardDescription>
         </CardHeader>
         </CardHeader>
-
-        <CardContent>
-          <Button className="w-full">Start Free Trial</Button>
-        </CardContent>
-
-        <hr className="w-4/5 m-auto mb-4" />
-
-        <CardFooter className="flex">
-          <div className="space-y-4">
-            {["4 Team member", "4 GB Storage", "Upto 6 pages"].map(
-              (benefit: string) => (
-                <span
-                  key={benefit}
-                  className="flex"
-                >
-                  <Check className="text-green-500" />{" "}
-                  <h3 className="ml-2">{benefit}</h3>
-                </span>
-              )
-            )}
-          </div>
-        </CardFooter>
-      </Card>
-
-      {/* Service */}
-      <Card className="absolute w-[350px] -right-[10px] bottom-[35px]  drop-shadow-xl shadow-black/10 dark:shadow-white/10">
-        <CardHeader className="space-y-1 flex md:flex-row justify-start items-start gap-4">
-          <div className="mt-1 bg-primary/20 p-1 rounded-2xl">
-            <LightBulbIcon />
-          </div>
-          <div>
-            <CardTitle>Light & dark mode</CardTitle>
-            <CardDescription className="text-md mt-2">
-              Lorem ipsum dolor sit amet consect adipisicing elit. Consectetur
-              natusm.
-            </CardDescription>
-          </div>
-        </CardHeader>
       </Card>
       </Card>
     </div>
     </div>
   );
   );

+ 9 - 9
src/components/Navbar.tsx

@@ -26,19 +26,19 @@ interface RouteProps {
 const routeList: RouteProps[] = [
 const routeList: RouteProps[] = [
   {
   {
     href: "#features",
     href: "#features",
-    label: "Features",
+    label: "Products",
   },
   },
   {
   {
     href: "#testimonials",
     href: "#testimonials",
-    label: "Testimonials",
+    label: "About Us",
   },
   },
   {
   {
-    href: "#pricing",
-    label: "Pricing",
+    href: "#services",
+    label: "Blog",
   },
   },
   {
   {
     href: "#faq",
     href: "#faq",
-    label: "FAQ",
+    label: "Contact Us",
   },
   },
 ];
 ];
 
 
@@ -55,7 +55,7 @@ export const Navbar = () => {
               className="ml-2 font-bold text-xl flex"
               className="ml-2 font-bold text-xl flex"
             >
             >
               <LogoIcon />
               <LogoIcon />
-              ShadcnUI/React
+              Canary/Website
             </a>
             </a>
           </NavigationMenuItem>
           </NavigationMenuItem>
 
 
@@ -79,7 +79,7 @@ export const Navbar = () => {
               <SheetContent side={"left"}>
               <SheetContent side={"left"}>
                 <SheetHeader>
                 <SheetHeader>
                   <SheetTitle className="font-bold text-xl">
                   <SheetTitle className="font-bold text-xl">
-                    Shadcn/React
+                    Canary/Website
                   </SheetTitle>
                   </SheetTitle>
                 </SheetHeader>
                 </SheetHeader>
                 <nav className="flex flex-col justify-center items-center gap-2 mt-4">
                 <nav className="flex flex-col justify-center items-center gap-2 mt-4">
@@ -96,7 +96,7 @@ export const Navbar = () => {
                   ))}
                   ))}
                   <a
                   <a
                     rel="noreferrer noopener"
                     rel="noreferrer noopener"
-                    href="https://github.com/leoMirandaa/shadcn-landing-page.git"
+                    href=""
                     target="_blank"
                     target="_blank"
                     className={`w-[110px] border ${buttonVariants({
                     className={`w-[110px] border ${buttonVariants({
                       variant: "secondary",
                       variant: "secondary",
@@ -129,7 +129,7 @@ export const Navbar = () => {
           <div className="hidden md:flex gap-2">
           <div className="hidden md:flex gap-2">
             <a
             <a
               rel="noreferrer noopener"
               rel="noreferrer noopener"
-              href="https://github.com/leoMirandaa/shadcn-landing-page.git"
+              href=""
               target="_blank"
               target="_blank"
               className={`border ${buttonVariants({ variant: "secondary" })}`}
               className={`border ${buttonVariants({ variant: "secondary" })}`}
             >
             >

+ 69 - 29
src/components/Services.tsx

@@ -1,53 +1,93 @@
 import { Card, CardDescription, CardHeader, CardTitle } from "./ui/card";
 import { Card, CardDescription, CardHeader, CardTitle } from "./ui/card";
 import { MagnifierIcon, WalletIcon, ChartIcon } from "./Icons";
 import { MagnifierIcon, WalletIcon, ChartIcon } from "./Icons";
 import cubeLeg from "../assets/cube-leg.png";
 import cubeLeg from "../assets/cube-leg.png";
+import {useEffect, useState} from "react";
+import {extractSubstring} from "@/services/api.ts";
+import axios from "axios";
 
 
 interface ServiceProps {
 interface ServiceProps {
   title: string;
   title: string;
-  description: string;
+  content: string;
   icon: JSX.Element;
   icon: JSX.Element;
 }
 }
-
-const serviceList: ServiceProps[] = [
-  {
-    title: "Code Collaboration",
-    description:
-      "Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi nesciunt est nostrum omnis ab sapiente.",
-    icon: <ChartIcon />,
-  },
-  {
-    title: "Project Management",
-    description:
-      "Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi nesciunt est nostrum omnis ab sapiente.",
-    icon: <WalletIcon />,
-  },
-  {
-    title: "Task Automation",
-    description:
-      "Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi nesciunt est nostrum omnis ab sapiente.",
-    icon: <MagnifierIcon />,
-  },
-];
+let serviceList: ServiceProps[] = [];
+const iconList = [<MagnifierIcon/>, <WalletIcon/>, <ChartIcon/>];
+// const serviceList: ServiceProps[] = [
+//   {
+//     title: "Code Collaboration",
+//     description:
+//       "Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi nesciunt est nostrum omnis ab sapiente.",
+//     icon: <ChartIcon />,
+//   },
+//   {
+//     title: "Project Management",
+//     description:
+//       "Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi nesciunt est nostrum omnis ab sapiente.",
+//     icon: <WalletIcon />,
+//   },
+//   {
+//     title: "Task Automation",
+//     description:
+//       "Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi nesciunt est nostrum omnis ab sapiente.",
+//     icon: <MagnifierIcon />,
+//   },
+// ];
 
 
 export const Services = () => {
 export const Services = () => {
+  const [loading, setLoading] = useState(true);
+  useEffect(() => {
+    // 使用 axios 进行 API 调用
+    const fetchData = async () => {
+      try {
+        const websiteCode = extractSubstring(window.location.pathname);
+        const response = await axios.get('/api/website/template/getWebsiteByWebsiteCode', {
+          params: {
+            websiteCode: websiteCode
+          }
+        });
+        const userWebsiteId = response.data.data.id;
+        const response2 = await axios.get('/api/website/template/blogs', {
+          params: {
+            userWebsiteId: userWebsiteId
+          }
+        });
+        serviceList = response2.data.data.map((item, index) => {
+          return {
+            title: item.name,
+            content: item.content.substring(0, 200) + '...',
+            icon: iconList[index % iconList.length],
+          }
+        })
+      } catch (err) {
+        console.error('Error fetching data:', err);
+      } finally {
+        setLoading(false);
+      }
+    };
+
+    fetchData();
+
+  }, []);
+  // 处理加载和错误状态
+  if (loading) {
+    return <div>Loading...</div>;
+  }
   return (
   return (
-    <section className="container py-24 sm:py-32">
+    <section id="services" className="container py-24 sm:py-32">
       <div className="grid lg:grid-cols-[1fr,1fr] gap-8 place-items-center">
       <div className="grid lg:grid-cols-[1fr,1fr] gap-8 place-items-center">
         <div>
         <div>
           <h2 className="text-3xl md:text-4xl font-bold">
           <h2 className="text-3xl md:text-4xl font-bold">
             <span className="bg-gradient-to-b from-primary/60 to-primary text-transparent bg-clip-text">
             <span className="bg-gradient-to-b from-primary/60 to-primary text-transparent bg-clip-text">
-              Client-Centric{" "}
+              Blog
             </span>
             </span>
-            Services
           </h2>
           </h2>
 
 
           <p className="text-muted-foreground text-xl mt-4 mb-8 ">
           <p className="text-muted-foreground text-xl mt-4 mb-8 ">
-            Lorem ipsum dolor sit amet consectetur, adipisicing elit. Veritatis
-            dolor.
+            Latest blog.
           </p>
           </p>
 
 
           <div className="flex flex-col gap-8">
           <div className="flex flex-col gap-8">
-            {serviceList.map(({ icon, title, description }: ServiceProps) => (
+            {serviceList.map(({ icon, title, content }: ServiceProps) => (
               <Card key={title}>
               <Card key={title}>
                 <CardHeader className="space-y-1 flex md:flex-row justify-start items-start gap-4">
                 <CardHeader className="space-y-1 flex md:flex-row justify-start items-start gap-4">
                   <div className="mt-1 bg-primary/20 p-1 rounded-2xl">
                   <div className="mt-1 bg-primary/20 p-1 rounded-2xl">
@@ -56,7 +96,7 @@ export const Services = () => {
                   <div>
                   <div>
                     <CardTitle>{title}</CardTitle>
                     <CardTitle>{title}</CardTitle>
                     <CardDescription className="text-md mt-2">
                     <CardDescription className="text-md mt-2">
-                      {description}
+                      {content}
                     </CardDescription>
                     </CardDescription>
                   </div>
                   </div>
                 </CardHeader>
                 </CardHeader>

+ 54 - 19
src/components/Statistics.tsx

@@ -1,28 +1,63 @@
+import {useEffect, useState} from "react";
+import {extractSubstring} from "@/services/api.ts";
+import axios from "axios";
+
 export const Statistics = () => {
 export const Statistics = () => {
+  const [loading, setLoading] = useState(true);
+  let stats: statsProps[] = [];
+  useEffect(() => {
+    // 使用 axios 进行 API 调用
+    const fetchData = async () => {
+      try {
+        const websiteCode = extractSubstring(window.location.pathname);
+        const response = await axios.get('/api/website/template/getWebsiteByWebsiteCode', {
+          params: {
+            websiteCode: websiteCode
+          }
+        });
+        const userWebsiteId = response.data.data.id;
+        const response2 = await axios.get('/api/website/template/company', {
+          params: {
+            userWebsiteId: userWebsiteId
+          }
+        });
+        stats = [
+          {
+            quantity: response2.data.data.userNum,
+            description: "Users",
+          },
+          {
+            quantity: response2.data.data.factorySpace,
+            description: "Factory Space",
+          },
+          {
+            quantity: response2.data.data.establishYear,
+            description: "Establish Year",
+          },
+          {
+            quantity: response2.data.data.productNum,
+            description: "Products",
+          },
+        ];
+      } catch (err) {
+        console.error('Error fetching data:', err);
+      } finally {
+        setLoading(false);
+      }
+    };
+
+    fetchData();
+
+  }, []);
+  // 处理加载和错误状态
+  if (loading) {
+    return <div>Loading...</div>;
+  }
   interface statsProps {
   interface statsProps {
     quantity: string;
     quantity: string;
     description: string;
     description: string;
   }
   }
 
 
-  const stats: statsProps[] = [
-    {
-      quantity: "2.7K+",
-      description: "Users",
-    },
-    {
-      quantity: "1.8K+",
-      description: "Subscribers",
-    },
-    {
-      quantity: "112",
-      description: "Downloads",
-    },
-    {
-      quantity: "4",
-      description: "Products",
-    },
-  ];
-
   return (
   return (
     <section id="statistics">
     <section id="statistics">
       <div className="grid grid-cols-2 lg:grid-cols-4 gap-8">
       <div className="grid grid-cols-2 lg:grid-cols-4 gap-8">

+ 14 - 14
src/components/Testimonials.tsx

@@ -17,43 +17,43 @@ interface TestimonialProps {
 const testimonials: TestimonialProps[] = [
 const testimonials: TestimonialProps[] = [
   {
   {
     image: "https://github.com/shadcn.png",
     image: "https://github.com/shadcn.png",
-    name: "John Doe React",
-    userName: "@john_Doe",
-    comment: "This landing page is awesome!",
+    name: "Canary",
+    userName: "@canary",
+    comment: "AI building website is awesome!",
   },
   },
   {
   {
     image: "https://github.com/shadcn.png",
     image: "https://github.com/shadcn.png",
-    name: "John Doe React",
-    userName: "@john_Doe1",
+    name: "Canary",
+    userName: "@canary1",
     comment:
     comment:
       "Lorem ipsum dolor sit amet,empor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud.",
       "Lorem ipsum dolor sit amet,empor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud.",
   },
   },
 
 
   {
   {
     image: "https://github.com/shadcn.png",
     image: "https://github.com/shadcn.png",
-    name: "John Doe React",
-    userName: "@john_Doe2",
+    name: "Canary",
+    userName: "@canary2",
     comment:
     comment:
       "Lorem ipsum dolor sit amet,exercitation. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident.",
       "Lorem ipsum dolor sit amet,exercitation. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident.",
   },
   },
   {
   {
     image: "https://github.com/shadcn.png",
     image: "https://github.com/shadcn.png",
-    name: "John Doe React",
-    userName: "@john_Doe3",
+    name: "Canary",
+    userName: "@canary3",
     comment:
     comment:
       "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.",
       "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.",
   },
   },
   {
   {
     image: "https://github.com/shadcn.png",
     image: "https://github.com/shadcn.png",
-    name: "John Doe React",
-    userName: "@john_Doe4",
+    name: "Canary",
+    userName: "@canary4",
     comment:
     comment:
       "Lorem ipsum dolor sit amet, tempor incididunt  aliqua. Ut enim ad minim veniam, quis nostrud.",
       "Lorem ipsum dolor sit amet, tempor incididunt  aliqua. Ut enim ad minim veniam, quis nostrud.",
   },
   },
   {
   {
     image: "https://github.com/shadcn.png",
     image: "https://github.com/shadcn.png",
-    name: "John Doe React",
-    userName: "@john_Doe5",
+    name: "Canary",
+    userName: "@canary5",
     comment:
     comment:
       "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
       "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
   },
   },
@@ -71,7 +71,7 @@ export const Testimonials = () => {
           {" "}
           {" "}
           People Love{" "}
           People Love{" "}
         </span>
         </span>
-        This Landing Page
+        AI building website
       </h2>
       </h2>
 
 
       <p className="text-xl text-muted-foreground pt-4 pb-8">
       <p className="text-xl text-muted-foreground pt-4 pb-8">

+ 16 - 0
src/services/api.ts

@@ -0,0 +1,16 @@
+export function extractSubstring(str: string) {
+    const startIndex = str.indexOf('/');
+    if (startIndex !== -1) {
+        const endIndex = str.indexOf('/', startIndex + 1);
+        if (endIndex !== -1) {
+            return str.substring(startIndex + 1, endIndex - 1);
+        } else {
+            return str.substring(startIndex + 1);
+        }
+    }
+    return ''; // 如果没有找到匹配,返回空字符串
+}
+export function getImageUrl(index) {
+    // 使用 index 对 3 取余数,循环分配图片
+    return this.images[index % this.images.length];
+}

+ 2 - 1
tsconfig.json

@@ -23,7 +23,8 @@
     "baseUrl": ".",
     "baseUrl": ".",
     "paths": {
     "paths": {
       "@/*": ["./src/*"]
       "@/*": ["./src/*"]
-    }
+    },
+    "allowSyntheticDefaultImports": true
   },
   },
   "include": ["src"],
   "include": ["src"],
   "references": [{ "path": "./tsconfig.node.json" }]
   "references": [{ "path": "./tsconfig.node.json" }]

+ 10 - 0
vite.config.ts

@@ -9,4 +9,14 @@ export default defineConfig({
       "@": path.resolve(__dirname, "./src"),
       "@": path.resolve(__dirname, "./src"),
     },
     },
   },
   },
+  server: {
+    port: 3300,
+    proxy: {
+      '/api': {// 匹配所有以 '/api1'开头的请求路径
+        target: 'http://localhost:8090',// 代理目标的基础路径
+        changeOrigin: true,
+        // pathRewrite: {'^/api1': ''}
+      },
+    }
+  },
 });
 });