update:before animate save

This commit is contained in:
zhangjianjun 2026-03-06 16:03:03 +08:00
parent aa8358c91e
commit 1c1c68d597
22 changed files with 771 additions and 216 deletions

View File

@ -104,7 +104,7 @@ const zhCN = {
{ {
title: "银泰商业集团", title: "银泰商业集团",
content: "涵盖地标型高端商业综合体in77、景观地标型商业综合体inPARK区域型品质商业生活中心银泰城等品牌的大型商业集团是一家持续推动传统零售业创新与互联网转型融合的典范性企业。", content: "涵盖地标型高端商业综合体in77、景观地标型商业综合体inPARK区域型品质商业生活中心银泰城等品牌的大型商业集团是一家持续推动传统零售业创新与互联网转型融合的典范性企业。",
image: "/images/bg-commercial-group.png", backgroundImage: "/images/bg-commercial-group.png",
links: [ links: [
{ text: "in77", path: "/in77" }, { text: "in77", path: "/in77" },
{ text: "inPARK", path: "/inPARK" }, { text: "inPARK", path: "/inPARK" },
@ -114,7 +114,7 @@ const zhCN = {
{ {
title: "银泰基业集团", title: "银泰基业集团",
content: "银泰基业集团是银泰集团旗下核心业务板块,深耕商业地产与零售领域多年,致力于打造高品质商业空间,引领现代消费体验。集团旗下拥有银泰百货、银泰城等多个知名商业品牌,在全国多个核心城市布局,持续为消费者创造美好生活。", content: "银泰基业集团是银泰集团旗下核心业务板块,深耕商业地产与零售领域多年,致力于打造高品质商业空间,引领现代消费体验。集团旗下拥有银泰百货、银泰城等多个知名商业品牌,在全国多个核心城市布局,持续为消费者创造美好生活。",
image: "/images/bg-base-group.png", backgroundImage: "/images/bg-base-group.png",
links: [ links: [
{ text: "in77", path: "/in77" }, { text: "in77", path: "/in77" },
{ text: "inPARK", path: "/inPARK" }, { text: "inPARK", path: "/inPARK" },
@ -124,7 +124,7 @@ const zhCN = {
{ {
title: "银泰置地集团", title: "银泰置地集团",
content: "银泰置地集团是银泰集团旗下核心业务板块,深耕商业地产与零售领域多年,致力于打造高品质商业空间,引领现代消费体验。集团旗下拥有银泰百货、银泰城等多个知名商业品牌,在全国多个核心城市布局,持续为消费者创造美好生活。", content: "银泰置地集团是银泰集团旗下核心业务板块,深耕商业地产与零售领域多年,致力于打造高品质商业空间,引领现代消费体验。集团旗下拥有银泰百货、银泰城等多个知名商业品牌,在全国多个核心城市布局,持续为消费者创造美好生活。",
image: "/images/bg-realty-group.png", backgroundImage: "/images/bg-realty-group.png",
links: [ links: [
{ text: "in77", path: "/in77" }, { text: "in77", path: "/in77" },
{ text: "inPARK", path: "/inPARK" }, { text: "inPARK", path: "/inPARK" },
@ -134,7 +134,7 @@ const zhCN = {
{ {
title: "银泰投资集团", title: "银泰投资集团",
content: "银泰投资集团是银泰集团旗下核心业务板块,深耕商业地产与零售领域多年,致力于打造高品质商业空间,引领现代消费体验。集团旗下拥有银泰百货、银泰城等多个知名商业品牌,在全国多个核心城市布局,持续为消费者创造美好生活。", content: "银泰投资集团是银泰集团旗下核心业务板块,深耕商业地产与零售领域多年,致力于打造高品质商业空间,引领现代消费体验。集团旗下拥有银泰百货、银泰城等多个知名商业品牌,在全国多个核心城市布局,持续为消费者创造美好生活。",
image: "/images/bg-invest-group.png", backgroundImage: "/images/bg-invest-group.png",
links: [ links: [
{ text: "in77", path: "/in77" }, { text: "in77", path: "/in77" },
{ text: "inPARK", path: "/inPARK" }, { text: "inPARK", path: "/inPARK" },
@ -144,7 +144,7 @@ const zhCN = {
{ {
title: "瑞京资产", title: "瑞京资产",
content: "瑞京集团是银泰集团旗下核心业务板块,深耕商业地产与零售领域多年,致力于打造高品质商业空间,引领现代消费体验。集团旗下拥有银泰百货、银泰城等多个知名商业品牌,在全国多个核心城市布局,持续为消费者创造美好生活。", content: "瑞京集团是银泰集团旗下核心业务板块,深耕商业地产与零售领域多年,致力于打造高品质商业空间,引领现代消费体验。集团旗下拥有银泰百货、银泰城等多个知名商业品牌,在全国多个核心城市布局,持续为消费者创造美好生活。",
image: "/images/bg-ruijing-group.png", backgroundImage: "/images/bg-ruijing-group.png",
links: [ links: [
{ text: "in77", path: "/in77" }, { text: "in77", path: "/in77" },
{ text: "inPARK", path: "/inPARK" }, { text: "inPARK", path: "/inPARK" },
@ -287,12 +287,12 @@ const zhCN = {
items: [ items: [
{ {
title: "商业领域", title: "商业领域",
image: "/images/bg-invest-group.png", backgroundImage: "/images/bg-invest-group.png",
content: "银泰集团在商业领域有着丰富的经验和深厚的实力,致力于打造高品质的商业空间,引领现代消费体验。", content: "银泰集团在商业领域有着丰富的经验和深厚的实力,致力于打造高品质的商业空间,引领现代消费体验。",
}, },
{ {
title: "社会责任", title: "社会责任",
image: "/images/bg-invest-group.png", backgroundImage: "/images/bg-invest-group.png",
content: "银泰集团在社会责任方面有着丰富的经验和深厚的实力,致力于打造高品质的商业空间,引领现代消费体验。", content: "银泰集团在社会责任方面有着丰富的经验和深厚的实力,致力于打造高品质的商业空间,引领现代消费体验。",
}, },
] ]
@ -333,12 +333,23 @@ const zhCN = {
title: "荣誉奖项", title: "荣誉奖项",
backgroundImage: '', backgroundImage: '',
items: [ items: [
{ year: '2026年', children: ["2015年度“影响·2015中国公益100人”", "2015年度“中国社会十大推动者”"]},
{ year: '2025年', children: ["2015年度“影响·2015中国公益100人”", "2015年度“中国社会十大推动者”"]},
{ year: '2024年', children: ["2015年度“影响·2015中国公益100人”", "2015年度“中国社会十大推动者”"]},
{ year: '2023年', children: ["2015年度“影响·2015中国公益100人”", "2015年度“中国社会十大推动者”"]},
{ year: '2022年', children: ["2015年度“影响·2015中国公益100人”", "2015年度“中国社会十大推动者”"]},
{ year: '2021年', children: ["2015年度“影响·2015中国公益100人”", "2015年度“中国社会十大推动者”"]},
{ year: '2020年', children: ["2015年度“影响·2015中国公益100人”", "2015年度“中国社会十大推动者”"]}, { year: '2020年', children: ["2015年度“影响·2015中国公益100人”", "2015年度“中国社会十大推动者”"]},
{ year: '2019年', children: ["2015年度“影响·2015中国公益100人”", "2015年度“中国社会十大推动者”"]}, { year: '2019年', children: ["2015年度“影响·2015中国公益100人”", "2015年度“中国社会十大推动者”"]},
{ year: '2018年', children: ["2015年度“影响·2015中国公益100人”", "2015年度“中国社会十大推动者”"]}, { year: '2018年', children: ["2015年度“影响·2015中国公益100人”", "2015年度“中国社会十大推动者”"]},
{ year: '2017年', children: ["2015年度“影响·2015中国公益100人”", "2015年度“中国社会十大推动者”"]}, { year: '2017年', children: ["2015年度“影响·2015中国公益100人”", "2015年度“中国社会十大推动者”"]},
{ year: '2016年', children: ["2015年度“影响·2015中国公益100人”", "2015年度“中国社会十大推动者”"]}, { year: '2016年', children: ["2015年度“影响·2015中国公益100人”", "2015年度“中国社会十大推动者”"]},
{ year: '2015年', children: ["2015年度“影响·2015中国公益100人”", "2015年度“中国社会十大推动者”"]}, { year: '2015年', children: ["2015年度“影响·2015中国公益100人”", "2015年度“中国社会十大推动者”"]},
{ year: '2014年', children: ["2015年度“影响·2015中国公益100人”", "2015年度“中国社会十大推动者”"]},
{ year: '2013年', children: ["2015年度“影响·2015中国公益100人”", "2015年度“中国社会十大推动者”"]},
{ year: '2012年', children: ["2015年度“影响·2015中国公益100人”", "2015年度“中国社会十大推动者”"]},
{ year: '2011年', children: ["2015年度“影响·2015中国公益100人”", "2015年度“中国社会十大推动者”"]},
{ year: '2010年', children: ["2015年度“影响·2015中国公益100人”", "2015年度“中国社会十大推动者”"]},
], ],
}, },
}, },
@ -359,17 +370,18 @@ const zhCN = {
}, },
section2Data: { section2Data: {
tabItems: [ tabItems: [
{ label: "in77", content: "in77 内容", image: "/images/bg-overview.png", path: "/business/commercial-group/in77" }, { tabName: "in77", content: "in77 内容", sideImage: "/images/bg-overview.png", path: "/business/commercial-group/in77" },
{ label: "inPARK", content: "inPARK 内容", image: "/images/bg-overview.png", path: "/business/commercial-group/inPARK" }, { tabName: "inPARK", content: "inPARK 内容", sideImage: "/images/bg-overview.png", path: "/business/commercial-group/inPARK" },
{ label: "银泰城购物中心", content: "银泰城 内容", image: "/images/bg-overview.png", path: "/business/commercial-group/shopping-center" }, { tabName: "银泰城购物中心", content: "银泰城 内容", sideImage: "/images/bg-overview.png", path: "/business/commercial-group/shopping-center" },
], ],
backgroundImage: '/images/bg-in.png'
}, },
section3Data: { section3Data: {
tabItems: [ tabItems: [
{ label: "深耕运营", content: "全域营销 内容", image: "/images/bg-overview.png" }, { tabName: "深耕运营", content: "全域营销 内容", backgroundImage: "/images/bg-overview.png" },
{ label: "行业领先", content: "数字化运营 内容", image: "/images/bg-overview.png" }, { tabName: "行业领先", content: "数字化运营 内容", backgroundImage: "/images/bg-overview.png" },
{ label: "创新变革", content: "全球品牌合作 内容", image: "/images/bg-overview.png" }, { tabName: "创新变革", content: "全球品牌合作 内容", backgroundImage: "/images/bg-overview.png" },
{ label: "数字生态", content: "全球品牌合作 内容", image: "/images/bg-overview.png" }, { tabName: "数字生态", content: "全球品牌合作 内容", backgroundImage: "/images/bg-overview.png" },
], ],
}, },
banner: { banner: {
@ -381,6 +393,9 @@ const zhCN = {
}, },
}, },
commercialGroupDetail: { commercialGroupDetail: {
items: [
{
pathname: "in77",
banner: { banner: {
title: "in77", title: "in77",
largeContent: "地标型高端商业综合体", largeContent: "地标型高端商业综合体",
@ -388,6 +403,27 @@ const zhCN = {
showBreadcrumb: true, showBreadcrumb: true,
backgroundImage: "/images/bg-overview.png", backgroundImage: "/images/bg-overview.png",
}, },
section1Data: {
backgroundImage: "",
title: "in77",
content: "作为高端商业品牌汲取了银泰集团优质的商业资源及运营管理能力旗下项目均位于核心商业圈或国家示范步行街成为时尚零售业和新消费领域的标杆。目前有北京银泰中心in01、杭州湖滨银泰in77、北京王府井银泰in88、合肥银泰in77及成都银泰中心in99等项目。每个项目都融入“唤醒真正的自我”的理念同时亦不乏各自特色与个性。",
},
section2Data: {
backgroundImage: "/images/bg-in.png",
titleDirection: "column",
tabItems: [
{ tabName: "北京银泰中心in01", icon: '/images/bg-overview.png', contentTitle: "银泰中心1", contentSubtitle: "城市封面地标", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", sideImage: "/images/bg-overview.png" },
{ tabName: "杭州湖滨银泰in77", icon: '/images/bg-overview.png', contentTitle: "银泰中心2", contentSubtitle: "城市封面地标", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", sideImage: "/images/bg-overview.png" },
{ tabName: "北京王府井银泰in88", icon: '/images/bg-overview.png', contentTitle: "银泰中心3", contentSubtitle: "城市封面地标", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", sideImage: "/images/bg-overview.png" },
{ tabName: "成都银泰中心in99", icon: '/images/bg-overview.png', contentTitle: "银泰中心", contentSubtitle: "城市封面地标", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", sideImage: "/images/bg-overview.png" },
{ tabName: "成都银泰中心in99", icon: '/images/bg-overview.png', contentTitle: "银泰中心", contentSubtitle: "城市封面地标", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", sideImage: "/images/bg-overview.png" },
{ tabName: "成都银泰中心in99", icon: '/images/bg-overview.png', contentTitle: "银泰中心", contentSubtitle: "城市封面地标", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", sideImage: "/images/bg-overview.png" },
{ tabName: "成都银泰中心in99", icon: '/images/bg-overview.png', contentTitle: "银泰中心", contentSubtitle: "城市封面地标", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", sideImage: "/images/bg-overview.png" },
{ tabName: "成都银泰中心in99", icon: '/images/bg-overview.png', contentTitle: "银泰中心", contentSubtitle: "城市封面地标", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", sideImage: "/images/bg-overview.png" },
],
}
}
]
}, },
baseGroup: { baseGroup: {
section1Data: { section1Data: {
@ -404,11 +440,11 @@ const zhCN = {
section2Data: { section2Data: {
title: "四大区域", title: "四大区域",
cardItems: [ cardItems: [
{ title: "服务业态1", content: "服务业态1", image: "/images/bg-overview.png" }, { title: "服务业态1", content: "服务业态1", backgroundImage: "/images/bg-overview.png" },
{ title: "服务业态2", content: "服务业态2", image: "/images/bg-overview.png" }, { title: "服务业态2", content: "服务业态2", backgroundImage: "/images/bg-overview.png" },
{ title: "服务业态3", content: "服务业态3", image: "/images/bg-overview.png" }, { title: "服务业态3", content: "服务业态3", backgroundImage: "/images/bg-overview.png" },
{ title: "服务业态4", content: "服务业态3", image: "/images/bg-overview.png" }, { title: "服务业态4", content: "服务业态3", backgroundImage: "/images/bg-overview.png" },
{ title: "服务业态5", content: "服务业态3", image: "/images/bg-overview.png" }, { title: "服务业态5", content: "服务业态3", backgroundImage: "/images/bg-overview.png" },
], ],
}, },
section3Data: { section3Data: {
@ -417,7 +453,7 @@ const zhCN = {
{ {
title: "北京", title: "北京",
subtitle: "北京银泰中心", subtitle: "北京银泰中心",
image: "/images/bg-overview.png", backgroundImage: "/images/bg-overview.png",
links: [ links: [
{ text: "in01", path: "" }, { text: "in01", path: "" },
{ text: "超甲级写字楼", path: "" }, { text: "超甲级写字楼", path: "" },
@ -426,9 +462,9 @@ const zhCN = {
{ text: "柏悦居", path: "" }, { text: "柏悦居", path: "" },
], ],
}, },
{ title: "四川", subtitle: "成都银泰中心", image: "/images/bg-overview.png" }, { title: "四川", subtitle: "成都银泰中心", backgroundImage: "/images/bg-overview.png" },
{ title: "浙江", subtitle: "杭州湖滨银泰in77", image: "/images/bg-overview.png" }, { title: "浙江", subtitle: "杭州湖滨银泰in77", backgroundImage: "/images/bg-overview.png" },
{ title: "上海", subtitle: "上海中骏广场", image: "/images/bg-overview.png" }, { title: "上海", subtitle: "上海中骏广场", backgroundImage: "/images/bg-overview.png" },
], ],
}, },
section4Data: { section4Data: {
@ -447,10 +483,10 @@ const zhCN = {
section5Data: { section5Data: {
title: "业务特色", title: "业务特色",
tabItems: [ tabItems: [
{ tabName: "精细化运营", contentTitle: "精细化运营——运筹帷幄·精于心", contentText: "通过精细化管理赋能运营,稳步提升商业资产价值。关注租金的成长性和租户的良性表现,实现产品逐步升级,服务稳健提升,实现商业资产整体增值。", image: "/images/bg-overview.png" }, { tabName: "精细化运营", contentTitle: "精细化运营——运筹帷幄·精于心", contentText: "通过精细化管理赋能运营,稳步提升商业资产价值。关注租金的成长性和租户的良性表现,实现产品逐步升级,服务稳健提升,实现商业资产整体增值。", backgroundImage: "/images/bg-overview.png" },
{ tabName: "数智化管理", contentTitle: "内容标题2", contentText: "内容文本2", image: "/images/bg-overview.png" }, { tabName: "数智化管理", contentTitle: "内容标题2", contentText: "内容文本2", backgroundImage: "/images/bg-overview.png" },
{ tabName: "生态化发展", contentTitle: "内容标题2", contentText: "内容文本2", image: "/images/bg-overview.png" }, { tabName: "生态化发展", contentTitle: "内容标题2", contentText: "内容文本2", backgroundImage: "/images/bg-overview.png" },
{ tabName: "品牌化升级", contentTitle: "内容标题2", contentText: "内容文本2", image: "/images/bg-overview.png" }, { tabName: "品牌化升级", contentTitle: "内容标题2", contentText: "内容文本2", backgroundImage: "/images/bg-overview.png" },
], ],
}, },
banner: { banner: {
@ -517,19 +553,19 @@ const zhCN = {
}, },
section2Data: { section2Data: {
tabItems: [ tabItems: [
{ tabName: "银泰中心", contentTitle: "银泰中心1", contentSubtitle: "城市封面地标", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", image: "/images/bg-overview.png" }, { tabName: "银泰中心", contentTitle: "银泰中心1", contentSubtitle: "城市封面地标", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", backgroundImage: "/images/bg-overview.png" },
{ tabName: "银泰城", contentTitle: "银泰中心2", contentSubtitle: "城市封面地标", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", image: "/images/bg-overview.png" }, { tabName: "银泰城", contentTitle: "银泰中心2", contentSubtitle: "城市封面地标", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", backgroundImage: "/images/bg-overview.png" },
{ tabName: "高级酒店与公寓", contentTitle: "银泰中心3", contentSubtitle: "城市封面地标", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", image: "/images/bg-overview.png" }, { tabName: "高级酒店与公寓", contentTitle: "银泰中心3", contentSubtitle: "城市封面地标", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", backgroundImage: "/images/bg-overview.png" },
{ tabName: "文旅小镇", contentTitle: "银泰中心", contentSubtitle: "城市封面地标", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", image: "/images/bg-overview.png" }, { tabName: "文旅小镇", contentTitle: "银泰中心", contentSubtitle: "城市封面地标", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", backgroundImage: "/images/bg-overview.png" },
], ],
}, },
section3Data: { section3Data: {
title: "标杆项目", title: "标杆项目",
items: [ items: [
{ title: "杭州银泰中心", content: '位于杭州未来科技城地块与余杭区政府合作开发建设规划投资数十亿元建设总建筑面积约60万方的高端TOD城市综合体推动区域向"国际化消费中心"转型,打造百亿级商圈。', image: "/images/bg-overview.png" }, { title: "杭州银泰中心", content: '位于杭州未来科技城地块与余杭区政府合作开发建设规划投资数十亿元建设总建筑面积约60万方的高端TOD城市综合体推动区域向"国际化消费中心"转型,打造百亿级商圈。', backgroundImage: "/images/bg-overview.png" },
{ title: "丽水银泰城", content: '位于杭州未来科技城地块与余杭区政府合作开发建设规划投资数十亿元建设总建筑面积约60万方的高端TOD城市综合体推动区域向"国际化消费中心"转型,打造百亿级商圈。', image: "/images/bg-overview.png" }, { title: "丽水银泰城", content: '位于杭州未来科技城地块与余杭区政府合作开发建设规划投资数十亿元建设总建筑面积约60万方的高端TOD城市综合体推动区域向"国际化消费中心"转型,打造百亿级商圈。', backgroundImage: "/images/bg-overview.png" },
{ title: "杭州银泰喜来登大酒店", content: '位于杭州未来科技城地块与余杭区政府合作开发建设规划投资数十亿元建设总建筑面积约60万方的高端TOD城市综合体推动区域向"国际化消费中心"转型,打造百亿级商圈。', image: "/images/bg-overview.png" }, { title: "杭州银泰喜来登大酒店", content: '位于杭州未来科技城地块与余杭区政府合作开发建设规划投资数十亿元建设总建筑面积约60万方的高端TOD城市综合体推动区域向"国际化消费中心"转型,打造百亿级商圈。', backgroundImage: "/images/bg-overview.png" },
{ title: "杭州银泰仙女湖小镇", content: '位于杭州未来科技城地块与余杭区政府合作开发建设规划投资数十亿元建设总建筑面积约60万方的高端TOD城市综合体推动区域向"国际化消费中心"转型,打造百亿级商圈。', image: "/images/bg-overview.png" }, { title: "杭州银泰仙女湖小镇", content: '位于杭州未来科技城地块与余杭区政府合作开发建设规划投资数十亿元建设总建筑面积约60万方的高端TOD城市综合体推动区域向"国际化消费中心"转型,打造百亿级商圈。', backgroundImage: "/images/bg-overview.png" },
], ],
}, },
section4Data: { section4Data: {
@ -548,10 +584,10 @@ const zhCN = {
section5Data: { section5Data: {
title: "业务特色", title: "业务特色",
tabItems: [ tabItems: [
{ tabName: "精细化运营", contentTitle: "精细化运营——运筹帷幄·精于心", contentText: "通过精细化管理赋能运营,稳步提升商业资产价值。关注租金的成长性和租户的良性表现,实现产品逐步升级,服务稳健提升,实现商业资产整体增值。", image: "/images/bg-overview.png" }, { tabName: "精细化运营", contentTitle: "精细化运营——运筹帷幄·精于心", contentText: "通过精细化管理赋能运营,稳步提升商业资产价值。关注租金的成长性和租户的良性表现,实现产品逐步升级,服务稳健提升,实现商业资产整体增值。", backgroundImage: "/images/bg-overview.png" },
{ tabName: "数智化管理", contentTitle: "内容标题2", contentText: "内容文本2", image: "/images/bg-overview.png" }, { tabName: "数智化管理", contentTitle: "内容标题2", contentText: "内容文本2", backgroundImage: "/images/bg-overview.png" },
{ tabName: "生态化发展", contentTitle: "内容标题2", contentText: "内容文本2", image: "/images/bg-overview.png" }, { tabName: "生态化发展", contentTitle: "内容标题2", contentText: "内容文本2", backgroundImage: "/images/bg-overview.png" },
{ tabName: "品牌化升级", contentTitle: "内容标题2", contentText: "内容文本2", image: "/images/bg-overview.png" }, { tabName: "品牌化升级", contentTitle: "内容标题2", contentText: "内容文本2", backgroundImage: "/images/bg-overview.png" },
], ],
}, },
banner: { banner: {
@ -575,13 +611,13 @@ const zhCN = {
section2Data: { section2Data: {
title: "业务架构", title: "业务架构",
cardItems: [ cardItems: [
{ title: "不良债权收购", content: "服务业态1", image: "/images/bg-overview.png" }, { title: "不良债权收购", content: "服务业态1", backgroundImage: "/images/bg-overview.png" },
{ title: "债务重组", content: "服务业态2", image: "/images/bg-overview.png" }, { title: "债务重组", content: "服务业态2", backgroundImage: "/images/bg-overview.png" },
{ title: "投资管理", content: "服务业态3", image: "/images/bg-overview.png" }, { title: "投资管理", content: "服务业态3", backgroundImage: "/images/bg-overview.png" },
{ title: "金融服务", content: "服务业态4", image: "/images/bg-overview.png" }, { title: "金融服务", content: "服务业态4", backgroundImage: "/images/bg-overview.png" },
{ title: "个贷不良", content: "服务业态5", image: "/images/bg-overview.png" }, { title: "个贷不良", content: "服务业态5", backgroundImage: "/images/bg-overview.png" },
{ title: "企业纾困", content: "服务业态5", image: "/images/bg-overview.png" }, { title: "企业纾困", content: "服务业态5", backgroundImage: "/images/bg-overview.png" },
{ title: "问题企业流动性支持", content: "服务业态5", image: "/images/bg-overview.png" }, { title: "问题企业流动性支持", content: "服务业态5", backgroundImage: "/images/bg-overview.png" },
], ],
}, },
section3Data: { section3Data: {
@ -629,21 +665,21 @@ const zhCN = {
section2Data: { section2Data: {
title: "服务业态", title: "服务业态",
cardItems: [ cardItems: [
{ title: "服务业态1", content: "服务业态1", image: "/images/bg-overview.png" }, { title: "服务业态1", content: "服务业态1", backgroundImage: "/images/bg-overview.png" },
{ title: "服务业态2", content: "服务业态2", image: "/images/bg-overview.png" }, { title: "服务业态2", content: "服务业态2", backgroundImage: "/images/bg-overview.png" },
{ title: "服务业态3", content: "服务业态3", image: "/images/bg-overview.png" }, { title: "服务业态3", content: "服务业态3", backgroundImage: "/images/bg-overview.png" },
{ title: "服务业态4", content: "服务业态3", image: "/images/bg-overview.png" }, { title: "服务业态4", content: "服务业态3", backgroundImage: "/images/bg-overview.png" },
{ title: "服务业态5", content: "服务业态3", image: "/images/bg-overview.png" }, { title: "服务业态5", content: "服务业态3", backgroundImage: "/images/bg-overview.png" },
], ],
}, },
section3Data: { section3Data: {
title: "标杆项目", title: "标杆项目",
items: [ items: [
{ title: "北京银泰中心", image: "/images/bg-overview.png" }, { title: "北京银泰中心", backgroundImage: "/images/bg-overview.png" },
{ title: "北京银泰吉祥大厦", image: "/images/bg-overview.png" }, { title: "北京银泰吉祥大厦", backgroundImage: "/images/bg-overview.png" },
{ title: "杭州城西银泰城", image: "/images/bg-overview.png" }, { title: "杭州城西银泰城", backgroundImage: "/images/bg-overview.png" },
{ title: "杭州千岛湖银泰城", image: "/images/bg-overview.png" }, { title: "杭州千岛湖银泰城", backgroundImage: "/images/bg-overview.png" },
{ title: "桐庐银泰城", image: "/images/bg-overview.png" }, { title: "桐庐银泰城", backgroundImage: "/images/bg-overview.png" },
], ],
}, },
section4Data: { section4Data: {
@ -748,16 +784,14 @@ const zhCN = {
title: "银泰公益基金会", title: "银泰公益基金会",
content: "由银泰集团创始人兼董事长沈国军先生发起于2014年初在北京成立。银泰集团希望以此为平台以公益促进社会进步用创新公益模式立足生态环保、乡村振兴、应急救灾、公益教育等方向用实际行动体现银泰人对社会责任的坚守和担当。", content: "由银泰集团创始人兼董事长沈国军先生发起于2014年初在北京成立。银泰集团希望以此为平台以公益促进社会进步用创新公益模式立足生态环保、乡村振兴、应急救灾、公益教育等方向用实际行动体现银泰人对社会责任的坚守和担当。",
backgroundImage: "/images/Foundation-sectionbg-1.png", backgroundImage: "/images/Foundation-sectionbg-1.png",
},
section2Data: {
tabItems: [ tabItems: [
{ tabName: "生态环保", contentTitle: "生态环保", contentSubtitle: "", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", image: "/images/bg-overview.png" }, { tabName: "生态环保", contentTitle: "生态环保", contentSubtitle: "", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", sideImage: "/images/bg-overview.png" },
{ tabName: "乡村振兴", contentTitle: "银泰中心", contentSubtitle: "", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", image: "/images/bg-overview.png" }, { tabName: "乡村振兴", contentTitle: "银泰中心", contentSubtitle: "", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", sideImage: "/images/bg-overview.png" },
{ tabName: "应急救灾", contentTitle: "银泰中心", contentSubtitle: "", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", image: "/images/bg-overview.png" }, { tabName: "应急救灾", contentTitle: "银泰中心", contentSubtitle: "", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", sideImage: "/images/bg-overview.png" },
{ tabName: "公益教育", contentTitle: "银泰中心", contentSubtitle: "", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", image: "/images/bg-overview.png" }, { tabName: "公益教育", contentTitle: "银泰中心", contentSubtitle: "", contentText: "北京银泰中心是银泰置地集团在北京的核心项目,是集高端购物中心、酒店、公寓、超甲级写字楼等业态于一体的综合性商业地产项目。", sideImage: "/images/bg-overview.png" },
], ],
}, },
section3Data: { section2Data: {
title: "公益传播", title: "公益传播",
items: Array(4).fill(null).map((_, i) => ({ items: Array(4).fill(null).map((_, i) => ({
title: `公益传播${i + 1}`, title: `公益传播${i + 1}`,
@ -766,7 +800,7 @@ const zhCN = {
link: "", link: "",
})), })),
}, },
section4Data: { section3Data: {
title: "信息公开", title: "信息公开",
tabItems: [ tabItems: [
{ tabName: "规章制度", fileItems: Array(15).fill(null).map(() => ({ fileName: "规章制度1.pdf", link: "" })) }, { tabName: "规章制度", fileItems: Array(15).fill(null).map(() => ({ fileName: "规章制度1.pdf", link: "" })) },
@ -777,7 +811,7 @@ const zhCN = {
], ],
backgroundImage: "/images/bg-overview.png", backgroundImage: "/images/bg-overview.png",
}, },
section5Data: { section4Data: {
title: "公益伙伴", title: "公益伙伴",
items: Array(6).fill(null).map(() => ({ logo: "/images/bg-overview.png" })), items: Array(6).fill(null).map(() => ({ logo: "/images/bg-overview.png" })),
}, },

View File

@ -0,0 +1,87 @@
.scrollContainer {
width: 100%;
overflow-x: auto;
overflow-y: auto;
}
.content {
position: relative;
flex-shrink: 0;
}
.svg {
width: 100%;
height: 100%;
display: block;
}
.bgPath {
stroke: #CACED9;
}
.mainPath {
stroke: #CACED9;
stroke-linecap: round;
stroke-linejoin: round;
}
.dotOuter {
fill: #14355c;
stroke: #2d4a7c;
stroke-width: 2;
}
.dotInner {
fill: rgba(255, 255, 255, 0.9);
}
.labelsOverlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
.labelBlock {
position: absolute;
pointer-events: auto;
min-width: 160px;
max-width: 550px;
min-height: 200px;
padding: 0 20px;
}
.labelBlock.top {
margin-bottom: 4px;
}
.labelBlock.bottom {
margin-top: 4px;
display: flex;
flex-direction: column;
justify-content: flex-end;
}
.labelYear {
font-size: 1.125rem;
font-weight: 600;
color: #14355c;
margin-bottom: 6px;
line-height: 1.3;
}
.labelList {
margin: 0;
font-size: 0.875rem;
line-height: 1.6;
color: #333;
list-style: disc;
}
.labelList li {
margin-bottom: 4px;
list-style: disc;
margin-left: 1.25em;
}

View File

@ -0,0 +1,215 @@
import styles from "./index.module.css";
const PEAK_TO_PEAK = 600;
const PEAK_TO_VALLEY = 125;
const AMPLITUDE = PEAK_TO_VALLEY / 2;
/** 正弦峰 xsin(2πx/600)=1 → x=150+600n */
const PEAK_X_OFFSET = PEAK_TO_PEAK / 4;
/** 正弦谷 xsin(2πx/600)=-1 → x=450+600n */
const VALLEY_X_OFFSET = (3 * PEAK_TO_PEAK) / 4;
const LINE_HEIGHT = 200;
/** 扩大 viewBox 以容纳上方垂直线,避免 rect 被裁剪 */
const VIEWBOX_PADDING = 170;
export type TimelineItem = {
year: string;
children: string[];
};
type Props = {
items: TimelineItem[];
height?: number;
};
function generateSinePath(
width: number,
height: number,
amplitude: number
): string {
const centerY = height / 2;
const step = 4;
const parts: string[] = [];
for (let x = 0; x <= width; x += step) {
const y = centerY - amplitude * Math.sin((2 * Math.PI * x) / PEAK_TO_PEAK);
parts.push(`${x},${y}`);
}
return `M ${parts.join(" L ")}`;
}
/** 余弦曲线:正弦峰时余弦谷,相位差 π/2即 cos(θ+π/2) = -sin(θ) */
function generateCosinePath(
width: number,
height: number,
amplitude: number
): string {
const centerY = height / 2;
const step = 4;
const parts: string[] = [];
for (let x = 0; x <= width; x += step) {
const y =
centerY -
amplitude * Math.cos((2 * Math.PI * x) / PEAK_TO_PEAK + Math.PI / 2);
parts.push(`${x},${y}`);
}
return `M ${parts.join(" L ")}`;
}
function computePeakValleyPoints(
items: TimelineItem[],
height: number
): Array<{
x: number;
y: number;
lineTopY: number;
side: "top" | "bottom";
item: TimelineItem;
}> {
if (items.length === 0) return [];
const centerY = height / 2;
return items.map((item, i) => {
const isPeak = i % 2 === 0;
const cycleIndex = Math.floor(i / 2);
const x = isPeak
? PEAK_X_OFFSET + cycleIndex * PEAK_TO_PEAK
: VALLEY_X_OFFSET + cycleIndex * PEAK_TO_PEAK;
const y =
centerY - AMPLITUDE * Math.sin((2 * Math.PI * x) / PEAK_TO_PEAK);
const lineTopY = isPeak ? y - LINE_HEIGHT : y;
return {
x,
y,
lineTopY,
side: isPeak ? "top" : "bottom",
item,
};
});
}
/** 根据 item 数量计算所需内容宽度 */
function computeContentWidth(items: TimelineItem[]): number {
if (items.length === 0) return 0;
const lastIndex = items.length - 1;
const isPeak = lastIndex % 2 === 0;
const cycleIndex = Math.floor(lastIndex / 2);
const lastX = isPeak
? PEAK_X_OFFSET + cycleIndex * PEAK_TO_PEAK
: VALLEY_X_OFFSET + cycleIndex * PEAK_TO_PEAK;
return lastX + 280;
}
export default function SineWaveTimeline({ items, height: propHeight = 400 }: Props) {
if (!items?.length) return null;
const height = propHeight ?? 400;
const contentWidth = computeContentWidth(items);
const points = computePeakValleyPoints(items, height);
const expandedHeight = height + 2 * VIEWBOX_PADDING;
const mainPathD = generateSinePath(contentWidth, height, AMPLITUDE);
const bgPathD = generateCosinePath(contentWidth, height, AMPLITUDE * 0.9);
return (
<div className={styles.scrollContainer}>
<div
className={styles.content}
style={{ width: contentWidth, height: `${expandedHeight}px` }}
>
<svg
className={styles.svg}
viewBox={`0 ${-VIEWBOX_PADDING} ${contentWidth} ${expandedHeight}`}
preserveAspectRatio="xMidYMid meet"
>
<defs>
<linearGradient
id="connectorLineGrad"
x1="0"
y1="0"
x2="0"
y2="1"
gradientUnits="objectBoundingBox"
>
<stop offset="0" stopColor="#14355C" />
<stop offset="0.9929" stopColor="rgba(20,53,92,0)" />
</linearGradient>
<linearGradient
id="connectorLineGradValley"
x1="0"
y1="0"
x2="0"
y2="1"
gradientUnits="objectBoundingBox"
>
<stop offset="0" stopColor="rgba(20,53,92,0)" />
<stop offset="0.9929" stopColor="#14355C" />
</linearGradient>
</defs>
{/* 背景余弦 - 正弦峰时余弦谷 */}
<path
d={bgPathD}
className={styles.bgPath}
fill="none"
strokeWidth="1"
/>
{/* 主正弦 */}
<path
d={mainPathD}
className={styles.mainPath}
fill="none"
strokeWidth="2"
/>
{/* 峰谷圆点与垂直线 */}
{points.map((point, i) => (
<g key={i}>
<rect
x={point.x - 1}
y={point.lineTopY}
width={2}
height={LINE_HEIGHT}
fill={
point.side === "top"
? "url(#connectorLineGrad)"
: "url(#connectorLineGradValley)"
}
/>
<circle
cx={point.x}
cy={point.y}
r="10"
className={styles.dotOuter}
/>
<circle
cx={point.x}
cy={point.y}
r="5"
className={styles.dotInner}
/>
</g>
))}
</svg>
{/* Item 文本块叠加层 */}
<div className={styles.labelsOverlay}>
{points.map((point, i) => (
<div
key={i}
className={`${styles.labelBlock} ${styles[point.side]}`}
style={{
left: `${((point.x + 14) / contentWidth) * 100}%`,
top: `${((point.lineTopY + VIEWBOX_PADDING) / expandedHeight) * 100}%`,
}}
>
<div className={styles.labelYear}>{point.item.year}</div>
<ul className={styles.labelList}>
{point.item.children?.map((child, j) => (
<li key={j}>{child}</li>
))}
</ul>
</div>
))}
</div>
</div>
</div>
);
}

View File

@ -29,7 +29,7 @@ export default function Banner({
desc, desc,
content, content,
largedesc, largedesc,
showBreadcrumb, showBreadcrumb = true,
titleSize = "large", titleSize = "large",
backgroundImage, backgroundImage,
}: Props) { }: Props) {

View File

@ -9,15 +9,18 @@ type Data = {
tabName: string; tabName: string;
contentTitle: string; contentTitle: string;
contentText: string; contentText: string;
image: string; /** 以 mockData 为准 */
backgroundImage?: string;
image?: string;
}[] }[]
} }
export default function BottomTabsSection({ data }: { data: Data }) { export default function BottomTabsSection({ data }: { data: Data }) {
const [activeIndex, setActiveIndex] = useState(0); const [activeIndex, setActiveIndex] = useState(0);
const bgImg = data.tabItems[activeIndex]?.backgroundImage ?? data.tabItems[activeIndex]?.image ?? "";
return ( return (
<div className={styles.bottomTabsSection} style={{ backgroundImage: `url(${data.tabItems[activeIndex].image})` }}> <div className={styles.bottomTabsSection} style={{ backgroundImage: bgImg ? `url(${bgImg})` : undefined }}>
<SectionTitle title={data.title} color="#fff" /> <SectionTitle title={data.title} color="#fff" />
<div className={styles.bottomTabsSectionContent}> <div className={styles.bottomTabsSectionContent}>
<div className={styles.bottomTabsSectionContentContent}> <div className={styles.bottomTabsSectionContentContent}>

View File

@ -15,7 +15,9 @@ type Data = {
text: string; text: string;
path: string; path: string;
}[]; }[];
image: string; /** 以 mockData 为准,优先使用 backgroundImage */
backgroundImage?: string;
image?: string;
}[]; }[];
} }
@ -34,7 +36,7 @@ export default function RowAccordion({ data, placement='bottom' }: Props) {
key={index} key={index}
className={styles.rowAccordionBgLayer} className={styles.rowAccordionBgLayer}
style={{ style={{
backgroundImage: `url(${item.image}), ${FALLBACK_GRADIENT}`, backgroundImage: `url(${item.backgroundImage ?? item.image ?? ""}), ${FALLBACK_GRADIENT}`,
opacity: activeIndex === index ? 1 : 0, opacity: activeIndex === index ? 1 : 0,
}} }}
/> />

View File

@ -11,7 +11,9 @@ type Data = {
title: string; title: string;
desc?: string; desc?: string;
content?: string; content?: string;
image: string; /** 以 mockData 为准,优先使用 backgroundImage */
backgroundImage?: string;
image?: string;
}[]; }[];
} }
@ -45,7 +47,7 @@ export default function SwiperCardSection({ data }: { data: Data }) {
{data.cardItems.map((item) => ( {data.cardItems.map((item) => (
<SwiperSlide key={item.title}> <SwiperSlide key={item.title}>
<div className={styles.swiperCardItem}> <div className={styles.swiperCardItem}>
<img src={item.image} alt={item.title} /> <img src={item.backgroundImage ?? item.image ?? ""} alt={item.title} />
<div className={styles.swiperMask}></div> <div className={styles.swiperMask}></div>
<div className={styles.swiperContent}> <div className={styles.swiperContent}>
<div className={styles.swiperTitle}> <div className={styles.swiperTitle}>

View File

@ -1,48 +1,149 @@
import { useState } from 'react'; import { useRef, useEffect, useState, useCallback } from 'react';
import { LeftOutlined, RightOutlined } from '@ant-design/icons';
import styles from './index.module.css'; import styles from './index.module.css';
type Data = { type Data = {
tabItems: { tabItems: {
icon?: string; icon?: string;
tabName: string; tabName?: string;
contentTitle: string; contentTitle?: string;
contentSubtitle: string; contentSubtitle?: string;
contentText: string; contentText?: string;
image: string; content?: string;
}[] /** 以 mockData 为准tabItems 可能使用 sideImage 或 backgroundImage */
sideImage?: string;
path?: string;
}[],
backgroundImage?: string;
titleDirection?: 'row' | 'column';
className?: string;
} }
export default function TopTabs({ data }: { data: Data }) { export default function TopTabs({ data, activeIndex, setActiveIndex, className }: { data: Data, activeIndex: number, setActiveIndex: (index: number) => void, className?: string }) {
const [activeIndex, setActiveIndex] = useState(0); const containerRef = useRef<HTMLDivElement>(null);
const scrollRef = useRef<HTMLDivElement>(null);
const [indicatorStyle, setIndicatorStyle] = useState<{ left: number; width: number }>({ left: 0, width: 0 });
const [canScrollLeft, setCanScrollLeft] = useState(false);
const [canScrollRight, setCanScrollRight] = useState(false);
const [shouldCenter, setShouldCenter] = useState(true);
const updateIndicatorPosition = useCallback(() => {
const scrollEl = scrollRef.current;
const activeTab = activeIndex < data.tabItems.length
? (scrollEl?.children[activeIndex] as HTMLElement)
: null;
if (!scrollEl || !activeTab) return;
const container = containerRef.current;
if (!container) return;
const containerRect = container.getBoundingClientRect();
const scrollRect = scrollEl.getBoundingClientRect();
const tabRect = activeTab.getBoundingClientRect();
const scrollLeft = scrollEl.scrollLeft;
const tabOffsetLeft = activeTab.offsetLeft;
const left = scrollRect.left - containerRect.left + tabOffsetLeft - scrollLeft;
const width = tabRect.width;
setIndicatorStyle({ left, width });
}, [activeIndex, data.tabItems.length]);
const updateScrollState = useCallback(() => {
const scrollEl = scrollRef.current;
if (!scrollEl) return;
const { scrollLeft, clientWidth, scrollWidth } = scrollEl;
setCanScrollLeft(scrollLeft > 0);
setCanScrollRight(scrollLeft + clientWidth < scrollWidth - 1);
setShouldCenter(scrollWidth <= clientWidth);
}, []);
const handleScrollLeft = () => {
scrollRef.current?.scrollBy({ left: -200, behavior: 'smooth' });
};
const handleScrollRight = () => {
scrollRef.current?.scrollBy({ left: 200, behavior: 'smooth' });
};
useEffect(() => {
const scrollEl = scrollRef.current;
const handleScroll = () => {
updateIndicatorPosition();
updateScrollState();
};
const rafId = requestAnimationFrame(() => {
requestAnimationFrame(() => {
updateIndicatorPosition();
updateScrollState();
});
});
if (!scrollEl) return () => cancelAnimationFrame(rafId);
scrollEl.addEventListener('scroll', handleScroll);
const resizeObserver = new ResizeObserver(() => {
updateIndicatorPosition();
updateScrollState();
});
resizeObserver.observe(scrollEl);
return () => {
cancelAnimationFrame(rafId);
scrollEl.removeEventListener('scroll', handleScroll);
resizeObserver.disconnect();
};
}, [activeIndex, data.tabItems.length, updateIndicatorPosition, updateScrollState]);
return ( return (
<div> <div className={className}>
<div className={styles.topTabsTabs}> <div ref={containerRef} className={styles.topTabsTabs}>
{canScrollLeft && (
<button
type="button"
className={`${styles.topTabsNavBtn} ${styles.topTabsNavBtnLeft}`}
onClick={handleScrollLeft}
aria-label="向左滚动"
>
<LeftOutlined />
</button>
)}
<div
ref={scrollRef}
className={`${styles.topTabsTabsScroll} ${shouldCenter ? styles.topTabsTabsScrollCenter : ''}`}
>
{data.tabItems.map((item, index) => ( {data.tabItems.map((item, index) => (
<div key={index} className={`${styles.topTabsTabItem} ${activeIndex === index ? styles.active : ''}`} onClick={() => setActiveIndex(index)}> <div
key={index}
className={`${styles.topTabsTabItem} ${activeIndex === index ? styles.active : ''}`}
onClick={() => setActiveIndex(index)}
>
<span>{item.tabName}</span> <span>{item.tabName}</span>
</div> </div>
))} ))}
</div> </div>
<div className={styles.topTabsContent}> {canScrollRight && (
<div className={styles.topTabsContentLeft}> <button
<div className={styles.topTabsContentLeftHead}> type="button"
{ className={`${styles.topTabsNavBtn} ${styles.topTabsNavBtnRight}`}
data.tabItems[activeIndex].icon && ( onClick={handleScrollRight}
<img src={data.tabItems[activeIndex].icon} alt="" style={{ width: '100px', height: '100px' }} /> aria-label="向右滚动"
) >
} <RightOutlined />
<div className={styles.topTabsContentLeftTitle}> </button>
<div className={styles.topTabsContentLeftTitleMain}>{data.tabItems[activeIndex].contentTitle}</div> )}
<div className={styles.topTabsContentLeftTitleSub}>{data.tabItems[activeIndex].contentSubtitle}</div> <div
</div> className={styles.topTabsBottomLine}
</div> style={{
<p className={styles.topTabsContentLeftDesc}> left: indicatorStyle.left,
{data.tabItems[activeIndex].contentText} width: indicatorStyle.width,
</p> }}
</div> />
<div className={styles.topTabsContentRight}> </div>
<img src={data.tabItems[activeIndex].image} alt="" /> </div>
</div> );
</div>
</div>
)
} }

View File

@ -4,30 +4,90 @@
min-height: 100vh; min-height: 100vh;
background-size: cover; background-size: cover;
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: repeat;
} }
.topTabsTabs { .topTabsTabs {
height: 60px; position: relative;
display: flex; /* height: 60px; */
flex-direction: row;
justify-content: center;
justify-content: space-between;
font-weight: 400; font-weight: 400;
font-size: 24px; font-size: 24px;
line-height: 34px; line-height: 34px;
border-bottom: 1px solid #D5D8DC; border-bottom: 1px solid #D5D8DC;
padding: 0 260px; width: 100%;
overflow: hidden;
}
.topTabsNavBtn {
position: absolute;
top: 50%;
transform: translateY(-50%);
z-index: 1;
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
border: none;
background: #fff;
color: #14355C;
cursor: pointer;
border-radius: 50%;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
transition: background 0.2s, color 0.2s;
}
.topTabsNavBtn:hover {
background: #f0f2f5;
color: #14355C;
}
.topTabsNavBtnLeft {
left: 0px;
}
.topTabsNavBtnRight {
right: 0px;
}
.topTabsTabsScroll {
position: relative;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
gap: 130px;
height: 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
/* 隐藏滚动条 */
scrollbar-width: none;
-ms-overflow-style: none;
&::-webkit-scrollbar {
display: none;
}
}
.topTabsTabsScrollCenter {
justify-content: center;
}
.topTabsBottomLine {
position: absolute;
bottom: 0;
height: 2px;
background: #000000;
transition: left 0.25s ease, width 0.25s ease;
} }
.topTabsTabItem { .topTabsTabItem {
height: 60px; height: 90px;
line-height: 90px;
flex-shrink: 0;
cursor: pointer; cursor: pointer;
color: #222222; color: #222222;
} }
.topTabsTabItem.active { .topTabsTabItem.active {
border-bottom: 2px solid #000000;
color: #14355C; color: #14355C;
} }
@ -72,6 +132,12 @@
text-transform: none; text-transform: none;
} }
} }
.columnCenter {
flex-direction: column;
align-items: flex-start;
justify-content: center;
}
} }
.topTabsContentLeftDesc { .topTabsContentLeftDesc {

View File

@ -5,18 +5,45 @@ import TopTabs from './TopTabs';
type Data = { type Data = {
tabItems: { tabItems: {
icon?: string; icon?: string;
tabName: string; tabName?: string;
contentTitle: string; contentTitle?: string;
contentSubtitle: string; contentSubtitle?: string;
contentText: string; contentText?: string;
image: string; content?: string;
/** 以 mockData 为准 */
sideImage?: string;
path?: string;
}[] }[]
backgroundImage?: string;
titleDirection?: 'row' | 'column';
} }
export default function TopTabsSection({ data }: { data: Data }) { export default function TopTabsSection({ data, className }: { data: Data, className?: string }) {
const [activeIndex, setActiveIndex] = useState(0);
return ( return (
<section className={styles.topTabsSection} style={{ backgroundImage: `url(/images/TopTabsSection-background.png)` }}> <section className={`${styles.topTabsSection} ${className}`} style={{ backgroundImage: `url(${data.backgroundImage})` }}>
<TopTabs data={data} /> <TopTabs data={data} activeIndex={activeIndex} setActiveIndex={setActiveIndex} />
<div className={styles.topTabsContent}>
<div className={styles.topTabsContentLeft}>
<div className={styles.topTabsContentLeftHead}>
{
data.tabItems[activeIndex].icon && (
<img src={data.tabItems[activeIndex].icon} alt="" style={{ width: '100px', height: '100px' }} />
)
}
<div className={`${styles.topTabsContentLeftTitle} ${data.titleDirection === 'column' ? styles.columnCenter : ''}`}>
<div className={styles.topTabsContentLeftTitleMain}>{data.tabItems[activeIndex].contentTitle}</div>
<div className={styles.topTabsContentLeftTitleSub}>{data.tabItems[activeIndex].contentSubtitle}</div>
</div>
</div>
<p className={styles.topTabsContentLeftDesc}>
{data.tabItems[activeIndex].contentText ?? data.tabItems[activeIndex].content}
</p>
</div>
<div className={styles.topTabsContentRight}>
<img src={data.tabItems[activeIndex].sideImage} alt="side-image" />
</div>
</div>
</section> </section>
) )
} }

View File

@ -106,18 +106,18 @@ export default function Header() {
</div> </div>
</div> </div>
{showDropPanel && activePanelItem.length > 0 && <DropPanel items={activePanelItem} left={hoverElLeft} />} {showDropPanel && activePanelItem.length > 0 && <DropPanel items={activePanelItem} left={hoverElLeft} onLinkClick={() => setShowDropPanel(false)} />}
</header> </header>
); );
} }
function DropPanel({ items, left }: { items: NavChild[]; left: number }) { function DropPanel({ items, left, onLinkClick }: { items: NavChild[]; left: number, onLinkClick: () => void }) {
return ( return (
<div id="drop-panel" className={styles.dropPanel} style={{ paddingLeft: left, }}> <div id="drop-panel" className={styles.dropPanel} style={{ paddingLeft: left, }}>
<div className={styles.dropPanelContent}> <div className={styles.dropPanelContent}>
{items.map((item) => ( {items.map((item) => (
<div key={item.path} className={styles.dropPanelItem}> <div key={item.path} className={styles.dropPanelItem}>
<Link to={item.path} className={styles.dropPanelLink}> <Link to={item.path} className={styles.dropPanelLink} onClick={onLinkClick}>
{item.label} {item.label}
</Link> </Link>
</div> </div>

View File

@ -171,6 +171,24 @@
} }
} }
.section4Section {
padding-top: 100px;
.section4Title {
font-weight: 700;
font-size: 40px;
color: #222222;
line-height: 50px;
text-align: center;
}
.timelineWrapper {
width: 100%;
overflow: auto;
}
}
@media (max-width: 768px) { @media (max-width: 768px) {
.section { .section {
padding: 2rem 1rem; padding: 2rem 1rem;
@ -196,4 +214,7 @@
padding-top: 1rem; padding-top: 1rem;
padding-right: 0; padding-right: 0;
} }
.timelineWrapper {
}
} }

View File

@ -3,6 +3,7 @@ import styles from "./Founder.module.css";
import ParagraphSection from "@/components/layout/ParagraphSection"; import ParagraphSection from "@/components/layout/ParagraphSection";
import { useStore } from "@/store"; import { useStore } from "@/store";
import Section from "@/components/layout/Section"; import Section from "@/components/layout/Section";
import SineWaveTimeline from "@/components/SineWaveTimeline";
export default function AboutFounder() { export default function AboutFounder() {
const appConfig = useStore((s) => s.appConfig); const appConfig = useStore((s) => s.appConfig);
@ -31,7 +32,7 @@ export default function AboutFounder() {
<div className={styles.images}> <div className={styles.images}>
{section1Data.items?.map((item, index) => ( {section1Data.items?.map((item, index) => (
<div className={styles.imageItem} key={item.title}> <div className={styles.imageItem} key={item.title}>
<img src={item.image} alt={item.title} /> <img src={item.backgroundImage} alt={item.title} />
<div className={styles.imageMask} /> <div className={styles.imageMask} />
<div className={styles.imageOverlay}> <div className={styles.imageOverlay}>
<div className={styles.imageOverlayTitle}> <div className={styles.imageOverlayTitle}>
@ -68,7 +69,8 @@ export default function AboutFounder() {
)} )}
{/* 社会职务 */} {/* 社会职务 */}
<Section title={section3Data?.title ?? ""} titleColor="#fff" background={section3Data?.backgroundImage ?? ""}> {section3Data && (
<Section title={section3Data?.title} titleColor="#fff" background={section3Data?.backgroundImage}>
<div className={styles.section3Content}> <div className={styles.section3Content}>
{Array.from({ {Array.from({
length: Math.max(0, ...(section3Data?.columns?.map((c) => c.length) ?? [0])), length: Math.max(0, ...(section3Data?.columns?.map((c) => c.length) ?? [0])),
@ -81,11 +83,15 @@ export default function AboutFounder() {
)} )}
</div> </div>
</Section> </Section>
)}
{/* 荣誉奖项 */} {section4Data && (
<Section title={section4Data?.title} background={section4Data?.backgroundImage ?? ""}> <section className={styles.section4Section} style={{ backgroundImage: section4Data?.backgroundImage ? `url(${section4Data?.backgroundImage})` : undefined }}>
<div className={styles.section4Title}>{section4Data?.title}</div>
</Section> <div className={styles.timelineWrapper}>
<SineWaveTimeline items={section4Data?.items ?? []} />
</div>
</section>)}
</div> </div>
); );
} }

View File

@ -22,10 +22,10 @@ export default function BaseGroup() {
const swiperCardData = section2Data const swiperCardData = section2Data
? { ? {
title: section2Data.title, title: section2Data.title,
cardItems: section2Data.cardItems?.map((c: { title: string; content: string; image: string }) => ({ cardItems: section2Data.cardItems?.map((c: { title: string; content: string; backgroundImage?: string }) => ({
title: c.title, title: c.title,
content: c.content, content: c.content,
image: c.image, backgroundImage: c.backgroundImage,
})) ?? [], })) ?? [],
} }
: null; : null;

View File

@ -35,8 +35,8 @@
background-size: cover; background-size: cover;
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
padding: 100px 0 !important;
} }
.twoColSection.reverse { .twoColSection.reverse {
flex-direction: row-reverse; flex-direction: row-reverse;
} }
@ -45,11 +45,7 @@
height: 4.125rem; height: 4.125rem;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: center;
gap: 8.125rem;
border-bottom: 1px solid #D5D8DC;
margin: 0 16.25rem; margin: 0 16.25rem;
margin-bottom: 3.75rem;
} }
.twoColSectionTab { .twoColSectionTab {
@ -66,6 +62,7 @@
.twoColSectionContent { .twoColSectionContent {
display: grid; display: grid;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
margin-top: 60px;
} }
.twoColImage { .twoColImage {

View File

@ -1,9 +1,11 @@
import { useState } from "react"; import { useState } from "react";
import { Link } from "react-router-dom";
import { useStore } from "@/store";
import styles from "./CommercialGroup.module.css"; import styles from "./CommercialGroup.module.css";
import Banner from "@/components/Banner"; import Banner from "@/components/Banner";
import { Link } from "react-router-dom";
import ParagraphSection from "@/components/layout/ParagraphSection"; import ParagraphSection from "@/components/layout/ParagraphSection";
import { useStore } from "@/store"; import Section from "@/components/layout/Section";
import TopTabs from "@/components/layout/TopTabsSection/TopTabs";
const FALLBACK_GRADIENT = "linear-gradient(135deg, #1a2a4a 0%, #2d4a7c 100%)"; const FALLBACK_GRADIENT = "linear-gradient(135deg, #1a2a4a 0%, #2d4a7c 100%)";
@ -23,8 +25,8 @@ export default function BusinessCommercialGroup() {
const banner = data.banner; const banner = data.banner;
const section1Data = data.section1Data; const section1Data = data.section1Data;
const tabItems = data.section2Data?.tabItems ?? []; const section2Data = data.section2Data;
const featuresTabItems = data.section3Data?.tabItems ?? []; const section3Data = data.section3Data;
return ( return (
<div> <div>
@ -38,28 +40,18 @@ export default function BusinessCommercialGroup() {
{section1Data && <ParagraphSection data={section1Data} />} {section1Data && <ParagraphSection data={section1Data} />}
<section <Section
background={section2Data.backgroundImage }
className={styles.twoColSection} className={styles.twoColSection}
style={{ backgroundImage: "url(/images/bg-in.png)" }}
> >
<div className={styles.twoColSectionTabs}> <TopTabs className={styles.twoColSectionTabs} data={section2Data} activeIndex={activeTabIndex} setActiveIndex={setActiveTabIndex} />
{tabItems.map((item: { label: string }, i: number) => (
<div
key={i}
className={`${styles.twoColSectionTab} ${activeTabIndex === i ? styles.active : ""}`}
onClick={() => setActiveTabIndex(i)}
>
<span>{item.label}</span>
</div>
))}
</div>
<div className={styles.twoColSectionContent}> <div className={styles.twoColSectionContent}>
<div className={styles.twoColImage}> <div className={styles.twoColImage}>
{in77ImgError ? ( {in77ImgError ? (
<PlaceholderImage /> <PlaceholderImage />
) : ( ) : (
<img <img
src={tabItems[activeTabIndex]?.image} src={section2Data.tabItems[activeTabIndex]?.sideImage as string}
alt="" alt=""
onError={() => setIn77ImgError(true)} onError={() => setIn77ImgError(true)}
style={{ width: "100%", height: "800px" }} style={{ width: "100%", height: "800px" }}
@ -67,16 +59,16 @@ export default function BusinessCommercialGroup() {
)} )}
</div> </div>
<div className={styles.twoColText}> <div className={styles.twoColText}>
<p className={styles.twoColDesc}>{tabItems[activeTabIndex]?.content}</p> <p className={styles.twoColDesc}>{section2Data.tabItems[activeTabIndex]?.content}</p>
<Link <Link
to={tabItems[activeTabIndex]?.path ?? "#"} to={section2Data.tabItems[activeTabIndex]?.path ?? "#"}
className={styles.btnPrimary} className={styles.btnPrimary}
> >
</Link> </Link>
</div> </div>
</div> </div>
</section> </Section>
<section <section
className={styles.featuresHero} className={styles.featuresHero}
@ -85,16 +77,16 @@ export default function BusinessCommercialGroup() {
}} }}
> >
<div className={styles.featuresHeroContent}> <div className={styles.featuresHeroContent}>
<div>{featuresTabItems[activeFeaturesTabIndex]?.content}</div> <div>{section3Data.tabItems[activeFeaturesTabIndex]?.content}</div>
</div> </div>
<div className={styles.featuresHeroTabs}> <div className={styles.featuresHeroTabs}>
{featuresTabItems.map((item: { label: string }, i: number) => ( {section3Data.tabItems.map((item: { tabName: string }, i: number) => (
<div <div
key={i} key={i}
className={`${styles.featuresHeroTab} ${activeFeaturesTabIndex === i ? styles.active : ""}`} className={`${styles.featuresHeroTab} ${activeFeaturesTabIndex === i ? styles.active : ""}`}
onClick={() => setActiveFeaturesTabIndex(i)} onClick={() => setActiveFeaturesTabIndex(i)}
> >
<span>{item.label}</span> <span>{item.tabName}</span>
</div> </div>
))} ))}
</div> </div>

View File

@ -1,10 +1,15 @@
import Banner, { type BannerConfig } from "@/components/Banner"; import Banner, { type BannerConfig } from "@/components/Banner";
import { useStore } from "@/store"; import { useStore } from "@/store";
import styles from "./CommercialGroupDetail.module.css"; import styles from "./CommercialGroupDetail.module.css";
import ParagraphSection from "@/components/layout/ParagraphSection";
import { useParams } from "react-router-dom";
import TopTabsSection from "@/components/layout/TopTabsSection";
export default function BusinessCommercialGroupDetail() { export default function BusinessCommercialGroupDetail() {
const appConfig = useStore((s) => s.appConfig); const appConfig = useStore((s) => s.appConfig);
const data = appConfig?.business?.commercialGroupDetail; const allData = appConfig?.business?.commercialGroupDetail;
const params = useParams()
const detailType = params.detailType as string
const data = allData?.items.find((item: any) => item.pathname === detailType)
const banner = data?.banner; const banner = data?.banner;
if (!data) return null; if (!data) return null;
@ -19,11 +24,9 @@ export default function BusinessCommercialGroupDetail() {
backgroundImage={banner?.backgroundImage ?? "/images/bg-commercial-group.png"} backgroundImage={banner?.backgroundImage ?? "/images/bg-commercial-group.png"}
/> />
<section className={styles.twoColSection}> <ParagraphSection data={data.section1Data}></ParagraphSection>
<p>
in77 <TopTabsSection data={data.section2Data as any} />
</p>
</section>
</div> </div>
); );
} }

View File

@ -25,10 +25,10 @@ export default function RealtyGroup() {
const rowAccordionData = section3Data const rowAccordionData = section3Data
? { ? {
title: section3Data.title, title: section3Data.title,
items: section3Data.items?.map((i: { title: string; content?: string; image: string }) => ({ items: section3Data.items?.map((i: { title: string; content?: string; backgroundImage?: string }) => ({
title: i.title, title: i.title,
content: i.content, content: i.content,
image: i.image, backgroundImage: i.backgroundImage,
})) ?? [], })) ?? [],
} }
: null; : null;

View File

@ -22,10 +22,10 @@ export default function RuijingGroup() {
const swiperCardData = section2Data const swiperCardData = section2Data
? { ? {
title: section2Data.title, title: section2Data.title,
cardItems: section2Data.cardItems?.map((c: { title: string; content: string; image: string }) => ({ cardItems: section2Data.cardItems?.map((c: { title: string; content: string; backgroundImage?: string }) => ({
title: c.title, title: c.title,
content: c.content, content: c.content,
image: c.image, backgroundImage: c.backgroundImage,
})) ?? [], })) ?? [],
} }
: null; : null;

View File

@ -20,10 +20,10 @@ export default function PropertyService() {
const swiperCardData = section2Data const swiperCardData = section2Data
? { ? {
title: section2Data.title, title: section2Data.title,
cardItems: section2Data.cardItems?.map((c: { title: string; content: string; image: string }) => ({ cardItems: section2Data.cardItems?.map((c: { title: string; content: string; backgroundImage?: string }) => ({
title: c.title, title: c.title,
content: c.content, content: c.content,
image: c.image, backgroundImage: c.backgroundImage,
})) ?? [], })) ?? [],
} }
: null; : null;
@ -31,9 +31,9 @@ export default function PropertyService() {
const rowAccordionData = section3Data const rowAccordionData = section3Data
? { ? {
title: section3Data.title, title: section3Data.title,
items: section3Data.items?.map((i: { title: string; image: string }) => ({ items: section3Data.items?.map((i: { title: string; backgroundImage?: string }) => ({
title: i.title, title: i.title,
image: i.image, backgroundImage: i.backgroundImage,
})) ?? [], })) ?? [],
} }
: null; : null;

View File

@ -1,3 +1,7 @@
.topTabsSection {
padding: 0 !important;
}
/* 公益传播 */ /* 公益传播 */
.publicWelfareDataItems { .publicWelfareDataItems {
/* 2列 */ /* 2列 */

View File

@ -1,12 +1,12 @@
import Banner, { type BannerConfig } from "@/components/Banner"; import Banner, { type BannerConfig } from "@/components/Banner";
import { useState } from "react"; import { useState } from "react";
import ParagraphSection from "@/components/layout/ParagraphSection"; import ParagraphSection from "@/components/layout/ParagraphSection";
import TopTabs from "@/components/layout/TopTabsSection/TopTabs";
import Section from "@/components/layout/Section"; import Section from "@/components/layout/Section";
import AnimateTopCard from "@/components/layout/AnimateTopCard"; import AnimateTopCard from "@/components/layout/AnimateTopCard";
import BottomTabs from "@/components/layout/BottomTabsSection/BottomTabs"; import BottomTabs from "@/components/layout/BottomTabsSection/BottomTabs";
import { useStore } from "@/store"; import { useStore } from "@/store";
import styles from "./Foundation.module.css"; import styles from "./Foundation.module.css";
import TopTabsSection from "@/components/layout/TopTabsSection";
export default function Foundation() { export default function Foundation() {
const appConfig = useStore((s) => s.appConfig); const appConfig = useStore((s) => s.appConfig);
@ -20,9 +20,6 @@ export default function Foundation() {
const section2Data = data.section2Data; const section2Data = data.section2Data;
const section3Data = data.section3Data; const section3Data = data.section3Data;
const section4Data = data.section4Data; const section4Data = data.section4Data;
const section5Data = data.section5Data;
const topTabsData = section2Data ? { tabItems: section2Data.tabItems ?? [] } : null;
return ( return (
<div> <div>
@ -37,19 +34,17 @@ export default function Foundation() {
{section1Data && ( {section1Data && (
<ParagraphSection data={section1Data}> <ParagraphSection data={section1Data}>
<div style={{ marginTop: "100px" }} /> <div style={{ marginTop: "100px" }} />
{topTabsData && <TopTabs data={topTabsData} />} {section1Data.tabItems && <TopTabsSection data={{ tabItems: section1Data.tabItems }} className={styles.topTabsSection} />}
<div style={{ marginBottom: "50px" }} />
</ParagraphSection> </ParagraphSection>
)} )}
{section2Data && (
{section3Data && (
<Section <Section
title={section3Data.title} title={section2Data.title}
background="" background=""
maskBackground="rgba(255,255,255,0.3)" maskBackground="rgba(255,255,255,0.3)"
> >
<div className={styles.publicWelfareDataItems}> <div className={styles.publicWelfareDataItems}>
{section3Data.items?.map((item, index) => ( {section2Data.items?.map((item, index) => (
<div <div
key={index} key={index}
className={styles.publicWelfareDataItem} className={styles.publicWelfareDataItem}
@ -67,12 +62,12 @@ export default function Foundation() {
<Section <Section
title={section4Data.title} title={section4Data.title}
titleColor="#fff" titleColor="#fff"
background={section4Data.backgroundImage ?? "/images/bg-overview.png"} background={section3Data.backgroundImage ?? "/images/bg-overview.png"}
maskBackground="rgba(255,255,255,0.1)" maskBackground="rgba(255,255,255,0.1)"
> >
<div className={styles.informationPublicDataContent}> <div className={styles.informationPublicDataContent}>
<div className={styles.informationPublicDataItems}> <div className={styles.informationPublicDataItems}>
{section4Data.tabItems?.[activeIndex]?.fileItems?.map((item, index) => ( {section3Data.tabItems?.[activeIndex]?.fileItems?.map((item, index) => (
<div key={index} className={styles.informationPublicDataItem}> <div key={index} className={styles.informationPublicDataItem}>
<li> <li>
<span>{item.fileName}</span> <span>{item.fileName}</span>
@ -81,7 +76,7 @@ export default function Foundation() {
))} ))}
</div> </div>
<BottomTabs <BottomTabs
tabItems={section4Data.tabItems ?? []} tabItems={section3Data.tabItems ?? []}
activeIndex={activeIndex} activeIndex={activeIndex}
setActiveIndex={setActiveIndex} setActiveIndex={setActiveIndex}
/> />
@ -89,10 +84,10 @@ export default function Foundation() {
</Section> </Section>
)} )}
{section5Data && ( {section4Data && (
<Section title={section5Data.title} background="" maskBackground="#F7FBFF"> <Section title={section4Data.title} background="" maskBackground="#F7FBFF">
<div className={styles.partnerItems}> <div className={styles.partnerItems}>
{section5Data.items?.map((item, index) => ( {section4Data.items?.map((item, index) => (
<div key={index} className={styles.partnerItem}> <div key={index} className={styles.partnerItem}>
<img src={item.logo} alt="logo" /> <img src={item.logo} alt="logo" />
</div> </div>