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-navigation-menu": "^1.2.0",
         "@radix-ui/react-slot": "^1.1.0",
+        "axios": "^1.7.7",
         "class-variance-authority": "^0.7.0",
         "clsx": "^2.1.1",
         "lucide-react": "^0.424.0",
@@ -2417,6 +2418,12 @@
         "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": {
       "version": "10.4.19",
       "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz",
@@ -2454,6 +2461,17 @@
         "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": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -2648,6 +2666,18 @@
       "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
       "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": {
       "version": "4.1.1",
       "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==",
       "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": {
       "version": "1.1.0",
       "resolved": "https://registry.npmmirror.com/detect-node-es/-/detect-node-es-1.1.0.tgz",
@@ -3226,6 +3265,26 @@
       "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
       "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": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
@@ -3241,6 +3300,20 @@
         "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": {
       "version": "4.3.7",
       "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
@@ -3728,6 +3801,27 @@
         "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": {
       "version": "9.0.4",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
@@ -4141,6 +4235,12 @@
         "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": {
       "version": "2.3.1",
       "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-navigation-menu": "^1.2.0",
     "@radix-ui/react-slot": "^1.1.0",
+    "axios": "^1.7.7",
     "class-variance-authority": "^0.7.0",
     "clsx": "^2.1.1",
     "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 { Navbar } from "./components/Navbar";
 import { Newsletter } from "./components/Newsletter";
-import { Pricing } from "./components/Pricing";
 import { ScrollToTop } from "./components/ScrollToTop";
 import { Services } from "./components/Services";
 import { Sponsors } from "./components/Sponsors";
@@ -28,7 +27,6 @@ function App() {
       <Cta />
       <Testimonials />
       <Team />
-      <Pricing />
       <Newsletter />
       <FAQ />
       <Footer />

BIN
src/assets/logo.png


+ 38 - 5
src/components/About.tsx

@@ -1,7 +1,44 @@
 import { Statistics } from "./Statistics";
 import pilot from "../assets/pilot.png";
+import {useEffect, useState} from "react";
+import {extractSubstring} from "@/services/api.ts";
+import axios from "axios";
 
 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 (
     <section
       id="about"
@@ -23,11 +60,7 @@ export const About = () => {
                 Company
               </h2>
               <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>
             </div>
 

+ 65 - 21
src/components/Features.tsx

@@ -9,6 +9,9 @@ import {
 import image from "../assets/growth.png";
 import image3 from "../assets/reflecting.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 {
   title: string;
@@ -16,27 +19,29 @@ interface FeatureProps {
   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[] = [
   "Dark/Light theme",
   "Reviews",
@@ -50,6 +55,44 @@ const featureList: string[] = [
 ];
 
 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 (
     <section
       id="features"
@@ -58,7 +101,7 @@ export const Features = () => {
       <h2 className="text-3xl lg:text-4xl font-bold md:text-center">
         Many{" "}
         <span className="bg-gradient-to-b from-primary/60 to-primary text-transparent bg-clip-text">
-          Great Features
+          Great Products
         </span>
       </h2>
 
@@ -97,3 +140,4 @@ export const Features = () => {
     </section>
   );
 };
+

+ 3 - 3
src/components/Footer.tsx

@@ -13,7 +13,7 @@ export const Footer = () => {
             className="font-bold text-xl flex"
           >
             <LogoIcon />
-            ShadcnUI/React
+            Canary/Website
           </a>
         </div>
 
@@ -152,14 +152,14 @@ export const Footer = () => {
 
       <section className="container pb-14 text-center">
         <h3>
-          &copy; 2024 Landing page made by{" "}
+          &copy; 2024 website made by{" "}
           <a
             rel="noreferrer noopener"
             target="_blank"
             href="https://www.linkedin.com/in/leopoldo-miranda/"
             className="text-primary transition-all border-primary hover:border-b-2"
           >
-            Leo Miranda
+            Canary
           </a>
         </h3>
       </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 { GitHubLogoIcon } from "@radix-ui/react-icons";
+import axios from 'axios';
+import { useEffect, useState } from 'react';
+import {extractSubstring} from "./../services/api.ts";
 
 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 (
     <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">
-        <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>
 
         <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>
-
-        <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>
 
       {/* 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 {
   Card,
   CardContent,
   CardDescription,
   CardHeader,
   CardTitle,
-  CardFooter,
 } from "@/components/ui/card";
-import { Check, Linkedin } from "lucide-react";
 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 = () => {
+  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 (
     <div className="hidden lg:flex flex-row flex-wrap gap-8 relative w-[700px] h-[500px]">
       {/* Testimonial */}
       <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>
         </CardHeader>
-
-        <CardContent>This landing page is awesome!</CardContent>
       </Card>
 
       {/* 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">
         <CardHeader className="mt-8 flex justify-center items-center pb-2">
           <img
-            src="https://i.pravatar.cc/150?img=58"
+            src={Logo}
             alt="user avatar"
             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>
 
         <CardContent className="text-center pb-2">
           <p>
-            I really enjoy transforming ideas into functional software that
-            exceeds expectations
+            {description1}
           </p>
         </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>
 
       {/* 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>
           <CardTitle className="flex item-center justify-between">
-            Free
-            <Badge
-              variant="secondary"
-              className="text-sm text-primary"
-            >
-              Most popular
-            </Badge>
+            {product2}
           </CardTitle>
-          <div>
-            <span className="text-3xl font-bold">$0</span>
-            <span className="text-muted-foreground"> /month</span>
-          </div>
-
           <CardDescription>
-            Lorem ipsum dolor sit, amet ipsum consectetur adipisicing elit.
+            {description2}
           </CardDescription>
         </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>
     </div>
   );

+ 9 - 9
src/components/Navbar.tsx

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

+ 69 - 29
src/components/Services.tsx

@@ -1,53 +1,93 @@
 import { Card, CardDescription, CardHeader, CardTitle } from "./ui/card";
 import { MagnifierIcon, WalletIcon, ChartIcon } from "./Icons";
 import cubeLeg from "../assets/cube-leg.png";
+import {useEffect, useState} from "react";
+import {extractSubstring} from "@/services/api.ts";
+import axios from "axios";
 
 interface ServiceProps {
   title: string;
-  description: string;
+  content: string;
   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 = () => {
+  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 (
-    <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>
           <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">
-              Client-Centric{" "}
+              Blog
             </span>
-            Services
           </h2>
 
           <p className="text-muted-foreground text-xl mt-4 mb-8 ">
-            Lorem ipsum dolor sit amet consectetur, adipisicing elit. Veritatis
-            dolor.
+            Latest blog.
           </p>
 
           <div className="flex flex-col gap-8">
-            {serviceList.map(({ icon, title, description }: ServiceProps) => (
+            {serviceList.map(({ icon, title, content }: ServiceProps) => (
               <Card key={title}>
                 <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">
@@ -56,7 +96,7 @@ export const Services = () => {
                   <div>
                     <CardTitle>{title}</CardTitle>
                     <CardDescription className="text-md mt-2">
-                      {description}
+                      {content}
                     </CardDescription>
                   </div>
                 </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 = () => {
+  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 {
     quantity: 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 (
     <section id="statistics">
       <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[] = [
   {
     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",
-    name: "John Doe React",
-    userName: "@john_Doe1",
+    name: "Canary",
+    userName: "@canary1",
     comment:
       "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",
-    name: "John Doe React",
-    userName: "@john_Doe2",
+    name: "Canary",
+    userName: "@canary2",
     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.",
   },
   {
     image: "https://github.com/shadcn.png",
-    name: "John Doe React",
-    userName: "@john_Doe3",
+    name: "Canary",
+    userName: "@canary3",
     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.",
   },
   {
     image: "https://github.com/shadcn.png",
-    name: "John Doe React",
-    userName: "@john_Doe4",
+    name: "Canary",
+    userName: "@canary4",
     comment:
       "Lorem ipsum dolor sit amet, tempor incididunt  aliqua. Ut enim ad minim veniam, quis nostrud.",
   },
   {
     image: "https://github.com/shadcn.png",
-    name: "John Doe React",
-    userName: "@john_Doe5",
+    name: "Canary",
+    userName: "@canary5",
     comment:
       "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{" "}
         </span>
-        This Landing Page
+        AI building website
       </h2>
 
       <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": ".",
     "paths": {
       "@/*": ["./src/*"]
-    }
+    },
+    "allowSyntheticDefaultImports": true
   },
   "include": ["src"],
   "references": [{ "path": "./tsconfig.node.json" }]

+ 10 - 0
vite.config.ts

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