From 8502fdc6c3676c23580ff60dad90cb7d5681336b Mon Sep 17 00:00:00 2001 From: zhangjianjun Date: Thu, 5 Mar 2026 16:06:45 +0800 Subject: [PATCH] update --- src/App.tsx | 32 ++- src/api/mockData.ts | 128 +++++++++- src/components/banner.tsx | 66 ++++- .../layout/SwiperCardSection/index.tsx | 5 +- src/layouts/Footer.tsx | 178 ++++++------- src/layouts/Header.tsx | 78 ++---- src/layouts/MainLayout.tsx | 9 +- src/pages/About/Founder.tsx | 120 +++++---- src/pages/About/History.tsx | 213 ++++++++-------- src/pages/About/overview.tsx | 120 ++++----- src/pages/Business/BaseGroup.tsx | 120 +++------ src/pages/Business/CommercialGroup.tsx | 209 ++++++++------- src/pages/Business/CommercialGroupDetail.tsx | 80 ++---- src/pages/Business/InvestGroup.tsx | 169 +++++-------- src/pages/Business/RealtyGroup.tsx | 108 +++----- src/pages/Business/RuijingGroup.tsx | 122 ++++----- src/pages/Home/index.tsx | 208 ++++++--------- src/pages/Join/Campus.tsx | 17 +- src/pages/Join/Culture.tsx | 117 +++++---- src/pages/News/Detail.tsx | 29 ++- src/pages/News/Media.tsx | 61 ++--- src/pages/News/NewsPublic.tsx | 131 +++++----- src/pages/Others/AuditReport.tsx | 62 +++-- src/pages/Others/PrivacyPolicy.tsx | 41 +-- src/pages/Others/Search.tsx | 99 +++++--- src/pages/Others/SiteMap.tsx | 158 ++++-------- src/pages/Others/TermsOfUse.tsx | 39 +-- src/pages/PropertyService/index.tsx | 105 ++++---- src/pages/Social/Foundation.tsx | 239 +++++++----------- src/pages/Social/Sustainability.tsx | 194 +++++++------- src/store/index.ts | 54 +++- 31 files changed, 1533 insertions(+), 1778 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 7a038fa..ed5b500 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,7 +4,7 @@ import "./App.css" import routes from "@/Routes"; import { useCallback, useEffect, useState } from "react"; import appApi from "@/api/app"; -import { useStore } from "@/store"; +import { useStore, type I18nData } from "@/store"; function AppRoutes() { return useRoutes(routes); @@ -12,9 +12,12 @@ function AppRoutes() { function App() { const [init, setInit] = useState(false); + const locale = useStore((s) => s.locale); + const appConfig = useStore((s) => s.appConfig); - const initState = useCallback((data: any) => { - const { favicon, shortName } = data?.company?.config || {}; + const initState = useCallback((data: Record) => { + const company = data?.company as { config?: { favicon?: string; shortName?: string } } | undefined; + const { favicon, shortName } = company?.config || {}; if (favicon) { // 替换网页图标 const favor: any = document.querySelector("link[rel*='icon']") || document.createElement('link'); @@ -29,24 +32,27 @@ function App() { const getAppConfig = useCallback(async () => { try { - let res = await appApi.getAppConfig(); - console.log('-------res', res) - let data = res.data; - + const res = await appApi.getAppConfig(); + const data = res.data as I18nData; useStore.getState().setAppConfig(data); - initState(data) + const locale = useStore.getState().locale; + const config = data[locale] ?? data.zhCN; + initState(config); } catch (error) { - console.log(error) + console.log(error); } setInit(true); }, []) useEffect(() => { - if (init) { - return; - } + if (init) return; getAppConfig(); - }, []) + }, []); + + useEffect(() => { + const shortName = (appConfig as { company?: { config?: { shortName?: string } } })?.company?.config?.shortName; + if (shortName) document.title = shortName; + }, [locale, appConfig]); return ( <> diff --git a/src/api/mockData.ts b/src/api/mockData.ts index c7e42cf..b13a80a 100644 --- a/src/api/mockData.ts +++ b/src/api/mockData.ts @@ -1,18 +1,32 @@ /** - * 页面数据统一配置 - * 注意:Header 与 Footer 在部分 path/label 上存在差异,后续应用时可统一修正 + * 接口返回数据结构 + * mockData: { + * zhCN: {...}, + * en: {...} + * } */ export type NavChild = { path: string; label: string }; -export type NavItem = { path: string; label: string; children?: NavChild[] }; +export type NavItem = { path: string; label: string; children?: NavChild[]; index?: boolean }; +export type LocaleKey = "zhCN" | "en"; -const mockData = { - // === 1. 全局/布局(优先) === +const zhCN = { companyName: "银泰", logo: "/images/logo.png", + company: { + config: { + favicon: "/favicon.ico", + shortName: "银泰", + }, + }, header: { navItems: [ + { + label: "首页", + path: "/", + index: true, + }, { label: "关于银泰", path: "/about", @@ -59,7 +73,7 @@ const mockData = { }, ] as NavItem[], langMenuItems: [ - { key: "zh", label: "中文" }, + { key: "zhCN", label: "中文" }, { key: "en", label: "English" }, ], }, @@ -157,6 +171,26 @@ const mockData = { backgroundImage: "/images/welfare-check.png", }, ], + newsData: [ + { + title: "银泰百货×敦煌研究院联名新品限量首发", + snippet: "10月28日,在杭州余杭区委城市工作会议暨城市新中心中轴线创新发展大会上,银泰集团正式宣布银泰杭州新中心项目定名为「杭州银泰中心」", + date: "2024-01-15", + path: "/news/1", + }, + { + title: "银泰中国区总裁陈晓:我们是长期主义者", + snippet: "10月28日,在杭州余杭区委城市工作会议暨城市新中心中轴线创新发展大会上,银泰集团正式宣布银泰杭州新中心项目定名为「杭州银泰中心」", + date: "2024-01-10", + path: "/news/2", + }, + { + title: "中国青年发展基金会 | 银泰公益基金会合作签约", + snippet: "10月28日,在杭州余杭区委城市工作会议暨城市新中心中轴线创新发展大会上,银泰集团正式宣布银泰杭州新中心项目定名为「杭州银泰中心」", + date: "2023-11-20", + path: "/news/3", + }, + ], }, about: { @@ -318,7 +352,7 @@ const mockData = { commercialGroupDetail: { banner: { title: "in77", - largedesc: "地标型高端商业综合体", + largeContent: "地标型高端商业综合体", titleSize: "large", showBreadcrumb: true, backgroundImage: "/images/bg-overview.png", @@ -888,5 +922,85 @@ const mockData = { }, }; +const en: typeof zhCN = { + ...zhCN, + companyName: "Yintai", + company: { config: { favicon: "/favicon.ico", shortName: "Yintai" } }, + header: { + ...zhCN.header, + navItems: [ + { label: "Home", path: "/", index: true }, + { + label: "About Yintai", + path: "/about", + children: [ + { path: "/about/overview", label: "Overview" }, + { path: "/about/history", label: "History" }, + { path: "/about/founder", label: "Founder" }, + ], + }, + { + label: "Business", + path: "/business", + children: [ + { path: "/business/commercial-group", label: "Yintai Commercial" }, + { path: "/business/base-group", label: "Yintai Base" }, + { path: "/business/realty-group", label: "Yintai Realty" }, + { path: "/business/invest-group", label: "Yintai Investment" }, + { path: "/business/ruijing-group", label: "Ruijing Group" }, + ], + }, + { + label: "Social Responsibility", + path: "/social", + children: [ + { path: "/social/sustainability", label: "Sustainability" }, + { path: "/social/foundation", label: "Yintai Foundation" }, + ], + }, + { + label: "News", + path: "/news", + children: [ + { path: "/news/public", label: "Press" }, + { path: "/news/media", label: "Media" }, + ], + }, + { + label: "Join Yintai", + path: "/join", + children: [ + { path: "/join/culture", label: "Culture" }, + { path: "/join/campus", label: "Careers" }, + ], + }, + ] as NavItem[], + langMenuItems: [ + { key: "zhCN", label: "中文" }, + { key: "en", label: "English" }, + ], + }, + footer: { + ...zhCN.footer, + lowerLinks: [ + { path: "/contact-us", label: "Contact" }, + { path: "/site-map", label: "Site Map" }, + { path: "/terms-of-use", label: "Terms of Use" }, + { path: "/privacy-policy", label: "Privacy Policy" }, + { path: "/audit-report", label: "Audit Report" }, + ], + copyright: "Copyright ©2001-{year} | China Yintai Investment Co., Ltd.", + }, + home: { + ...zhCN.home, + banner: { + ...zhCN.home.banner, + title: "Yintai Group", + content: "A Model of Modern Commerce in China", + }, + }, +}; +export type LocaleConfig = typeof zhCN; +const mockData = { zhCN, en }; export default mockData; diff --git a/src/components/banner.tsx b/src/components/banner.tsx index db9fc21..3d0441e 100644 --- a/src/components/banner.tsx +++ b/src/components/banner.tsx @@ -4,20 +4,30 @@ import { Autoplay, EffectFade } from "swiper/modules"; import "swiper/css"; import "swiper/css/effect-fade"; import styles from "./Banner.module.css"; -import { useEffect } from "react"; +import { useMemo } from "react"; +import { useStore } from "@/store"; const FALLBACK_GRADIENT = "linear-gradient(135deg, #1a2a4a 0%, #2d4a7c 100%)"; -type BreadcrumbItem = { label: string; to: string }; + +export type BannerConfig = { + title?: string; + content?: string; + subtitle?: string; + largeContent?: string; + titleSize?: "large" | "medium" | string; + showBreadcrumb?: boolean; + backgroundImage?: string | string[]; +}; type Props = { title: string; subtitle?: string; desc?: string; + content?: string; largedesc?: string; showBreadcrumb?: boolean; - breadcrumbItems?: BreadcrumbItem[]; //废弃掉,后改用pathname查找菜单名显示 - titleSize?: "large" | "medium"; + titleSize?: "large" | "medium" | string; backgroundImage: string | string[]; }; @@ -25,21 +35,57 @@ export default function Banner({ title, subtitle, desc, + content, largedesc, showBreadcrumb, - breadcrumbItems, titleSize = "large", backgroundImage, }: Props) { + const appConfig = useStore((s) => s.appConfig); + const header = appConfig?.header; + const navItems = header?.navItems ?? []; + const location = useLocation(); const images = Array.isArray(backgroundImage) ? backgroundImage : [backgroundImage]; const isCarousel = images.length > 1; + const descText = desc ?? content; + + const breadcrumbItems = useMemo(() => { + const segments = location.pathname.split("/").filter((s) => s !== ""); + if (segments.length === 0) { + return [{ label: "首页", to: "/" }]; + } + const paths: string[] = []; + for (let i = 0; i < segments.length; i++) { + paths.push((paths[i - 1] ?? "") + "/" + segments[i]); + } + const getLabelByPath = (path: string): string => { + if (path === "/") return navItems.find((n) => n.index)?.label ?? "首页"; + const top = navItems.find((n) => n.path === path); + if (top) return top.label; + for (const item of navItems) { + const child = item.children?.find((c) => c.path === path); + if (child) return child.label; + } + const last = path.split("/").pop() ?? path; + return last; + }; + const items = paths.map((path) => ({ + label: getLabelByPath(path), + to: path, + })); + items.unshift({ + label: navItems.find((n) => n.index)?.label ?? "首页", + to: "/", + }); + return items; + }, [location.pathname, navItems]); const heroContent = (

{title}

{subtitle &&

{subtitle}

} - {desc &&

{desc}

} + {descText &&

{descText}

} {largedesc &&

{largedesc}

}
{showBreadcrumb && @@ -52,14 +98,6 @@ export default function Banner({
); - - - // pathname - useEffect(() => { - const pathname = location.pathname; - console.log('pathname', pathname) - console.log('location', location) - },[location.pathname]) return (
{item.title} -

{item.desc}

+

{item.content ?? item.desc}

diff --git a/src/layouts/Footer.tsx b/src/layouts/Footer.tsx index b7511cc..d7f2f10 100644 --- a/src/layouts/Footer.tsx +++ b/src/layouts/Footer.tsx @@ -1,112 +1,86 @@ import { Link } from "react-router-dom"; import styles from "./Footer.module.css"; - -const footerColumns = [ - { - title: "关于银泰", - children: [ - { path: "/about", label: "公司简介" }, - { path: "/about/history", label: "发展历程" }, - { path: "/about/culture", label: "企业文化" }, - ], - }, - { - title: "集团业务", - children: [ - { path: "/about", label: "银泰商业集团" }, - { path: "/business/base-group", label: "银泰基业集团" }, - { path: "/business/realty-group", label: "银泰置地集团" }, - { path: "/business/invest-group", label: "银泰投资集团" }, - { path: "/business/ruijing-group", label: "瑞京集团" }, - ], - }, - { - title: "社会责任", - children: [ - { path: "/social", label: "可持续发展" }, - { path: "/social/sustainable", label: "银泰公益基金会" }, - ], - }, - { - title: "新闻中心", - children: [ - { path: "/news", label: "银泰咨询" }, - { path: "/news/media", label: "媒体垂询" }, - ], - }, - { - title: "加入我们", - children: [ - { path: "/join", label: "企业文化" }, - { path: "/join/campus", label: "招贤纳士" }, - ], - }, -]; +import { useStore } from "@/store"; export default function Footer() { - return ( -
-
-
-
- {footerColumns.map((col) => ( -
-
{col.title}
- {col.children.map((link) => ( - - {link.label} - - ))} -
- ))} -
- weixin - weibo - logo + const appConfig = useStore((s) => s.appConfig); + const footer = appConfig?.footer; + const header = appConfig?.header; + + const footerColumns = header?.navItems?.filter((item) => !item.index) ?? []; + const lowerLinks = footer?.lowerLinks ?? []; + const socialIcons = footer?.socialIcons ?? []; + const copyright = footer?.copyright ?? "版权声明©2001-{year} | 中国银泰投资有限公司"; + const icpNumber = footer?.icpNumber ?? "京ICP备05026114号-1"; + + return ( +
+
+
+
+ {footerColumns.map((col) => ( +
+
{col.label}
+ {col.children?.map((link) => ( + + {link.label} + + ))} +
+ ))} +
+ {socialIcons.map((icon) => ( + {icon.alt} + ))} +
+
+
-
-
-
- -
- ); + + + ); } - -function FooterLower() { - const footerLowerLinks = [ - { path: "/contact-us", label: "联系我们" }, - { path: "/site-map", label: "网站地图" }, - { path: "/terms-of-use", label: "使用条款" }, - { path: "/privacy-policy", label: "隐私保护" }, - { path: "/audit-report", label: "审计举报" }, - ] +function FooterLower({ + lowerLinks, + copyright, + icpNumber, +}: { + lowerLinks: { path: string; label: string }[]; + copyright: string; + icpNumber: string; +}) { return (
-
-
- 版权声明©2001-{new Date().getFullYear()} | 中国银泰投资有限公司 - 京ICP备05026114号-1 -
-
- {footerLowerLinks.map((link, index) => ( - <> - - {link.label} - - { - index !== footerLowerLinks.length - 1 && ( - · - ) - } - - ))} -
+
+
+ {copyright} + {icpNumber} +
+
+ {lowerLinks.map((link, index) => ( + < > + + {link.label} + + {index !== lowerLinks.length - 1 && ·} + + ))} +
+
-
- ) -} \ No newline at end of file + ); +} diff --git a/src/layouts/Header.tsx b/src/layouts/Header.tsx index d9f42cc..82b095a 100644 --- a/src/layouts/Header.tsx +++ b/src/layouts/Header.tsx @@ -2,70 +2,27 @@ import { Link, useLocation } from "react-router-dom"; import { Dropdown } from "antd"; import styles from "./Header.module.css"; import { useEffect, useMemo, useState } from "react"; +import { useStore } from "@/store"; +import type { NavChild } from "@/api/mockData"; +import type { LocaleKey } from "@/store"; -type NavChild = { path: string; label: string }; -type NavItem = { path: string; label: string; children?: NavChild[] }; +const DEFAULT_NAV_ITEMS: { path: string; label: string; children?: NavChild[] }[] = []; +const DEFAULT_LANG_ITEMS = [{ key: "zh", label: "中文" }, { key: "en", label: "English" }]; export default function Header() { const location = useLocation(); + const appConfig = useStore((s) => s.appConfig); + const locale = useStore((s) => s.locale); + const setLocale = useStore((s) => s.setLocale); - const navItems: NavItem[] = [ - { - label: "关于银泰", - path: "/about", - children: [ - { path: "/about/overview", label: "集团概览" }, - { path: "/about/history", label: "发展历程" }, - { path: "/about/founder", label: "创始人介绍" }, - ], - }, - { - label: "集团业务", - path: "/business", - children: [ - { path: "/business/commercial-group", label: "银泰商业集团" }, - { path: "/business/base-group", label: "银泰基业集团" }, - { path: "/business/realty-group", label: "银泰置地集团" }, - { path: "/business/invest-group", label: "银泰投资集团" }, - { path: "/business/ruijing-group", label: "瑞京集团" }, - ], - }, - { - label: "社会责任", - path: "/social", - children: [ - { path: "/social/sustainability", label: "可持续发展" }, - { path: "/social/foundation", label: "银泰公益基金会" }, - ], - }, - { - label: "新闻中心", - path: "/news", - children: [ - { path: "/news/public", label: "集团发布" }, - { path: "/news/media", label: "媒体垂询" }, - ], - }, - { - label: "加入银泰", - path: "/join", - children: [ - { path: "/join/culture", label: "企业文化" }, - { path: "/join/campus", label: "招贤纳士" }, - ], - }, - ]; - - const langMenuItems = [ - { key: "zh", label: "中文" }, - { key: "en", label: "English" }, - ]; + const navItems = appConfig?.header?.navItems?.filter((item) => !item.index) ?? DEFAULT_NAV_ITEMS; + const langMenuItems = appConfig?.header?.langMenuItems ?? DEFAULT_LANG_ITEMS; + const logo = appConfig?.logo ?? "/images/logo.png"; const [activeNav, setActiveNav] = useState(""); const [showDropPanel, setShowDropPanel] = useState(false); const [hoverElLeft, setHoverElLeft] = useState(0); const handleNavEnter = (e: any, path: string) => { - console.log(e, e.target.offsetWidth) // left + 元素宽度的一半 const left = e.target.offsetLeft; setHoverElLeft(left); @@ -110,7 +67,7 @@ export default function Header() { >
- logo + logo