Преглед изворни кода

feat(about):重构招聘列表页面并增强关于页面动画效果

- 将招聘列表页改为服务端渲染,支持分页参数
- 添加数据获取失败的错误提示
- 实现响应式布局优化,适配移动端显示
- 引入缓存策略提升性能- 在关于页面添加滚动动画组件包裹各区块
- 调整公司简介内容结构与样式以适应新设计
- 更新荣誉资质及联系我们的展示方式
- 减少首页招聘列表显示数量至3条
-为静态资源设置重新验证时间以提高加载速度
nahida пре 7 месеци
родитељ
комит
04fb50f081
2 измењених фајлова са 270 додато и 200 уклоњено
  1. 125 69
      src/app/about/page.tsx
  2. 145 131
      src/app/about/recruitList/page.tsx

+ 125 - 69
src/app/about/page.tsx

@@ -6,6 +6,7 @@ import TopNav from "@/components/about/TopNav";
 import Development from "@/components/about/Development";
 import Honor from "@/components/about/Honor";
 import {serverGet, serverPost} from "@/utils/request";
+import AnimatedSection from "@/components/AnimatedSection";
 
 // export const revalidate = 1800
 
@@ -14,98 +15,153 @@ export default async function Home() {
   const res = await serverPost<Page<RecruitmentInfo>, {
     pageNum: number,
     pageSize: number
-  }>('webSite/getRecruitmentInfoByPage', {
+  }>('/webSite/getRecruitmentInfoByPage', {
     pageNum: 1,
-    pageSize: 4
+    pageSize: 3
+  }, {
+    next: {
+      revalidate: 30
+    },
+    cache: "force-cache"
   })
-  const honorRes = await serverGet<HonorInfo[]>("/webSite/getHonor")
+  const honorRes = await serverGet<HonorInfo[]>("/webSite/getHonor", {
+    next: {
+      revalidate: 1800
+    },
+    cache: "force-cache"
+  })
+
+  const basicInfoRes = await serverGet<BasicInfo[]>("/webSite/getBasicInfo", {
+    next: {
+      revalidate: 1800
+    },
+    cache: "force-cache"
+  })
+
+  const basicInfo = basicInfoRes.data[0] || {
+    address: "",
+    companyProfile: "",
+    companyProfileUrl: "",
+    consultationHotline: "",
+    email: "",
+    hardwareIntroduction: "",
+    id: "",
+    qrCodeUrl: "",
+    serviceHotline: "",
+    softwareIntroduction: "",
+    telephone: ""
+  };
+
 
   return (
     <>
-      <div className="hidden sm:block">
-        <Image src={"/assets/about/1.png"} alt={"关于我们"} width={1920} height={1080}/>
-      </div>
-      <div className="sm:hidden">
-        <Image src={"/assets/about/23.png"} alt={"关于我们"} width={1920} height={1080}/>
-      </div>
+      <AnimatedSection effect="slide" direction="left">
+        <div className="hidden sm:block">
+          <Image src={"/assets/about/1.png"} alt={"关于我们"} width={1920} height={1080}/>
+        </div>
+        <div className="sm:hidden">
+          <Image src={"/assets/about/23.png"} alt={"关于我们"} width={1920} height={1080}/>
+        </div>
+      </AnimatedSection>
       <div className="w-full">
-        {/* 顶部导航 */}
-        <TopNav/>
-
+        <AnimatedSection effect="slide" direction="right">
+          {/* 顶部导航 */}
+          <TopNav/>
+        </AnimatedSection>
         <div className="max-w-4/5 mx-auto py-4 px-4">
           <SubTitle title={"公司简介"}/>
         </div>
 
         {/* 公司简介 */}
-        <section id="section-0"
-                 className="scroll-mt-50 max-w-4/5 mx-auto grid sm:grid-cols-1 md:grid-cols-2">
-          <div className="bg-[url('/assets/about/16.png')] bg-cover px-24 py-18">
-            <p className="text-gray-700 leading-7 mb-12">
-              中科盛阳信息技术有限公司是一家专注于物联网智能感知设备及平台研发的国家级高新技术企业。公司联合中南大学设有博士后创新创业实践基地并建立了物联网感知设备研发中心;公司拥有包含发明专利及集成电路设计布图在内的自主知识产权一百余项;自主研发的多项产品及技术行业领先;其中核心产品如城市生命线安全监测设备及平台、道路桥梁安全检测设备及平台、城市排水及污水管网监测设备及平台、水库雨水情测报与大坝安全监测设备及平台等产品和技术广泛应用于国内数字新基建行业。
-            </p>
-            <p className="text-gray-700 leading-7">
-              公司自成立以来持续健康发展,先后荣获了多项荣誉,包括专精特新中小企业、双软认定、国家高新技术企业、创新型中小企业、科技型中小企业等。同时公司通过了
-              ISO45001 、ISO14004、ISO27001、信息技术服务管理体系、信息安全管理体系等数十项管理体系认证。并且与国内多个大学及科研院所建立了联合研发中心或者产学研基地。
-            </p>
-            <div className="grid grid-cols-4 gap-6 mt-6">
-              <div className="text-center flex flex-col items-center gap-2">
-                <div className="w-14 h-14 rounded-full bg-blue-100 flex items-center justify-center">
-                  <Image src={"/assets/about/12.png"} alt={"专精特新小巨人企业"} width={100} height={100}/>
+        <AnimatedSection effect="slide" direction="left">
+          <section
+            id="section-0"
+            className="scroll-mt-50 max-w-[90%] md:max-w-4/5 mx-auto grid grid-cols-1 md:grid-cols-2"
+          >
+            {/* 左侧文字块 */}
+            <div className="bg-[url('/assets/about/16.png')] bg-cover px-6 py-8 sm:px-12 sm:py-10 md:px-24 md:py-18">
+              <p className="text-gray-700 leading-6 sm:leading-7 mb-6 sm:mb-12 text-sm sm:text-base">
+                {basicInfo.companyProfile}
+              </p>
+              <p className="text-gray-700 leading-6 sm:leading-7 text-sm sm:text-base">
+                {basicInfo.companyProfileTwo}
+              </p>
+
+              {/* 图标荣誉 */}
+              <div className="grid grid-cols-2 sm:grid-cols-4 gap-4 sm:gap-6 mt-6">
+                <div className="text-center flex flex-col items-center gap-2">
+                  <div className="w-12 h-12 sm:w-14 sm:h-14 rounded-full bg-blue-100 flex items-center justify-center">
+                    <Image src={"/assets/about/12.png"} alt={"专精特新小巨人企业"} width={60} height={60}/>
+                  </div>
+                  <p className="text-xs sm:text-sm">专精特新小巨人企业</p>
                 </div>
-                <p className="text-sm">专精特新小巨人企业</p>
-              </div>
-              <div className="text-center flex flex-col items-center gap-2">
-                <div className="w-14 h-14 rounded-full bg-blue-100 flex items-center justify-center">
-                  <Image src={"/assets/about/13.png"} alt={"创新型中小企业"} width={100} height={100}/>
+
+                <div className="text-center flex flex-col items-center gap-2">
+                  <div className="w-12 h-12 sm:w-14 sm:h-14 rounded-full bg-blue-100 flex items-center justify-center">
+                    <Image src={"/assets/about/13.png"} alt={"创新型中小企业"} width={60} height={60}/>
+                  </div>
+                  <p className="text-xs sm:text-sm">创新型中小企业</p>
                 </div>
-                <p className="text-sm">创新型中小企业</p>
-              </div>
-              <div className="text-center flex flex-col items-center gap-2">
-                <div className="w-14 h-14 rounded-full bg-blue-100 flex items-center justify-center">
-                  <Image src={"/assets/about/15.png"} alt={"高新技术企业"} width={100} height={100}/>
+
+                <div className="text-center flex flex-col items-center gap-2">
+                  <div className="w-12 h-12 sm:w-14 sm:h-14 rounded-full bg-blue-100 flex items-center justify-center">
+                    <Image src={"/assets/about/15.png"} alt={"高新技术企业"} width={60} height={60}/>
+                  </div>
+                  <p className="text-xs sm:text-sm">高新技术企业</p>
                 </div>
-                <p className="text-sm">高新技术企业</p>
-              </div>
-              <div className="text-center flex flex-col items-center gap-2">
-                <div className="w-14 h-14 rounded-full bg-blue-100 flex items-center justify-center">
-                  <Image src={"/assets/about/14.png"} alt={"省级博士后创新基地"} width={100} height={100}/>
+
+                <div className="text-center flex flex-col items-center gap-2">
+                  <div className="w-12 h-12 sm:w-14 sm:h-14 rounded-full bg-blue-100 flex items-center justify-center">
+                    <Image src={"/assets/about/14.png"} alt={"省级博士后创新基地"} width={60} height={60}/>
+                  </div>
+                  <p className="text-xs sm:text-sm">省级博士后创新基地</p>
                 </div>
-                <p className="text-sm">省级博士后创新基地</p>
               </div>
             </div>
-          </div>
-          <div className="bg-gray-300 w-full bg-[url('/assets/about/17.jpg')] bg-cover"></div>
-        </section>
 
-        {/* 发展历程 */}
-        <section id="section-1"
-                 className="scroll-mt-10 bg-blue-900 text-white mt-10 py-12 px-4 bg-[url('/assets/about/18.png')] bg-cover">
-          <div className="max-w-4/5 mx-auto my-10 sm:my-6">
-            <SubTitle title={"发展历程"}/>
-          </div>
-          <div className={"max-w-4/5 mx-auto"}>
-            <Development/>
-          </div>
-        </section>
+            {/* 右侧背景图 */}
+            <div className="bg-gray-300 w-full h-48 sm:h-64 md:h-auto bg-[url('/assets/about/17.jpg')] bg-cover"></div>
+          </section>
+        </AnimatedSection>
 
+        {/* 发展历程 */}
+        <AnimatedSection effect="slide" direction="right">
+          <section id="section-1"
+                   className="scroll-mt-10 bg-blue-900 text-white mt-10 py-12 px-4 bg-[url('/assets/about/18.png')] bg-cover">
+            <div className="max-w-4/5 mx-auto my-10 sm:my-6">
+              <SubTitle title={"发展历程"}/>
+            </div>
+            <div className={"max-w-4/5 mx-auto"}>
+              <Development/>
+            </div>
+          </section>
+        </AnimatedSection>
         {/* 荣誉资质 */}
-        <section id="section-2" className="scroll-mt-10 max-w-4/5 mx-auto py-12 px-4">
-          <div className="my-10 sm:my-6">
-            <SubTitle title="荣誉资质"/>
-          </div>
-          <Honor honorList={honorRes.data} />
-        </section>
-
+        <AnimatedSection effect="slide" direction="left">
+          <section id="section-2" className="scroll-mt-10 max-w-4/5 mx-auto py-12 px-4">
+            <div className="my-10 sm:my-6">
+              <SubTitle title="荣誉资质"/>
+            </div>
+            <Honor honorList={honorRes.data}/>
+          </section>
+        </AnimatedSection>
         {/* 公司招聘 */}
-        <div className="w-4/5 mx-auto my-10 sm:my-6">
-          <SubTitle title="公司招聘"/>
-        </div>
-        <section id="section-3" className="scroll-mt-10 w-full py-12 px-4 bg-[url('/assets/about/20.png')]">
-          <Recruitment list={res.data.records}/>
-        </section>
 
+        <AnimatedSection effect="slide" direction="right">
+          <section
+            id="section-3"
+            className="scroll-mt-10 w-full py-12 px-4 bg-[url('/assets/about/20.png')]"
+          >
+            <div className="w-4/5 mx-auto my-10 sm:my-6">
+              <SubTitle title="公司招聘"/>
+            </div>
+            <Recruitment list={res.data.records}/>
+          </section>
+        </AnimatedSection>
         {/* 联系我们 */}
-        <ContactUs/>
+        <AnimatedSection effect="slide" direction="left">
+          <ContactUs basicInfo={basicInfo}/>
+        </AnimatedSection>
       </div>
     </>
   )

+ 145 - 131
src/app/about/recruitList/page.tsx

@@ -1,153 +1,167 @@
-"use client";
-
-import React, {useEffect, useState} from "react";
-import {Breadcrumb, Pagination, Spin} from "antd";
-import Image from "next/image";
+import {Breadcrumb} from "antd"
+import Image from "next/image"
+import Link from "next/link"
+import PaginationClient from "@/components/PaginationClient"
 import {serverPost} from "@/utils/request";
-import Link from "next/link";
 
-export default function RecruitmentListPage() {
-  const [data, setData] = useState<Page<RecruitmentInfo>>();
-  const [loading, setLoading] = useState(false);
-  const [pageNum, setPageNum] = useState(1);
-  const pageSize = 4;
+async function fetchRecruitmentData(pageNum: number, pageSize: number) {
+  try {
+    const response = await serverPost<Page<RecruitmentInfo>, {
+      pageNum: number;
+      pageSize: number
+    }>(`/webSite/getRecruitmentInfoByPage`, {
+      pageNum,
+      pageSize,
+    },{
+      next:{
+        revalidate: 120,
+      },
+      cache:'force-cache'
+    })
+
+    return response.data
+  } catch (error) {
+    console.error("Error fetching recruitment data:", error)
+    return null
+  }
+}
 
-  const fetchData = async (page: number) => {
-    setLoading(true);
-    try {
-      const res = await serverPost<Page<RecruitmentInfo>, { pageNum: number; pageSize: number }>(
-        "webSite/getRecruitmentInfoByPage",
-        {pageNum: page, pageSize}
-      );
-      setData(res.data);
-    } finally {
-      setLoading(false);
-    }
-  };
+export default async function RecruitmentListPage({
+                                                    searchParams,
+                                                  }: {
+  searchParams: Promise<{ page?: string }>
+}) {
+  // 等待 searchParams 解析
+  const params = await searchParams
+  const pageNum = Number.parseInt(params.page || "1", 10)
+  const pageSize = 4
 
-  useEffect(() => {
-    fetchData(pageNum);
-  }, [pageNum]);
+  const data = await fetchRecruitmentData(pageNum, pageSize)
+
+  if (!data) {
+    return (
+      <div className="w-full bg-[url('/assets/about/recruitList/1.png')] bg-cover min-h-screen">
+        {/* <CHANGE> 容器宽度响应式调整,移动端全宽,桌面端保持原样 */}
+        <div className="w-full px-4 sm:w-3/5 sm:mx-auto">
+          {/* <CHANGE> 面包屑导航响应式调整,移动端去掉左边距 */}
+          <div className="pt-6 sm:pt-10 px-2 sm:ml-20 flex gap-2">
+            <span className="text-sm">您当前的所在位置:</span>
+            <Breadcrumb separator=">" items={[{title: "关于我们", href: "/about"}, {title: "招聘列表"}]}/>
+          </div>
+          {/* <CHANGE> 内容区域 padding 响应式调整 */}
+          <div className="p-4 sm:p-10">
+            <div className="flex justify-center py-20">
+              <p className="text-red-500">加载招聘信息失败,请稍后重试。</p>
+            </div>
+          </div>
+        </div>
+      </div>
+    )
+  }
 
   return (
     <div className="w-full bg-[url('/assets/about/recruitList/1.png')] bg-cover min-h-screen">
-      <div className="w-3/5 mx-auto">
+      {/* <CHANGE> 容器宽度响应式调整,移动端全宽,桌面端保持原样 */}
+      <div className="w-full px-4 sm:w-3/5 sm:mx-auto">
         {/* 面包屑 */}
-        <div className="pt-10 ml-20 flex gap-2">
+        {/* <CHANGE> 面包屑导航响应式调整,移动端去掉左边距 */}
+        <div className="pt-6 sm:pt-10 px-2 sm:ml-20 flex gap-2">
           <span className="text-sm">您当前的所在位置:</span>
-          <Breadcrumb
-            separator=">"
-            items={[
-              {title: "关于我们", href: "/about"},
-              {title: "招聘列表"},
-            ]}
-          />
+          <Breadcrumb separator=">" items={[{title: "关于我们", href: "/about"}, {title: "招聘列表"}]}/>
         </div>
 
         {/* 内容 */}
-        <div className="p-10">
-          {loading ? (
-            <div className="flex justify-center py-20">
-              <Spin size="large"/>
-            </div>
-          ) : (
-            <>
-              {data?.records?.map((item) => (
-                <div
-                  key={item.id}
-                  className="mb-10 bg-[url('/assets/about/recruitList/2.png')] bg-[length:100.5%_106%] rounded-4xl shadow-lg"
-                >
-                  <div className="text-xl pt-1.5 pl-4 text-white font-bold">
-                    {item.jobOpenings}
-                  </div>
+        {/* <CHANGE> 内容区域 padding 响应式调整 */}
+        <div className="p-4 sm:p-10">
+          {data?.records?.map((item) => (
+            <div
+              key={item.id}
+              className="mb-6 sm:mb-10 bg-[url('/assets/about/recruitList/2.png')] bg-[length:100.5%_106%] rounded-4xl shadow-lg"
+            >
+              {/* <CHANGE> 标题区域 padding 响应式调整 */}
+              <div className="text-lg sm:text-xl pt-1.5 pl-3 sm:pl-4 text-white font-bold bg-blue-600 pb-3 sm:pb-10 rounded-t-xl">{item.jobOpenings}</div>
 
-                  <div className="flex flex-col lg:flex-row p-8 gap-6">
-                    {/* 左侧内容 */}
-                    <div className="flex-1">
-                      <div className="grid grid-cols-2 gap-4 text-sm font-bold">
-                        <div className="flex gap-2 items-center">
-                          <Image
-                            className="w-4 h-4"
-                            src={"/assets/about/recruitList/3.png"}
-                            alt="图标"
-                            width={16}
-                            height={16}
-                          />
-                          <span>工作地址: {item.workLocation}</span>
-                        </div>
-                        <div className="flex gap-2 items-center">
-                          <Image
-                            className="w-4 h-4"
-                            src={"/assets/about/recruitList/3.png"}
-                            alt="图标"
-                            width={16}
-                            height={16}
-                          />
-                          <span>招聘人数: {item.numberRecruits}</span>
-                        </div>
-                        <div className="flex gap-2 items-center">
-                          <Image
-                            className="w-4 h-4"
-                            src={"/assets/about/recruitList/3.png"}
-                            alt="图标"
-                            width={16}
-                            height={16}
-                          />
-                          <span>薪资: {item.salary}</span>
-                        </div>
-                        <div className="flex gap-2 items-center">
-                          <Image
-                            className="w-4 h-4"
-                            src={"/assets/about/recruitList/3.png"}
-                            alt="图标"
-                            width={16}
-                            height={16}
-                          />
-                          <span>联系人: {item.contact}</span>
-                        </div>
-                      </div>
-
-                      <div className="mt-4 flex gap-2 items-start">
-                        <Image
-                          className="w-5 h-5 mt-1"
-                          src={"/assets/about/recruitList/3.png"}
-                          alt="图标"
-                          width={20}
-                          height={20}
-                        />
-                        <p className="text-sm w-4/5 line-clamp-6">
-                          职位要求: {item.jobRequirements}
-                        </p>
-                      </div>
+              {/* <CHANGE> 卡片内容布局响应式调整,移动端垂直排列,桌面端水平排列 */}
+              <div className="flex flex-col p-4 sm:p-8 gap-4 sm:gap-6">
+                {/* 左侧内容 */}
+                <div className="flex-1">
+                  {/* <CHANGE> 网格布局响应式调整,移动端单列,桌面端双列 */}
+                  <div className="grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4 text-sm font-bold">
+                    <div className="flex gap-2 items-center">
+                      <Image
+                        className="w-4 h-4"
+                        src={"/assets/about/recruitList/3.png"}
+                        alt="图标"
+                        width={16}
+                        height={16}
+                      />
+                      <span>工作地址: {item.workLocation}</span>
                     </div>
-
-                    {/* 右侧按钮 */}
-                    <div className="flex justify-center items-center">
-                      <Link href={`/about/recruitList/${item.id}`}>
-                        <button
-                          className="cursor-pointer mt-4 lg:mt-20 w-40 bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded-full transition duration-300 ease-in-out transform hover:scale-105">
-                          了解详情 &gt;&gt;
-                        </button>
-                      </Link>
+                    <div className="flex gap-2 items-center">
+                      <Image
+                        className="w-4 h-4"
+                        src={"/assets/about/recruitList/3.png"}
+                        alt="图标"
+                        width={16}
+                        height={16}
+                      />
+                      <span>招聘人数: {item.numberRecruits}</span>
+                    </div>
+                    <div className="flex gap-2 items-center">
+                      <Image
+                        className="w-4 h-4"
+                        src={"/assets/about/recruitList/3.png"}
+                        alt="图标"
+                        width={16}
+                        height={16}
+                      />
+                      <span>薪资: {item.salary}</span>
                     </div>
+                    <div className="flex gap-2 items-center">
+                      <Image
+                        className="w-4 h-4"
+                        src={"/assets/about/recruitList/3.png"}
+                        alt="图标"
+                        width={16}
+                        height={16}
+                      />
+                      <span>联系人: {item.contact}</span>
+                    </div>
+                  </div>
+
+                  <div className="mt-4 flex gap-2 items-start">
+                    <Image
+                      className="w-5 h-5 mt-1"
+                      src={"/assets/about/recruitList/3.png"}
+                      alt="图标"
+                      width={20}
+                      height={20}
+                    />
+                    {/* <CHANGE> 职位要求文本宽度响应式调整 */}
+                    <p className="text-sm w-full sm:w-4/5 line-clamp-6">职位要求: {item.jobRequirements}</p>
                   </div>
                 </div>
-              ))}
 
-              {/* 分页器 */}
-              <div className="flex justify-center py-6">
-                <Pagination
-                  current={pageNum}
-                  pageSize={pageSize}
-                  total={data?.total || 0}
-                  onChange={(page) => setPageNum(page)}
-                  showSizeChanger={false}
-                />
+                {/* 右侧按钮 */}
+                {/* <CHANGE> 按钮区域响应式调整,移动端居中,桌面端右对齐 */}
+                <div className="flex justify-center sm:justify-center sm:items-center">
+                  <Link href={`/about/recruitList/${item.id}`}>
+                    <button
+                      className="cursor-pointer mt-2 sm:mt-4 lg:mt-20 w-32 sm:w-40 bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 sm:py-3 px-4 sm:px-6 rounded-full transition duration-300 ease-in-out transform hover:scale-105 text-sm sm:text-base">
+                      了解详情 &gt;&gt;
+                    </button>
+                  </Link>
+                </div>
               </div>
-            </>
-          )}
+            </div>
+          ))}
+
+          {/* 分页器 */}
+          <div className="flex justify-center py-4 sm:py-6">
+            <PaginationClient current={pageNum} total={data?.total || 0} pageSize={pageSize}/>
+          </div>
         </div>
       </div>
     </div>
-  );
-}
+  )
+}