save
|
Before Width: | Height: | Size: 670 B After Width: | Height: | Size: 670 B |
|
Before Width: | Height: | Size: 680 B After Width: | Height: | Size: 680 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="92" height="55" viewBox="0 0 92 55"><defs><pattern x="0" y="0" width="92" height="55" patternUnits="userSpaceOnUse" id="master_svg0_94_11479"><image x="0" y="0" width="92" height="55" xlink:href="data:image/png;base64,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"/></pattern></defs><rect x="0" y="0" width="92" height="55" rx="0" fill="url(#master_svg0_94_11479)" fill-opacity="1"/></svg>
|
||||
|
Before Width: | Height: | Size: 3.7 KiB |
|
|
@ -138,3 +138,7 @@ body {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.logo-dark {
|
||||
filter: brightness(0) saturate(100%) invert(16%) sepia(25%) saturate(4500%) hue-rotate(223deg) brightness(80%) contrast(85%);
|
||||
}
|
||||
|
|
@ -17,9 +17,9 @@ function App() {
|
|||
const locale = useStore((s) => s.locale);
|
||||
const appConfig = useStore((s) => s.appConfig);
|
||||
|
||||
const initState = useCallback((data: Record<string, unknown>) => {
|
||||
const company = data?.company as { config?: { favicon?: string; shortName?: string } } | undefined;
|
||||
const { favicon, shortName } = company?.config || {};
|
||||
const initState = useCallback((data: any) => {
|
||||
const company = data?.__global__.company;
|
||||
const { favicon, shortName } = company || {};
|
||||
if (favicon) {
|
||||
const favor: any = document.querySelector("link[rel*='icon']") || document.createElement('link');
|
||||
favor.type = 'image/x-icon';
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ export default function YearPicker({
|
|||
{value != null ? `${value}年` : placeholder}
|
||||
</span>
|
||||
<div className={styles.icons}>
|
||||
<img className={`${styles.arrow} ${open ? styles.arrowOpen : ""}`} src="/images/icon-arrow-down.png" alt="arrow-down" style={{ width: "24px", height: "24px" }} />
|
||||
<img className={`${styles.arrow} ${open ? styles.arrowOpen : ""}`} src="/images/icons/icon-arrow-down.png" alt="arrow-down" style={{ width: "24px", height: "24px" }} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -33,8 +33,7 @@ export default function Banner({
|
|||
backgroundImage,
|
||||
}: Props) {
|
||||
const appConfig = useStore((s) => s.appConfig);
|
||||
const header = appConfig?.header;
|
||||
const navItems = header?.navItems ?? [];
|
||||
const navItems = appConfig?.navItems ?? [];
|
||||
|
||||
const location = useLocation();
|
||||
const images = Array.isArray(backgroundImage) ? backgroundImage : [backgroundImage];
|
||||
|
|
@ -61,7 +60,7 @@ export default function Banner({
|
|||
if (child) return child.label;
|
||||
}
|
||||
const last = path.split("/").pop() ?? path;
|
||||
return last;
|
||||
return title;
|
||||
};
|
||||
const items = paths.map((path) => ({
|
||||
label: getLabelByPath(path),
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export default function Article({ data }: { data: Data }) {
|
|||
<div className={styles.article}>
|
||||
<div className={styles.articleHeaderLine}>
|
||||
<div className={styles.articleHeaderLineBack} onClick={() => window.history.back()}>
|
||||
<img src="/images/icon-arrowleft.png" alt="arrowleft" style={{ width: "20px", height: "20px" }} />
|
||||
<img src="/images/icons/icon-arrowleft.png" alt="arrowleft" style={{ width: "20px", height: "20px" }} />
|
||||
<span>返回</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export default function JobPage({ data }: { data: Data }) {
|
|||
<div className={styles.jobPage}>
|
||||
<div className={styles.jobPageHeaderLine}>
|
||||
<div className={styles.jobPageHeaderLineBack} onClick={() => window.history.back()}>
|
||||
<img src="/images/icon-arrowleft.png" alt="arrowleft" style={{ width: "20px", height: "20px" }} />
|
||||
<img src="/images/icons/icon-arrowleft.png" alt="arrowleft" style={{ width: "20px", height: "20px" }} />
|
||||
<span>返回</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ export default function RowAccordion({ data, placement='bottom' }: Props) {
|
|||
useEffect(() => {
|
||||
if (isInView && containerRef.current) {
|
||||
const rect = containerRef.current.getBoundingClientRect();
|
||||
smoothScrollTo(window.scrollY + rect.top, 1200);
|
||||
smoothScrollTo(window.scrollY + rect.top, 800);
|
||||
}
|
||||
}, [isInView]);
|
||||
|
||||
|
|
@ -99,7 +99,7 @@ export default function RowAccordion({ data, placement='bottom' }: Props) {
|
|||
variants={contentItemVariants}
|
||||
transition={{
|
||||
duration: 0.6,
|
||||
delay: 0.5 + index * 0.12,
|
||||
delay: 0.3 + index * 0.12,
|
||||
ease: [0.25, 0.46, 0.45, 0.94],
|
||||
}}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import { useCallback, useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { Swiper, SwiperSlide } from "swiper/react";
|
||||
import type { Swiper as SwiperType } from "swiper";
|
||||
import "swiper/css";
|
||||
import SectionTitle from "../SectionTitle";
|
||||
import styles from "./index.module.css";
|
||||
import { RightOutlined, LeftOutlined } from "@ant-design/icons";
|
||||
import { useLocation } from "react-router-dom";
|
||||
type Data = {
|
||||
title: string;
|
||||
cardItems: {
|
||||
|
|
@ -18,13 +19,28 @@ type Data = {
|
|||
}
|
||||
|
||||
export default function SwiperCardSection({ data }: { data: Data }) {
|
||||
const location = useLocation();
|
||||
const hash = location.hash;
|
||||
const id = decodeURIComponent(hash.replace('#', ''));
|
||||
|
||||
const [swiperRef, setSwiperRef] = useState<SwiperType | null>(null);
|
||||
const [activeIndex, setActiveIndex] = useState(0);
|
||||
const onSwiperChange = useCallback((e: any) => {
|
||||
setActiveIndex(e.activeIndex);
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (id && data.cardItems && swiperRef) {
|
||||
const index = data.cardItems.findIndex((item) => item.title === id);
|
||||
if (index !== -1) {
|
||||
setTimeout(() => {
|
||||
swiperRef.slideTo(index);
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
}, [id, data.cardItems, swiperRef])
|
||||
return (
|
||||
<section className={styles.swiperCardSection}>
|
||||
<section className={styles.swiperCardSection} id={id}>
|
||||
<SectionTitle title={data.title} />
|
||||
<div className={styles.carouselWrapper} >
|
||||
{activeIndex > 0 && (
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import styles from './index.module.css';
|
||||
import TopTabs from './TopTabs';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
type Data = {
|
||||
tabItems: {
|
||||
|
|
@ -19,9 +20,24 @@ type Data = {
|
|||
}
|
||||
|
||||
export default function TopTabsSection({ data, className }: { data: Data, className?: string }) {
|
||||
const location = useLocation();
|
||||
const hash = location.hash;
|
||||
const id = decodeURIComponent(hash.replace('#', ''));
|
||||
const [activeIndex, setActiveIndex] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (id && data.tabItems) {
|
||||
setTimeout(() => {
|
||||
const index = data.tabItems.findIndex((item) => item.tabName === id);
|
||||
console.log('index', index, id, data.tabItems)
|
||||
if (index !== -1) {
|
||||
setActiveIndex(index);
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
}, [id, data.tabItems])
|
||||
return (
|
||||
<section className={`${styles.topTabsSection} ${className}`} style={{ backgroundImage: `url(${data.backgroundImage})` }}>
|
||||
<section id={id} className={`${styles.topTabsSection} ${className}`} style={{ backgroundImage: `url(${data.backgroundImage})` }}>
|
||||
<TopTabs data={data} activeIndex={activeIndex} setActiveIndex={setActiveIndex} />
|
||||
<div className={styles.topTabsContent}>
|
||||
<div className={styles.topTabsContentLeft}>
|
||||
|
|
|
|||
|
|
@ -6,8 +6,20 @@ const useHashScroll = () => {
|
|||
|
||||
useEffect(() => {
|
||||
if (location.hash) {
|
||||
const element = document.querySelector(location.hash);
|
||||
element?.scrollIntoView({ behavior: "smooth" });
|
||||
setTimeout(() => {
|
||||
const element = document.querySelector(decodeURIComponent(location.hash));
|
||||
if (element) {
|
||||
const header = document.querySelector("header");
|
||||
const headerHeight = header?.getBoundingClientRect().height ?? 7.5 * 16;
|
||||
const elementTop = element.getBoundingClientRect().top + window.scrollY;
|
||||
const offsetPosition = elementTop - headerHeight;
|
||||
|
||||
window.scrollTo({
|
||||
top: offsetPosition,
|
||||
behavior: "smooth",
|
||||
});
|
||||
}
|
||||
})
|
||||
} else {
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
|
|
|
|||
|
|
@ -42,11 +42,13 @@
|
|||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
gap: 40px;
|
||||
position: absolute;
|
||||
right: 3.75rem;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.footerLogo {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
|
|
|
|||
|
|
@ -5,15 +5,17 @@ import type { NavItem, NavChild } from "@/type";
|
|||
|
||||
export default function Footer() {
|
||||
const appConfig = useStore((s) => s.appConfig);
|
||||
const footer = appConfig?.footer;
|
||||
const header = appConfig?.header;
|
||||
const footer = appConfig?.__global__?.footer;
|
||||
|
||||
const footerColumns = header?.navItems?.filter((item: NavItem) => item.path !== "/") ?? [];
|
||||
const lowerLinks = footer?.lowerLinks ?? [];
|
||||
const socialIcons = footer?.socialIcons ?? [];
|
||||
const copyright = footer?.copyright ?? "版权声明©2001-{year} | 中国银泰投资有限公司";
|
||||
const footerColumns = appConfig?.navItems?.filter((item: NavItem) => item.path !== "/") ?? [];
|
||||
const lowerLinks = footer?.lowerLinks?.items ?? [];
|
||||
const socialIcons = footer?.socialIcons?.items ?? [];
|
||||
const copyright = footer?.copyright ?? "版权声明©2001-{year}";
|
||||
const companyName = appConfig?.__global__.company?.companyName;
|
||||
const icpNumber = footer?.icpNumber ?? "京ICP备05026114号-1";
|
||||
|
||||
const logo = appConfig?.__global__.company?.logo;
|
||||
|
||||
return (
|
||||
<footer className={`layout-footer ${styles.footer}`}>
|
||||
<div className={styles.footerUpper}>
|
||||
|
|
@ -34,14 +36,21 @@ export default function Footer() {
|
|||
</div>
|
||||
))}
|
||||
<div className={styles.footerRight}>
|
||||
{socialIcons.map((icon: { src: string; alt: string }) => (
|
||||
{socialIcons.filter((item:any) => item.show).map((icon: any) => (
|
||||
<Link to={icon.link} target="_blank" key={icon.alt}>
|
||||
<img
|
||||
key={icon.alt}
|
||||
src={icon.src}
|
||||
alt={icon.alt}
|
||||
style={{ width: "26px", height: "26px" }}
|
||||
/>
|
||||
</Link>
|
||||
))}
|
||||
<img
|
||||
src={logo}
|
||||
alt="logo"
|
||||
style={{ width: "92px", height: "56px" }}
|
||||
className="logo-dark"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -49,6 +58,7 @@ export default function Footer() {
|
|||
<FooterLower
|
||||
lowerLinks={lowerLinks}
|
||||
copyright={copyright.replace("{year}", String(new Date().getFullYear()))}
|
||||
companyName={companyName}
|
||||
icpNumber={icpNumber}
|
||||
/>
|
||||
</footer>
|
||||
|
|
@ -58,17 +68,19 @@ export default function Footer() {
|
|||
function FooterLower({
|
||||
lowerLinks,
|
||||
copyright,
|
||||
companyName,
|
||||
icpNumber,
|
||||
}: {
|
||||
lowerLinks: { path: string; label: string }[];
|
||||
copyright: string;
|
||||
companyName: string;
|
||||
icpNumber: string;
|
||||
}) {
|
||||
return (
|
||||
<div className={styles.footerLower}>
|
||||
<div className={`header-row ${styles.footerLowerInner}`}>
|
||||
<div style={{ display: "flex", flexDirection: "row", gap: "50px" }}>
|
||||
<span>{copyright}</span>
|
||||
<span>{`${copyright} | ${companyName}`}</span>
|
||||
<span>{icpNumber}</span>
|
||||
</div>
|
||||
<div className={styles.footerLowerLinks}>
|
||||
|
|
|
|||
|
|
@ -14,22 +14,41 @@
|
|||
font-style: normal;
|
||||
text-transform: none;
|
||||
|
||||
transition: background 0.3s ease;
|
||||
/* transition: all 0.7s ease-in-out;
|
||||
transition-delay: 0.3s; */
|
||||
}
|
||||
|
||||
.header::before {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 0%;
|
||||
background: #fff;
|
||||
transition: height 0.7s ease-in-out;
|
||||
}
|
||||
|
||||
|
||||
.showDropPanel.header::before {
|
||||
height: 350%;
|
||||
}
|
||||
.whiteMode.header::before {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.whiteMode.header {
|
||||
background: #fff;
|
||||
/* background: rgba(255, 255, 255, 1); */
|
||||
box-shadow: 0 0 10px 0 rgba(255, 255, 255, 0.1);
|
||||
border-bottom: 1px solid #eee;
|
||||
|
||||
box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.2);
|
||||
transition-delay: none;
|
||||
}
|
||||
|
||||
.whiteMode .navLink {
|
||||
.whiteMode .navLink, .showDropPanel .navLink {
|
||||
color: #222222;
|
||||
}
|
||||
|
||||
.whiteMode {
|
||||
.whiteMode, .showDropPanel {
|
||||
.searchBtn {
|
||||
color: #222222;
|
||||
}
|
||||
|
|
@ -49,6 +68,7 @@
|
|||
}
|
||||
|
||||
.headerInner {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
|
@ -58,14 +78,35 @@
|
|||
|
||||
.headerInner::after {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 3.75rem;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
content: '';
|
||||
display: block;
|
||||
width: calc(100% - 7.5rem);
|
||||
width: 95%;
|
||||
margin: 0 auto;
|
||||
box-sizing: border-box;
|
||||
height: 1px;
|
||||
background: #FFFFFF;
|
||||
transform: scaleX(0);
|
||||
transform-origin: 90% 0; /* 交点:左侧 85%,右侧 15%,从此点向左右展开 */
|
||||
transition: transform 1.5s ease-in-out;
|
||||
}
|
||||
.animate {
|
||||
&.headerInner::after {
|
||||
transform: scaleX(1);
|
||||
}
|
||||
.crossYline {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.whiteMode, .showDropPanel {
|
||||
.headerInner::after {
|
||||
transform: scaleX(0);
|
||||
}
|
||||
.crossYline {
|
||||
height: 0%;
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
|
|
@ -121,9 +162,11 @@
|
|||
|
||||
.crossYline {
|
||||
width: 1px;
|
||||
height: 100%;
|
||||
height: 0%;
|
||||
background: #FFFFFF;
|
||||
transition: height 0.3s ease-in-out;
|
||||
align-self: flex-end; /* 交点在最底部,从此点向上展开 */
|
||||
transform-origin: center bottom; /* 缩放从底部中心点展开 */
|
||||
transition: height 1s ease-in-out;
|
||||
}
|
||||
|
||||
.langTrigger {
|
||||
|
|
@ -154,15 +197,16 @@
|
|||
left: 0;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
/* background: rgba(255, 255, 255, 0.9); */
|
||||
/* box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.1); */
|
||||
padding: 0;
|
||||
z-index: 1000;
|
||||
transition: height 0.9s ease-in-out;
|
||||
overflow: hidden;
|
||||
transition: height 0.5s ease-in-out, padding-top 0.5s ease-in-out;
|
||||
|
||||
&.visible {
|
||||
height: 23.75rem;
|
||||
padding: 1.25rem;
|
||||
padding-top: 1.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import styles from "./Header.module.css";
|
|||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useStore } from "@/store";
|
||||
import type { NavChild, NavItem, LocaleKey, SupportLocale } from "@/type";
|
||||
import ScrollReveal from "@/components/ScrollReveal";
|
||||
|
||||
|
||||
const DEFAULT_NAV_ITEMS: { path: string; label: string; children?: NavChild[] }[] = [];
|
||||
|
||||
|
|
@ -15,9 +15,9 @@ export default function Header() {
|
|||
const setLocale = useStore((s) => s.setLocale);
|
||||
const supportLocales = useStore((s) => s.supportLocales);
|
||||
|
||||
const navItems = appConfig?.header?.navItems?.filter((item: NavItem) => item.path !== "/") ?? DEFAULT_NAV_ITEMS;
|
||||
const navItems = appConfig?.navItems?.filter((item: NavItem) => item.path !== "/") ?? DEFAULT_NAV_ITEMS;
|
||||
const langMenuItems: SupportLocale[] = supportLocales || [];
|
||||
const logo = appConfig?.company?.logo ?? "/images/logo.png";
|
||||
const logo = appConfig?.__global__.company?.logo;
|
||||
|
||||
const [activeNav, setActiveNav] = useState("");
|
||||
const [showDropPanel, setShowDropPanel] = useState(false);
|
||||
|
|
@ -57,13 +57,26 @@ export default function Header() {
|
|||
return () => window.removeEventListener("scroll", handleScroll);
|
||||
}, []);
|
||||
|
||||
// 动画
|
||||
const [animateHeader, setAnimateHeader] = useState(false);
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
setAnimateHeader(true)
|
||||
}, 500);
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<header className={`${styles.header} ${(showDropPanel || showWhiteMode) ? styles.whiteMode : ""}`}
|
||||
<header className={`${styles.header}
|
||||
${showWhiteMode && styles.whiteMode}
|
||||
${showDropPanel && styles.showDropPanel}
|
||||
`}
|
||||
onMouseLeave={() => setShowDropPanel(false)}
|
||||
>
|
||||
<div className={`header-row ${styles.headerInner}`}>
|
||||
<div className={`header-row ${styles.headerInner} ${animateHeader ? styles.animate : ""}`}>
|
||||
<Link to="/" className={styles.logo}>
|
||||
<img src={logo} alt="logo" style={{ width: "5.75rem", height: "3.4375rem" }} />
|
||||
<img src={logo} alt="logo" style={{ width: "5.75rem", height: "3.4375rem" }}
|
||||
className={(showDropPanel || showWhiteMode) ? "logo-dark" : ""}
|
||||
/>
|
||||
</Link>
|
||||
<div className={styles.headerRight}>
|
||||
<nav>
|
||||
|
|
@ -125,7 +138,6 @@ function DropPanel({ items, left, onLinkClick, show }: {
|
|||
clearTimeout(timeout);
|
||||
}
|
||||
}, [show]);
|
||||
if (!visible) return null;
|
||||
return (
|
||||
<div id="drop-panel" className={`${styles.dropPanel} ${visible ? styles.visible : ""}`} style={{ paddingLeft: left}}>
|
||||
<div className={styles.dropPanelContent}>
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@ import { Outlet, useLocation } from "react-router-dom";
|
|||
import { useEffect } from "react";
|
||||
import Header from "./Header";
|
||||
import Footer from "./Footer";
|
||||
|
||||
import useHashScroll from "@/hooks/useHashScroll";
|
||||
export default function MainLayout() {
|
||||
useHashScroll()
|
||||
const { pathname } = useLocation();
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -71,15 +71,13 @@ export default function AboutFounder() {
|
|||
{section3Data && (
|
||||
<Section title={section3Data?.title} titleColor="#fff" background={section3Data?.backgroundImage}>
|
||||
<div className={styles.section3Content}>
|
||||
{Array.from({
|
||||
length: Math.max(0, ...(section3Data?.columns?.map((c: { title?: string }[]) => c.length) ?? [0])),
|
||||
}).flatMap((_, rowIndex) =>
|
||||
(section3Data?.columns ?? []).map((colItems: { title?: string }[], colIndex: number) => (
|
||||
<div key={`${rowIndex}-${colIndex}`} className={styles.section3Item}>
|
||||
{colItems[rowIndex] ? <li>{colItems[rowIndex].title}</li> : null}
|
||||
{
|
||||
section3Data?.items.map((item: { title?: string }, index: number) => (
|
||||
<div key={index} className={styles.section3Item}>
|
||||
{item.title ? <li>{item.title}</li> : null}
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
}
|
||||
</div>
|
||||
</Section>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ export default function InvestGroup() {
|
|||
{section1Data && <ParagraphSection data={section1Data} />}
|
||||
|
||||
{section2Data && (
|
||||
<section className={styles.investGroup}>
|
||||
<section className={styles.investGroup} id={section2Data.title}>
|
||||
<SectionTitle title={section2Data.title} color="#fff" />
|
||||
<div className={styles.investGroupContent}>
|
||||
<div className={styles.investGroupContentItems}>
|
||||
|
|
@ -45,7 +45,7 @@ export default function InvestGroup() {
|
|||
)}
|
||||
|
||||
{section3Data && (
|
||||
<section className={styles.equityInvestment}>
|
||||
<section className={styles.equityInvestment} id={section3Data.title}>
|
||||
<SectionTitle title={section3Data.title} />
|
||||
<div className={styles.equityInvestmentItems}>
|
||||
{section3Data.items?.map((item: { logo: string; title: string }, index: number) => (
|
||||
|
|
@ -63,6 +63,7 @@ export default function InvestGroup() {
|
|||
)}
|
||||
|
||||
{section4Data && (
|
||||
<div id={section4Data.title}>
|
||||
<Section
|
||||
background={section4Data.backgroundImage}
|
||||
maskBackground="rgba(20,53,92,0.1)"
|
||||
|
|
@ -73,6 +74,7 @@ export default function InvestGroup() {
|
|||
<div className={styles.industryFosterMaskContent}>{section4Data.content}</div>
|
||||
</div>
|
||||
</Section>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -354,7 +354,7 @@
|
|||
color: #666;
|
||||
margin: 0 0 0.5rem;
|
||||
line-height: 1.6;
|
||||
height: 75px;
|
||||
height: 70px;
|
||||
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ function News() {
|
|||
const handleVideoPause = () => {
|
||||
if (videoRef.current) {
|
||||
videoRef.current.pause();
|
||||
videoRef.current.currentTime = 0;
|
||||
// videoRef.current.currentTime = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -160,7 +160,7 @@ function News() {
|
|||
}
|
||||
|
||||
<p className={styles.newsFeaturedCaption}>
|
||||
银泰集团联合钱塘产业集团竞得杭州东部湾新城地块
|
||||
{localNewsData[activeNewsIndex]?.title}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -172,7 +172,7 @@ function News() {
|
|||
<h3 className={styles.newsItemTitle}>
|
||||
{item.title}
|
||||
</h3>
|
||||
<p className={styles.newsItemSnippet}>{item.snippet}</p>
|
||||
<p className={styles.newsItemSnippet} dangerouslySetInnerHTML={{ __html: item.snippet }} ></p>
|
||||
<div className={styles.newsItemDateWrap}>
|
||||
<span className={styles.newsItemDate}>{item.date}</span>
|
||||
<ArrowRightOutlined className={styles.newsItemArrowIcon} style={{ fontSize: '12px' }} />
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export default function CampusDetail() {
|
|||
content: item.description,
|
||||
requirement: item.requirement,
|
||||
lang: item.lang,
|
||||
contact: item.contact,
|
||||
contact: item.contract_info,
|
||||
}
|
||||
});
|
||||
setJobDetail(items);
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ export default function SiteMap() {
|
|||
<div className={styles.siteMapItemChildChildren}>
|
||||
{child.children?.map((childChild) => (
|
||||
<Link
|
||||
to={childChild.path}
|
||||
to={childChild.path.replace('{id}', childChild.label )}
|
||||
className={styles.siteMapItemChildChild}
|
||||
key={childChild.label}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ function resolveKeyPath(
|
|||
|
||||
if (page === "/") {
|
||||
if (tags === "menu") return "home";
|
||||
if (name === "全局配置") return "__global__";
|
||||
if (tags === "global") return "__global__";
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -123,34 +123,6 @@ function buildNavItems(
|
|||
});
|
||||
}
|
||||
|
||||
const DEFAULT_FOOTER_ZH = {
|
||||
lowerLinks: [
|
||||
{ path: "/contact-us", label: "联系我们" },
|
||||
{ path: "/site-map", label: "网站地图" },
|
||||
{ path: "/terms-of-use", label: "使用条款" },
|
||||
{ path: "/privacy-policy", label: "隐私保护" },
|
||||
{ path: "/audit-report", label: "审计举报" },
|
||||
],
|
||||
socialIcons: [
|
||||
{ src: "/images/icon-weixin.png", alt: "weixin" },
|
||||
{ src: "/images/icon-weibo.png", alt: "weibo" },
|
||||
{ src: "/images/logo.png", alt: "logo" },
|
||||
],
|
||||
copyright: "版权声明©2001-{year} | 中国银泰投资有限公司",
|
||||
icpNumber: "京ICP备05026114号-1",
|
||||
};
|
||||
|
||||
const DEFAULT_FOOTER_EN = {
|
||||
...DEFAULT_FOOTER_ZH,
|
||||
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.",
|
||||
};
|
||||
|
||||
/**
|
||||
* Restructure global config to match the expected layout:
|
||||
|
|
@ -193,6 +165,7 @@ export function parsePageConfig(items: RawPageItem[]): {
|
|||
const zhNavItems = buildNavItems(menuItems, "ZH", parsedContentMap);
|
||||
const enNavItems = buildNavItems(menuItems, "EN", parsedContentMap);
|
||||
|
||||
|
||||
const zhConfig: Record<string, any> = {};
|
||||
const enConfig: Record<string, any> = {};
|
||||
|
||||
|
|
@ -220,12 +193,8 @@ export function parsePageConfig(items: RawPageItem[]): {
|
|||
}
|
||||
}
|
||||
|
||||
zhConfig.header = { navItems: zhNavItems };
|
||||
zhConfig.footer = { ...DEFAULT_FOOTER_ZH };
|
||||
|
||||
enConfig.header = { navItems: enNavItems };
|
||||
enConfig.footer = { ...DEFAULT_FOOTER_EN };
|
||||
|
||||
zhConfig.navItems = zhNavItems;
|
||||
enConfig.navItems = enNavItems;
|
||||
deepFallback(enConfig, zhConfig);
|
||||
|
||||
return { "zh-CN": zhConfig, "en-US": enConfig };
|
||||
|
|
|
|||