Index.vue 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743
  1. <template>
  2. <DefaultLayout>
  3. <!-- banner -->
  4. <section class="banner-section">
  5. <div class="banner-image animate-fade-in">
  6. <img src="@assets/banner.png" alt="" srcset="">
  7. </div>
  8. <div class="info-row">
  9. <div class="info-item animate-scale-in" :class="{ 'animate-visible': isInfoVisible }"
  10. style="animation-delay: 0.2s">
  11. <span class="text">覆盖</span>
  12. <span class="number" ref="number1">{{ animatedNumbers.number1 }}+</span>
  13. <span class="text">垂直行业</span>
  14. </div>
  15. <div class="info-item animate-scale-in" :class="{ 'animate-visible': isInfoVisible }"
  16. style="animation-delay: 0.4s">
  17. <span class="number" ref="number2">{{ animatedNumbers.number2 }}</span>
  18. <span class="text">小时原型交付</span>
  19. </div>
  20. <div class="info-item animate-scale-in" :class="{ 'animate-visible': isInfoVisible }"
  21. style="animation-delay: 0.6s">
  22. <span class="text">定制成本降低</span>
  23. <span class="number" ref="number3">{{ animatedNumbers.number3 }}%</span>
  24. </div>
  25. </div>
  26. </section>
  27. <!-- 产品中心 -->
  28. <section class="products-section" ref="productsSection">
  29. <div class="container">
  30. <div class="section-header animate-fade-up" :class="{ 'animate-visible': isProductsVisible }">
  31. <h2 class="section-title">产品中心</h2>
  32. <p class="section-subtitle">SMART SOLUTION</p>
  33. <p class="section-description">智慧管理系统采用先进开发技术,为智慧产业提供一站式解决方案</p>
  34. </div>
  35. <div class="products-content animate-fade-up" :class="{ 'animate-visible': isProductsVisible }"
  36. style="animation-delay: 0.3s">
  37. <div class="products-nav">
  38. <div v-for="(product, index) in productList" :key="product.id" class="nav-item animate-slide-right"
  39. :class="{ active: activeProductId === product.id, 'animate-visible': isProductsVisible }"
  40. :style="{ 'animation-delay': `${0.1 * index}s` }" @click="setActiveProduct(product.id)">
  41. {{ product.classifyName }}
  42. </div>
  43. </div>
  44. <div class="product-detail animate-fade-left" v-if="activeProduct"
  45. :class="{ 'animate-visible': isProductsVisible }" style="animation-delay: 0.5s">
  46. <div class="detail-content">
  47. <h3 class="product-title">{{ activeProduct.classifyName }}</h3>
  48. <p class="product-description">{{ activeProduct.description || activeProduct.classifyDesc || '为您提供专业的解决方案'
  49. }}</p>
  50. </div>
  51. <div class="detail-image">
  52. <img :src="imgHost + activeProduct.projectImage" :alt="activeProduct.classifyName" />
  53. </div>
  54. </div>
  55. </div>
  56. </div>
  57. </section>
  58. <!-- 行业案例 -->
  59. <section class="cases-section" ref="casesSection">
  60. <div class="container">
  61. <div class="section-header animate-fade-up" :class="{ 'animate-visible': isCasesVisible }">
  62. <h2 class="section-title">行业案例</h2>
  63. <p class="section-subtitle">SMART SOLUTION</p>
  64. <p class="section-description">智慧管理系统采用先进开发技术,为智慧产业提供一站式解决方案</p>
  65. </div>
  66. <div class="cases-carousel animate-fade-up" :class="{ 'animate-visible': isCasesVisible }"
  67. style="animation-delay: 0.3s">
  68. <div class="nav-arrow nav-arrow-left animate-bounce-in"
  69. :class="{ disabled: currentCaseIndex === 0, 'animate-visible': isCasesVisible }" @click="prevCase"
  70. style="animation-delay: 0.5s">
  71. <div class="arrow-icon">
  72. <img src="@assets/arrow-right.png" alt="Previous" />
  73. </div>
  74. </div>
  75. <div class="cases-container">
  76. <div class="cases-wrapper"
  77. :style="{ transform: `translateX(-${currentCaseIndex * (100 / visibleCases)}%)` }">
  78. <div v-for="caseItem in casesList" :key="caseItem.id" @click="goToCaseDetail(caseItem)" class="case-item">
  79. <div class="case-image">
  80. <img :src="imgHost + caseItem.projectImage" :alt="caseItem.title" />
  81. </div>
  82. <div class="case-content">
  83. <h3 class="case-title">{{ caseItem.projectName }}</h3>
  84. <p class="case-description">{{ caseItem.projectProfile }}</p>
  85. </div>
  86. </div>
  87. </div>
  88. </div>
  89. <div class="nav-arrow nav-arrow-right animate-bounce-in"
  90. :class="{ disabled: currentCaseIndex >= maxCaseIndex, 'animate-visible': isCasesVisible }" @click="nextCase"
  91. style="animation-delay: 0.7s">
  92. <div class="arrow-icon">
  93. <img src="@assets/arrow-right.png" alt="Next" />
  94. </div>
  95. </div>
  96. </div>
  97. </div>
  98. </section>
  99. <!-- 企业简介 -->
  100. <section class="about-section" ref="aboutSection">
  101. <div class="container">
  102. <div class="section-header animate-fade-up" :class="{ 'animate-visible': isAboutVisible }">
  103. <h2 class="section-title">企业简介</h2>
  104. <p class="section-subtitle">ENTERPRISE QUALIFICATION</p>
  105. </div>
  106. <div class="about-content">
  107. <div class="about-tabs animate-fade-up" :class="{ 'animate-visible': isAboutVisible }"
  108. style="animation-delay: 0.2s">
  109. <div v-for="(tab, index) in aboutTabs" :key="tab.id" class="tab-item animate-slide-up"
  110. :class="{ active: activeAboutTab === tab.id, 'animate-visible': isAboutVisible }"
  111. :style="{ 'animation-delay': `${0.1 * index}s` }" @click="setActiveAboutTab(tab.id)">
  112. {{ tab.title }}
  113. </div>
  114. </div>
  115. <div class="about-detail animate-fade-up" :class="{ 'animate-visible': isAboutVisible }"
  116. style="animation-delay: 0.4s">
  117. <transition name="fade-slide" mode="out-in">
  118. <div :key="activeAboutTab" class="detail-content">
  119. <div class="content-left">
  120. <img :src="activeAboutContent.image" :alt="activeAboutContent.title" />
  121. </div>
  122. <div class="content-right">
  123. <h3 class="content-title">{{ activeAboutContent.title }}</h3>
  124. <div class="content-description" v-html="activeAboutContent.description"></div>
  125. <div class="content-action">
  126. <button class="learn-more-btn" @click="router.push({ name: 'About' })">查看更多 →</button>
  127. </div>
  128. </div>
  129. </div>
  130. </transition>
  131. </div>
  132. </div>
  133. </div>
  134. </section>
  135. <!-- 合作伙伴 -->
  136. <section class="cooperation-section" ref="cooperationSection">
  137. <div class="container">
  138. <div class="section-header animate-fade-up" :class="{ 'animate-visible': isCooperationVisible }">
  139. <h2 class="section-title">合作伙伴</h2>
  140. <p class="section-subtitle">BUSINESS PARTNER</p>
  141. </div>
  142. <div class="partners-grid animate-fade-up" :class="{ 'animate-visible': isCooperationVisible }"
  143. style="animation-delay: 0.3s">
  144. <a v-for="(partner, index) in partnersList" :key="partner.id" :href="partner.partnersUrl" target="_blank"
  145. class="partner-item animate-scale-in" :class="{ 'animate-visible': isCooperationVisible }"
  146. :style="{ 'animation-delay': `${0.1 * (index % 6)}s` }">
  147. <img :src="imgHost + partner.partnersLogo" :alt="partner.partnersName" />
  148. </a>
  149. </div>
  150. </div>
  151. </section>
  152. </DefaultLayout>
  153. </template>
  154. <script>
  155. import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue'
  156. import { useRouter } from 'vue-router'
  157. import DefaultLayout from '@/layouts/DefaultLayout.vue'
  158. import { getCompanyInfo, getProjectClassifyList, getProjectList, getCompanyCertList, getPartners } from '@/api/modules/home'
  159. import { animateNumber, createNumberAnimationObserver } from '@/utils/numberAnimation'
  160. // 导入图片资源
  161. import indexAboutBg from '@/assets/index-about-img.png'
  162. export default {
  163. name: 'HomePage',
  164. components: {
  165. DefaultLayout
  166. },
  167. setup() {
  168. const router = useRouter()
  169. const activeProductId = ref(null)
  170. // 环境变量
  171. const imgHost = import.meta.env.VITE_APP_IMG_HOST
  172. // 动画状态管理
  173. const isInfoVisible = ref(false)
  174. const isProductsVisible = ref(false)
  175. const isCasesVisible = ref(false)
  176. const isAboutVisible = ref(false)
  177. const isCooperationVisible = ref(false)
  178. // 元素引用
  179. const productsSection = ref(null)
  180. const casesSection = ref(null)
  181. const aboutSection = ref(null)
  182. const cooperationSection = ref(null)
  183. // 数字滚动动画相关
  184. const animatedNumbers = ref({
  185. number1: 0,
  186. number2: 0,
  187. number3: 0
  188. })
  189. const targetNumbers = {
  190. number1: 10,
  191. number2: 72,
  192. number3: 30
  193. }
  194. // 启动所有数字动画
  195. const startNumberAnimations = () => {
  196. // 延迟启动,让页面加载完成后再开始动画
  197. setTimeout(() => {
  198. animateNumber(
  199. (value) => animatedNumbers.value.number1 = value,
  200. targetNumbers.number1,
  201. 2000
  202. )
  203. }, 200)
  204. setTimeout(() => {
  205. animateNumber(
  206. (value) => animatedNumbers.value.number2 = value,
  207. targetNumbers.number2,
  208. 2500
  209. )
  210. }, 500)
  211. setTimeout(() => {
  212. animateNumber(
  213. (value) => animatedNumbers.value.number3 = value,
  214. targetNumbers.number3,
  215. 2200
  216. )
  217. }, 800)
  218. }
  219. // 设置数字动画观察器
  220. const setupIntersectionObserver = () => {
  221. createNumberAnimationObserver('.info-row', startNumberAnimations, {
  222. threshold: 0.5,
  223. rootMargin: '0px 0px -50px 0px'
  224. })
  225. }
  226. // 设置滚动动画观察器
  227. const setupScrollAnimations = () => {
  228. const observerOptions = {
  229. threshold: 0.2,
  230. rootMargin: '0px 0px -50px 0px'
  231. }
  232. const observer = new IntersectionObserver((entries) => {
  233. entries.forEach(entry => {
  234. if (entry.isIntersecting) {
  235. const target = entry.target
  236. if (target.classList.contains('banner-section')) {
  237. isInfoVisible.value = true
  238. } else if (target.classList.contains('products-section')) {
  239. isProductsVisible.value = true
  240. } else if (target.classList.contains('cases-section')) {
  241. isCasesVisible.value = true
  242. } else if (target.classList.contains('about-section')) {
  243. isAboutVisible.value = true
  244. } else if (target.classList.contains('cooperation-section')) {
  245. isCooperationVisible.value = true
  246. }
  247. }
  248. })
  249. }, observerOptions)
  250. // 观察各个区域
  251. nextTick(() => {
  252. const bannerSection = document.querySelector('.banner-section')
  253. if (bannerSection) observer.observe(bannerSection)
  254. if (productsSection.value) observer.observe(productsSection.value)
  255. if (casesSection.value) observer.observe(casesSection.value)
  256. if (aboutSection.value) observer.observe(aboutSection.value)
  257. if (cooperationSection.value) observer.observe(cooperationSection.value)
  258. })
  259. }
  260. // 产品分类列表
  261. let productList = ref([])
  262. // 当前选中分类的产品列表
  263. let currentProductList = ref([])
  264. const activeProduct = computed(() => {
  265. if (productList.value.length === 0) return null
  266. return productList.value.find(product => product.id === activeProductId.value) || productList.value[0]
  267. })
  268. const setActiveProduct = async (id) => {
  269. activeProductId.value = id
  270. // 获取选中分类的产品列表
  271. const selectedCategory = productList.value.find(product => product.id === id)
  272. if (selectedCategory && selectedCategory.id) {
  273. await getProductsByClassify(selectedCategory.id)
  274. }
  275. }
  276. // 行业案例数据和逻辑
  277. const currentCaseIndex = ref(0)
  278. const visibleCases = ref(3) // 同时显示的案例数量
  279. // 企业简介数据和逻辑
  280. const activeAboutTab = ref('about')
  281. const aboutTabs = ref([
  282. { id: 'about', title: '关于达泽' },
  283. { id: 'history', title: '发展历程' },
  284. { id: 'qualification', title: '荣誉资质' }
  285. ])
  286. let aboutContents = ref({
  287. about: {
  288. title: '关于达泽',
  289. description: '<p>加载中...</p>',
  290. image: indexAboutBg
  291. },
  292. history: {
  293. title: '发展历程',
  294. description: '<p>加载中...</p>',
  295. image: indexAboutBg
  296. },
  297. qualification: {
  298. title: '荣誉资质',
  299. description: '<p>加载中...</p>',
  300. image: indexAboutBg
  301. }
  302. })
  303. const activeAboutContent = computed(() => {
  304. return aboutContents.value[activeAboutTab.value]
  305. })
  306. const setActiveAboutTab = (tabId) => {
  307. activeAboutTab.value = tabId
  308. }
  309. // 合作伙伴数据
  310. let partnersList = ref([])
  311. let casesList = ref([
  312. {
  313. id: 1,
  314. projectName: '智慧农业(种植+养殖)',
  315. projectProfile: '通过物联网技术实现农业自动化管理,利用传感器监控土壤、水质等环境参数,提高农业生产效率。',
  316. projectImage: 'https://unsplash.it/300/200'
  317. }
  318. ])
  319. const maxCaseIndex = computed(() => {
  320. return Math.max(0, casesList.value.length - visibleCases.value)
  321. })
  322. const nextCase = () => {
  323. if (currentCaseIndex.value < maxCaseIndex.value) {
  324. currentCaseIndex.value++
  325. }
  326. }
  327. const prevCase = () => {
  328. if (currentCaseIndex.value > 0) {
  329. currentCaseIndex.value--
  330. }
  331. }
  332. // API调用方法
  333. const loadHomeData = async () => {
  334. try {
  335. const result = await getCompanyInfo()
  336. const data = result.data
  337. // console.log('首页数据:', data)
  338. if (data) {
  339. // 更新关于达泽的描述
  340. if (data.companyDescribe) {
  341. aboutContents.value.about.description = data.companyDescribe
  342. }
  343. // 更新发展历程的描述
  344. if (data.courseList && Array.isArray(data.courseList)) {
  345. const historyHtml = data.courseList.map(item => {
  346. const time = item.createTime ? new Date(item.createTime).getFullYear() : '未知时间'
  347. const description = item.courseDescribe || '暂无描述'
  348. return `<p><strong>${time}年</strong> - ${description}</p>`
  349. }).join('')
  350. aboutContents.value.history.description = historyHtml || '<p>暂无发展历程数据</p>'
  351. }
  352. }
  353. } catch (error) {
  354. console.error('加载首页数据失败:', error)
  355. }
  356. }
  357. // 获取产品分类列表
  358. const handleGetProjectClassifyList1 = async () => {
  359. try {
  360. const data = await getProjectClassifyList({ classifyType: 1 })
  361. // console.log('产品中心分类列表:', data)
  362. if (data && data.rows && data.rows.length > 0) {
  363. productList.value = data.rows
  364. // 默认选中第一个分类
  365. activeProductId.value = data.rows[0].id
  366. // 获取第一个分类的产品列表
  367. await getProductsByClassify(data.rows[0].id)
  368. }
  369. } catch (error) {
  370. console.error('加载产品中心分类列表失败:', error)
  371. }
  372. }
  373. // 根据分类ID获取产品列表
  374. const getProductsByClassify = async (classifyId) => {
  375. try {
  376. const data = await getProjectList({
  377. classifyId: classifyId,
  378. projectType: 1 // 1:产品中心 2:行业案例
  379. })
  380. // console.log('产品列表:', data)
  381. if (data && data.rows) {
  382. currentProductList.value = data.rows
  383. // 更新当前选中分类的描述信息
  384. const currentCategory = productList.value.find(item => item.id === activeProductId.value)
  385. if (currentCategory && data.rows.length > 0) {
  386. // 可以根据API返回的数据更新分类的描述信息
  387. currentCategory.description = data.rows[0].projectProfile || currentCategory.classifyDesc || '为您提供专业的解决方案';
  388. currentCategory.projectImage = data.rows[0].projectImage
  389. // console.log('currentCategory', currentCategory)
  390. }
  391. }
  392. } catch (error) {
  393. console.error('加载产品列表失败:', error)
  394. }
  395. }
  396. // 产品/案例信息-案例信息
  397. const handleGetProjectList = async () => {
  398. try {
  399. const data = await getProjectList({ projectType: 2 })
  400. // 这里可以更新products和advantages数据
  401. // console.log('案例信息:', data)
  402. casesList.value = data.rows;
  403. // console.log('案例信息列表:', casesList.value)
  404. } catch (error) {
  405. console.error('加载案例信息失败:', error)
  406. }
  407. }
  408. // 响应式处理
  409. const updateVisibleCases = () => {
  410. if (window.innerWidth <= 768) {
  411. visibleCases.value = 1
  412. } else {
  413. visibleCases.value = 3
  414. }
  415. // 重置索引以防超出范围
  416. if (currentCaseIndex.value > maxCaseIndex.value) {
  417. currentCaseIndex.value = maxCaseIndex.value
  418. }
  419. }
  420. // 跳转到案例详情页
  421. const goToCaseDetail = (caseItem) => {
  422. router.push({
  423. name: 'Casesdetails',
  424. query: { id: caseItem.id, classifyId: caseItem.classifyId }
  425. })
  426. }
  427. // 获取企业资质证书
  428. const loadCompanyCertList = async () => {
  429. try {
  430. const data = await getCompanyCertList()
  431. // console.log('企业资质数据:', data)
  432. if (data && data.rows && Array.isArray(data.rows)) {
  433. const certHtml = data.rows.map(item => {
  434. const certName = item.certName || '未知证书'
  435. return `<p><strong>${certName}</strong></p>`
  436. }).join('')
  437. aboutContents.value.qualification.description = certHtml || '<p>暂无资质证书数据</p>'
  438. }
  439. } catch (error) {
  440. console.error('加载企业资质失败:', error)
  441. }
  442. }
  443. // 获取合作伙伴列表
  444. const loadPartnersList = async () => {
  445. try {
  446. const data = await getPartners()
  447. // console.log('合作伙伴数据:', data)
  448. if (data && data.rows && Array.isArray(data.rows)) {
  449. partnersList.value = data.rows
  450. }
  451. } catch (error) {
  452. console.error('加载合作伙伴失败:', error)
  453. }
  454. }
  455. // 优化API请求顺序
  456. const loadCriticalData = async () => {
  457. // 关键数据:首屏可见内容
  458. try {
  459. await Promise.all([
  460. loadHomeData(), // 首页基础数据和企业简介
  461. handleGetProjectClassifyList1() // 产品分类列表(首屏可见)
  462. ])
  463. } catch (error) {
  464. console.error('加载关键数据失败:', error)
  465. }
  466. }
  467. const loadSecondaryData = async () => {
  468. // 次要数据:首屏下方内容,可以延迟加载
  469. try {
  470. await Promise.all([
  471. handleGetProjectList(), // 案例列表
  472. loadCompanyCertList(), // 企业资质证书
  473. loadPartnersList() // 合作伙伴列表
  474. ])
  475. } catch (error) {
  476. console.error('加载次要数据失败:', error)
  477. }
  478. }
  479. onMounted(async () => {
  480. // 先加载关键数据
  481. await loadCriticalData()
  482. // 延迟加载次要数据,避免阻塞首屏渲染
  483. setTimeout(() => {
  484. loadSecondaryData()
  485. }, 100)
  486. updateVisibleCases()
  487. window.addEventListener('resize', updateVisibleCases)
  488. // 设置数字滚动动画的观察器
  489. nextTick(() => {
  490. setupIntersectionObserver()
  491. setupScrollAnimations()
  492. })
  493. // 延迟显示banner信息区域
  494. setTimeout(() => {
  495. isInfoVisible.value = true
  496. }, 800)
  497. })
  498. onUnmounted(() => {
  499. window.removeEventListener('resize', updateVisibleCases)
  500. })
  501. return {
  502. router,
  503. productList,
  504. currentProductList,
  505. activeProductId,
  506. activeProduct,
  507. setActiveProduct,
  508. casesList,
  509. currentCaseIndex,
  510. visibleCases,
  511. maxCaseIndex,
  512. nextCase,
  513. prevCase,
  514. aboutTabs,
  515. activeAboutTab,
  516. activeAboutContent,
  517. setActiveAboutTab,
  518. partnersList,
  519. goToCaseDetail,
  520. imgHost,
  521. animatedNumbers,
  522. // 动画状态
  523. isInfoVisible,
  524. isProductsVisible,
  525. isCasesVisible,
  526. isAboutVisible,
  527. isCooperationVisible,
  528. // 元素引用
  529. productsSection,
  530. casesSection,
  531. aboutSection,
  532. cooperationSection
  533. }
  534. }
  535. }
  536. </script>
  537. <style lang="scss" scoped>
  538. // 动画定义
  539. @keyframes fadeIn {
  540. from {
  541. opacity: 0;
  542. }
  543. to {
  544. opacity: 1;
  545. }
  546. }
  547. @keyframes slideUp {
  548. from {
  549. opacity: 0;
  550. transform: translateY(30px);
  551. }
  552. to {
  553. opacity: 1;
  554. transform: translateY(0);
  555. }
  556. }
  557. @keyframes slideRight {
  558. from {
  559. opacity: 0;
  560. transform: translateX(-30px);
  561. }
  562. to {
  563. opacity: 1;
  564. transform: translateX(0);
  565. }
  566. }
  567. @keyframes slideLeft {
  568. from {
  569. opacity: 0;
  570. transform: translateX(30px);
  571. }
  572. to {
  573. opacity: 1;
  574. transform: translateX(0);
  575. }
  576. }
  577. @keyframes scaleIn {
  578. from {
  579. opacity: 0;
  580. transform: scale(0.8);
  581. }
  582. to {
  583. opacity: 1;
  584. transform: scale(1);
  585. }
  586. }
  587. @keyframes bounceIn {
  588. 0% {
  589. opacity: 0;
  590. transform: scale(0.3);
  591. }
  592. 50% {
  593. transform: scale(1.05);
  594. }
  595. 70% {
  596. transform: scale(0.9);
  597. }
  598. 100% {
  599. opacity: 1;
  600. transform: scale(1);
  601. }
  602. }
  603. @keyframes fadeUp {
  604. from {
  605. opacity: 0;
  606. transform: translateY(40px);
  607. }
  608. to {
  609. opacity: 1;
  610. transform: translateY(0);
  611. }
  612. }
  613. @keyframes fadeLeft {
  614. from {
  615. opacity: 0;
  616. transform: translateX(40px);
  617. }
  618. to {
  619. opacity: 1;
  620. transform: translateX(0);
  621. }
  622. }
  623. // 动画类
  624. .animate-fade-in {
  625. animation: fadeIn 1s ease-out;
  626. }
  627. .animate-slide-up {
  628. opacity: 0;
  629. transform: translateY(30px);
  630. transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
  631. &.animate-visible {
  632. opacity: 1;
  633. transform: translateY(0);
  634. }
  635. }
  636. .animate-slide-right {
  637. opacity: 0;
  638. transform: translateX(-30px);
  639. transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
  640. &.animate-visible {
  641. opacity: 1;
  642. transform: translateX(0);
  643. }
  644. }
  645. .animate-slide-left {
  646. opacity: 0;
  647. transform: translateX(30px);
  648. transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
  649. &.animate-visible {
  650. opacity: 1;
  651. transform: translateX(0);
  652. }
  653. }
  654. .animate-scale-in {
  655. opacity: 1;
  656. transform: scale(0.95);
  657. transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
  658. &.animate-visible {
  659. opacity: 1;
  660. transform: scale(1);
  661. }
  662. }
  663. .animate-bounce-in {
  664. opacity: 0;
  665. transform: scale(0.3);
  666. transition: all 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55);
  667. &.animate-visible {
  668. opacity: 1;
  669. transform: scale(1);
  670. }
  671. }
  672. .animate-fade-up {
  673. opacity: 0;
  674. transform: translateY(40px);
  675. transition: all 0.8s cubic-bezier(0.4, 0, 0.2, 1);
  676. &.animate-visible {
  677. opacity: 1;
  678. transform: translateY(0);
  679. }
  680. }
  681. .animate-fade-left {
  682. opacity: 0;
  683. transform: translateX(40px);
  684. transition: all 0.8s cubic-bezier(0.4, 0, 0.2, 1);
  685. &.animate-visible {
  686. opacity: 1;
  687. transform: translateX(0);
  688. }
  689. }
  690. // banner区域
  691. .banner-section {
  692. position: relative;
  693. .banner-image {
  694. img {
  695. width: 100%;
  696. }
  697. }
  698. }
  699. .info-row {
  700. height: 130px;
  701. position: absolute;
  702. left: 0;
  703. right: 0;
  704. bottom: 0;
  705. display: flex;
  706. justify-content: center;
  707. align-items: center;
  708. backdrop-filter: blur(5px);
  709. background-color: rgba(255, 255, 255, 0.3);
  710. .info-item {
  711. // flex: 1;
  712. padding: 0 78px;
  713. position: relative;
  714. text-align: center;
  715. }
  716. .info-item:not(:last-child)::after {
  717. content: '';
  718. position: absolute;
  719. top: 50%;
  720. right: 0;
  721. width: 1px;
  722. height: 20px;
  723. background-color: #ccc;
  724. transform: translateY(-50%);
  725. }
  726. .number {
  727. color: #0066cc;
  728. font-weight: bold;
  729. font-size: 32px;
  730. vertical-align: middle;
  731. margin: 0 5px;
  732. font-family: 'Arial', monospace;
  733. letter-spacing: 1px;
  734. transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  735. display: inline-block;
  736. min-width: 1.2em;
  737. text-align: center;
  738. position: relative;
  739. text-shadow: 0 2px 4px rgba(0, 102, 204, 0.2);
  740. &::after {
  741. content: '';
  742. position: absolute;
  743. bottom: -2px;
  744. left: 50%;
  745. width: 0;
  746. height: 2px;
  747. background: linear-gradient(90deg, #0066cc, #00aaff);
  748. transform: translateX(-50%);
  749. transition: width 0.6s ease;
  750. }
  751. }
  752. .info-item:hover .number::after {
  753. width: 100%;
  754. }
  755. .text {
  756. font-size: 18px;
  757. font-weight: 400;
  758. color: #333;
  759. margin: 0;
  760. display: inline-block;
  761. }
  762. }
  763. // 产品中心
  764. .products-section {
  765. background: url('@assets/index-products-bg.png') no-repeat center center;
  766. background-size: cover;
  767. padding: 80px 0;
  768. position: relative;
  769. .section-header {
  770. text-align: center;
  771. margin-bottom: 60px;
  772. .section-title {
  773. font-size: 42px;
  774. font-weight: bold;
  775. color: #333;
  776. margin: 0 0 20px 0;
  777. }
  778. .section-subtitle {
  779. font-size: 16px;
  780. color: #999;
  781. margin: 0 0 20px 0;
  782. letter-spacing: 2px;
  783. text-transform: uppercase;
  784. }
  785. .section-description {
  786. font-size: 18px;
  787. color: #666;
  788. margin: 0;
  789. line-height: 1.6;
  790. }
  791. }
  792. .products-content {
  793. display: flex;
  794. gap: 60px;
  795. align-items: flex-start;
  796. }
  797. .products-nav {
  798. flex: 0 0 21.6%;
  799. .nav-item {
  800. height: 100px;
  801. line-height: 100px;
  802. padding: 0 30px;
  803. margin-bottom: 2px;
  804. cursor: pointer;
  805. font-size: 24px;
  806. font-weight: 500;
  807. color: #343434;
  808. transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  809. position: relative;
  810. overflow: hidden;
  811. box-sizing: border-box;
  812. &::before {
  813. content: '';
  814. position: absolute;
  815. top: 0;
  816. left: -100%;
  817. width: 100%;
  818. height: 100%;
  819. background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
  820. transition: left 0.6s ease;
  821. }
  822. &:hover {
  823. background: rgba(0, 102, 204, 0.1);
  824. color: #0066cc;
  825. transform: translateX(5px);
  826. &::before {
  827. left: 100%;
  828. }
  829. }
  830. &.active {
  831. background: linear-gradient(to right, #CAE0FF, #E5F0FF);
  832. color: #0054FF;
  833. transform: translateX(8px);
  834. box-shadow: 0 4px 15px rgba(0, 102, 204, 0.2);
  835. }
  836. }
  837. }
  838. .product-detail {
  839. flex: 1;
  840. .detail-content {
  841. flex: 1;
  842. .product-title {
  843. font-size: 36px;
  844. font-weight: bold;
  845. color: #333;
  846. margin: 0 0 20px 0;
  847. }
  848. .product-description {
  849. font-size: 24px;
  850. color: #333;
  851. line-height: 1.5;
  852. margin-bottom: 35px;
  853. }
  854. }
  855. .detail-image {
  856. img {
  857. width: 100%;
  858. object-fit: cover;
  859. border-radius: 8px;
  860. box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
  861. }
  862. }
  863. }
  864. }
  865. // 行业案例
  866. .cases-section {
  867. background: url('@assets/index-cases-bg.png') no-repeat center center;
  868. background-size: cover;
  869. padding: 80px 0;
  870. position: relative;
  871. .section-header {
  872. text-align: center;
  873. margin-bottom: 60px;
  874. .section-title {
  875. font-size: 42px;
  876. font-weight: bold;
  877. color: #333;
  878. margin: 0 0 20px 0;
  879. }
  880. .section-subtitle {
  881. font-size: 16px;
  882. color: #999;
  883. margin: 0 0 20px 0;
  884. letter-spacing: 2px;
  885. text-transform: uppercase;
  886. }
  887. .section-description {
  888. font-size: 18px;
  889. color: #666;
  890. margin: 0;
  891. line-height: 1.6;
  892. }
  893. }
  894. .cases-carousel {
  895. position: relative;
  896. display: flex;
  897. align-items: center;
  898. gap: 30px;
  899. }
  900. .nav-arrow {
  901. width: 60px;
  902. height: 60px;
  903. border-radius: 50%;
  904. background: rgba(255, 255, 255, 0.9);
  905. display: flex;
  906. align-items: center;
  907. justify-content: center;
  908. cursor: pointer;
  909. transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  910. box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  911. flex-shrink: 0;
  912. position: relative;
  913. overflow: hidden;
  914. &::before {
  915. content: '';
  916. position: absolute;
  917. top: 0;
  918. left: 0;
  919. right: 0;
  920. bottom: 0;
  921. background: linear-gradient(45deg, rgba(0, 102, 204, 0.1), transparent);
  922. opacity: 0;
  923. transition: opacity 0.3s ease;
  924. }
  925. &:hover {
  926. background: rgba(255, 255, 255, 1);
  927. box-shadow: 0 8px 20px rgba(0, 102, 204, 0.15);
  928. transform: scale(1.05);
  929. &::before {
  930. opacity: 1;
  931. }
  932. }
  933. &:active {
  934. transform: scale(0.95);
  935. }
  936. &.disabled {
  937. opacity: 0.3;
  938. cursor: not-allowed;
  939. pointer-events: none;
  940. }
  941. .arrow-icon {
  942. width: 24px;
  943. height: 24px;
  944. display: flex;
  945. align-items: center;
  946. justify-content: center;
  947. transition: transform 0.3s ease;
  948. img {
  949. width: 100%;
  950. height: 100%;
  951. object-fit: contain;
  952. filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.1));
  953. }
  954. }
  955. &:hover .arrow-icon {
  956. transform: translateX(2px);
  957. }
  958. &.nav-arrow-left {
  959. .arrow-icon {
  960. transform: rotate(180deg);
  961. }
  962. &:hover .arrow-icon {
  963. transform: rotate(180deg) translateX(2px);
  964. }
  965. }
  966. }
  967. .cases-container {
  968. flex: 1;
  969. overflow: hidden;
  970. border-radius: 12px;
  971. }
  972. .cases-wrapper {
  973. display: flex;
  974. transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1);
  975. width: 100%;
  976. }
  977. .case-item {
  978. flex: 0 0 calc(100% / 3);
  979. padding: 0 15px;
  980. box-sizing: border-box;
  981. cursor: pointer;
  982. transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  983. &:hover {
  984. transform: translateY(-8px);
  985. }
  986. .case-image {
  987. width: 100%;
  988. height: 200px;
  989. border-radius: 12px 12px 0 0;
  990. overflow: hidden;
  991. background: #fff;
  992. position: relative;
  993. &::after {
  994. content: '';
  995. position: absolute;
  996. top: 0;
  997. left: 0;
  998. right: 0;
  999. bottom: 0;
  1000. background: linear-gradient(45deg, rgba(0, 102, 204, 0.1), transparent);
  1001. opacity: 0;
  1002. transition: opacity 0.3s ease;
  1003. }
  1004. img {
  1005. width: 100%;
  1006. height: 100%;
  1007. object-fit: cover;
  1008. transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  1009. }
  1010. }
  1011. &:hover .case-image {
  1012. &::after {
  1013. opacity: 1;
  1014. }
  1015. img {
  1016. transform: scale(1.08);
  1017. }
  1018. }
  1019. .case-content {
  1020. background: rgba(255, 255, 255, 0.95);
  1021. padding: 25px;
  1022. box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
  1023. backdrop-filter: blur(10px);
  1024. border-radius: 0 0 12px 12px;
  1025. transition: box-shadow 0.3s ease;
  1026. .case-title {
  1027. text-align: center;
  1028. font-size: 20px;
  1029. font-weight: bold;
  1030. color: #333;
  1031. margin: 0 0 15px 0;
  1032. line-height: 1.4;
  1033. transition: color 0.3s ease;
  1034. }
  1035. .case-description {
  1036. font-size: 14px;
  1037. color: #666;
  1038. line-height: 1.6;
  1039. margin: 0;
  1040. min-height: 45px;
  1041. overflow: hidden;
  1042. text-overflow: ellipsis;
  1043. display: -webkit-box;
  1044. -webkit-line-clamp: 2;
  1045. line-clamp: 2;
  1046. -webkit-box-orient: vertical;
  1047. }
  1048. }
  1049. &:hover .case-content {
  1050. box-shadow: 0 8px 25px rgba(0, 102, 204, 0.15);
  1051. .case-title {
  1052. color: #0066cc;
  1053. }
  1054. }
  1055. }
  1056. }
  1057. // 企业简介
  1058. .about-section {
  1059. background: url('@assets/index-about-bg.png') no-repeat center center;
  1060. background-size: cover;
  1061. padding: 80px 0;
  1062. position: relative;
  1063. .section-header {
  1064. text-align: center;
  1065. margin-bottom: 60px;
  1066. .section-title {
  1067. font-size: 42px;
  1068. font-weight: bold;
  1069. color: #333;
  1070. margin: 0 0 20px 0;
  1071. }
  1072. .section-subtitle {
  1073. font-size: 16px;
  1074. color: #999;
  1075. margin: 0 0 20px 0;
  1076. letter-spacing: 2px;
  1077. text-transform: uppercase;
  1078. }
  1079. }
  1080. .about-content {
  1081. // max-width: 1200px;
  1082. margin: 0 auto;
  1083. }
  1084. .about-tabs {
  1085. display: flex;
  1086. justify-content: space-between;
  1087. // gap: 0;
  1088. margin-bottom: 95px;
  1089. .tab-item {
  1090. flex: 0 0 400px;
  1091. height: 66px;
  1092. line-height: 66px;
  1093. text-align: center;
  1094. font-size: 30px;
  1095. font-weight: 500;
  1096. color: #333;
  1097. // background: rgba(255, 255, 255, 0.8);
  1098. // border: 2px solid #E5E5E5;
  1099. border-radius: 5px;
  1100. cursor: pointer;
  1101. transition: all 0.3s ease;
  1102. position: relative;
  1103. // &:first-child {
  1104. // border-radius: 8px 0 0 8px;
  1105. // }
  1106. // &:last-child {
  1107. // border-radius: 0 8px 8px 0;
  1108. // }
  1109. // &:not(:last-child) {
  1110. // border-right: none;
  1111. // }
  1112. &:hover {
  1113. background: rgba(0, 102, 204, 0.1);
  1114. color: #0066cc;
  1115. border-color: #0066cc;
  1116. z-index: 2;
  1117. }
  1118. &.active {
  1119. background: #0066cc;
  1120. color: white;
  1121. border-color: #0066cc;
  1122. z-index: 3;
  1123. box-shadow: 0 4px 12px rgba(0, 102, 204, 0.3);
  1124. }
  1125. }
  1126. }
  1127. .about-detail {
  1128. // background: rgba(255, 255, 255, 0.95);
  1129. border-radius: 16px;
  1130. padding: 40px 0;
  1131. // box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
  1132. // backdrop-filter: blur(10px);
  1133. min-height: 400px;
  1134. }
  1135. .detail-content {
  1136. display: flex;
  1137. gap: 110px;
  1138. align-items: flex-start;
  1139. .content-left {
  1140. flex: 0 800px;
  1141. max-width: 800px;
  1142. img {
  1143. width: 100%;
  1144. height: 480px;
  1145. object-fit: cover;
  1146. border-radius: 12px;
  1147. box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
  1148. }
  1149. }
  1150. .content-right {
  1151. flex: 1;
  1152. .content-title {
  1153. font-size: 28px;
  1154. font-weight: bold;
  1155. color: #333;
  1156. margin: 0 0 25px 0;
  1157. }
  1158. .content-description {
  1159. font-size: 16px;
  1160. color: #666;
  1161. line-height: 1.8;
  1162. margin-bottom: 30px;
  1163. p {
  1164. margin: 0 0 15px 0;
  1165. &:last-child {
  1166. margin-bottom: 0;
  1167. }
  1168. }
  1169. strong {
  1170. color: #0066cc;
  1171. font-weight: 600;
  1172. }
  1173. :deep(img) {
  1174. max-width: 100%;
  1175. height: auto;
  1176. border-radius: 8px;
  1177. margin: 10px 0;
  1178. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  1179. }
  1180. }
  1181. .content-action {
  1182. .learn-more-btn {
  1183. background: transparent;
  1184. color: #0054FF;
  1185. border: 1px solid #0054FF;
  1186. padding: 12px 30px;
  1187. border-radius: 5px;
  1188. font-size: 16px;
  1189. font-weight: 500;
  1190. cursor: pointer;
  1191. transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  1192. box-shadow: 0 4px 12px rgba(0, 102, 204, 0.3);
  1193. position: relative;
  1194. overflow: hidden;
  1195. &::before {
  1196. content: '';
  1197. position: absolute;
  1198. top: 0;
  1199. left: -100%;
  1200. width: 100%;
  1201. height: 100%;
  1202. background: linear-gradient(90deg, transparent, rgba(0, 84, 255, 0.1), transparent);
  1203. transition: left 0.6s ease;
  1204. }
  1205. &:hover {
  1206. transform: translateY(-3px);
  1207. box-shadow: 0 8px 25px rgba(0, 102, 204, 0.4);
  1208. background: rgba(0, 84, 255, 0.05);
  1209. &::before {
  1210. left: 100%;
  1211. }
  1212. }
  1213. &:active {
  1214. transform: translateY(-1px);
  1215. }
  1216. }
  1217. }
  1218. }
  1219. }
  1220. }
  1221. // 合作伙伴
  1222. .cooperation-section {
  1223. // background: url('@assets/index-cooperation-bg.png') no-repeat center center;
  1224. background-size: cover;
  1225. padding: 80px 0;
  1226. position: relative;
  1227. &::before {
  1228. position: absolute;
  1229. content: '';
  1230. width: 1346px;
  1231. height: 335px;
  1232. right: 150px;
  1233. top: 0;
  1234. background: url('@assets/index-cooperation-bg.png') no-repeat center center;
  1235. ;
  1236. background-size: contain;
  1237. }
  1238. .section-header {
  1239. text-align: center;
  1240. margin-bottom: 60px;
  1241. .section-title {
  1242. font-size: 42px;
  1243. font-weight: bold;
  1244. color: #333;
  1245. margin: 0 0 20px 0;
  1246. }
  1247. .section-subtitle {
  1248. font-size: 16px;
  1249. color: #999;
  1250. margin: 0 0 185px 0;
  1251. letter-spacing: 2px;
  1252. text-transform: uppercase;
  1253. }
  1254. }
  1255. .partners-grid {
  1256. display: flex;
  1257. flex-wrap: wrap;
  1258. justify-content: center;
  1259. gap: 30px;
  1260. // max-width: 1000px;
  1261. margin: 0 auto;
  1262. .partner-item {
  1263. display: flex;
  1264. align-items: center;
  1265. justify-content: center;
  1266. width: 214px;
  1267. height: 84px;
  1268. background: rgba(255, 255, 255, 0.9);
  1269. border: 2px solid #E5E5E5;
  1270. border-radius: 8px;
  1271. transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  1272. text-decoration: none;
  1273. backdrop-filter: blur(5px);
  1274. overflow: hidden;
  1275. position: relative;
  1276. &::before {
  1277. content: '';
  1278. position: absolute;
  1279. top: 0;
  1280. left: -100%;
  1281. width: 100%;
  1282. height: 100%;
  1283. background: linear-gradient(90deg, transparent, rgba(0, 102, 204, 0.1), transparent);
  1284. transition: left 0.6s ease;
  1285. }
  1286. &:hover {
  1287. background: rgba(255, 255, 255, 1);
  1288. border-color: #0066cc;
  1289. transform: translateY(-8px) scale(1.02);
  1290. box-shadow: 0 12px 30px rgba(0, 102, 204, 0.2);
  1291. &::before {
  1292. left: 100%;
  1293. }
  1294. }
  1295. img {
  1296. max-width: 100%;
  1297. max-height: 84px;
  1298. object-fit: contain;
  1299. transition: all 0.4s ease;
  1300. filter: grayscale(20%);
  1301. }
  1302. &:hover img {
  1303. filter: grayscale(0%) brightness(1.1);
  1304. transform: scale(1.05);
  1305. }
  1306. }
  1307. }
  1308. }
  1309. // 切换动画
  1310. .fade-slide-enter-active,
  1311. .fade-slide-leave-active {
  1312. transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  1313. }
  1314. .fade-slide-enter-from {
  1315. opacity: 0;
  1316. transform: translateX(30px);
  1317. }
  1318. .fade-slide-leave-to {
  1319. opacity: 0;
  1320. transform: translateX(-30px);
  1321. }
  1322. // 响应式设计
  1323. @media (max-width: 768px) {
  1324. .cooperation-section {
  1325. &::before {
  1326. width: 0;
  1327. }
  1328. .section-header {
  1329. .section-subtitle {
  1330. margin-bottom: 10px;
  1331. }
  1332. }
  1333. }
  1334. .info-row {
  1335. .info-item {
  1336. padding: 0 10px;
  1337. }
  1338. .text {
  1339. font-size: 14px;
  1340. }
  1341. .number {
  1342. font-size: 14px;
  1343. }
  1344. }
  1345. .products-section {
  1346. padding: 40px 0;
  1347. .section-header {
  1348. margin-bottom: 40px;
  1349. .section-title {
  1350. font-size: 32px;
  1351. }
  1352. }
  1353. .products-content {
  1354. flex-direction: column;
  1355. gap: 0;
  1356. }
  1357. .products-nav {
  1358. flex: none;
  1359. display: flex;
  1360. overflow-x: auto;
  1361. gap: 10px;
  1362. padding-bottom: 10px;
  1363. flex-wrap: wrap;
  1364. .nav-item {
  1365. flex: 0 0 auto;
  1366. white-space: nowrap;
  1367. padding: 15px 20px;
  1368. font-size: 16px;
  1369. height: auto;
  1370. line-height: 1;
  1371. }
  1372. }
  1373. .product-detail {
  1374. flex-direction: column;
  1375. padding: 30px 20px;
  1376. .detail-image {
  1377. flex: none;
  1378. width: 100%;
  1379. img {
  1380. height: 200px;
  1381. }
  1382. }
  1383. }
  1384. }
  1385. .cases-section {
  1386. padding: 40px 0;
  1387. .section-header {
  1388. margin-bottom: 40px;
  1389. .section-title {
  1390. font-size: 32px;
  1391. }
  1392. }
  1393. .cases-carousel {
  1394. gap: 15px;
  1395. }
  1396. .nav-arrow {
  1397. width: 50px;
  1398. height: 50px;
  1399. .arrow-icon {
  1400. width: 20px;
  1401. height: 20px;
  1402. }
  1403. }
  1404. .case-item {
  1405. flex: 0 0 100%;
  1406. padding: 0 10px;
  1407. .case-image {
  1408. height: 180px;
  1409. margin-bottom: 15px;
  1410. }
  1411. .case-content {
  1412. padding: 20px;
  1413. .case-title {
  1414. font-size: 18px;
  1415. margin-bottom: 12px;
  1416. }
  1417. .case-description {
  1418. font-size: 13px;
  1419. }
  1420. }
  1421. }
  1422. }
  1423. .about-section {
  1424. padding: 40px 0;
  1425. .section-header {
  1426. margin-bottom: 40px;
  1427. .section-title {
  1428. font-size: 32px;
  1429. }
  1430. }
  1431. .about-tabs {
  1432. flex-direction: column;
  1433. gap: 2px;
  1434. margin-bottom: 30px;
  1435. .tab-item {
  1436. flex: none;
  1437. border-radius: 8px !important;
  1438. border: 2px solid #E5E5E5 !important;
  1439. margin-bottom: 2px;
  1440. font-size: 16px;
  1441. height: 50px;
  1442. line-height: 50px;
  1443. }
  1444. }
  1445. .about-detail {
  1446. padding: 25px 20px;
  1447. margin: 0 15px;
  1448. }
  1449. .detail-content {
  1450. flex-direction: column;
  1451. gap: 25px;
  1452. .content-left {
  1453. flex: none;
  1454. width: 100%;
  1455. img {
  1456. height: 200px;
  1457. }
  1458. }
  1459. .content-right {
  1460. .content-title {
  1461. font-size: 24px;
  1462. margin-bottom: 20px;
  1463. }
  1464. .content-description {
  1465. font-size: 15px;
  1466. margin-bottom: 25px;
  1467. }
  1468. .content-action {
  1469. text-align: center;
  1470. .learn-more-btn {
  1471. padding: 10px 25px;
  1472. font-size: 15px;
  1473. }
  1474. }
  1475. }
  1476. }
  1477. }
  1478. .cooperation-section {
  1479. padding: 40px 0;
  1480. .section-header {
  1481. margin-bottom: 40px;
  1482. .section-title {
  1483. font-size: 32px;
  1484. }
  1485. }
  1486. .partners-grid {
  1487. gap: 20px;
  1488. margin: 0 20px;
  1489. .partner-item {
  1490. width: calc(50% - 10px);
  1491. height: 80px;
  1492. padding: 15px;
  1493. img {
  1494. max-height: 50px;
  1495. }
  1496. }
  1497. }
  1498. }
  1499. }
  1500. </style>