Hanye官网
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167
  1. <template>
  2. <div>
  3. <div class="w-full h-[88px] md:h-[0]"></div>
  4. <!-- 轮播图 -->
  5. <section class="max-w-full mb-12 md:mb-32 xl:px-8 lg:px-6 md:px-4 px-4">
  6. <Swiper
  7. :modules="[Pagination, Autoplay, EffectCreative]"
  8. :slides-per-view="1"
  9. :space-between="30"
  10. :loop="true"
  11. :pagination="{ el: '.swiper-pagination-1', clickable: true }"
  12. :autoplay="{
  13. delay: 5000,
  14. disableOnInteraction: false,
  15. pauseOnMouseEnter: true,
  16. waitForTransition: true,
  17. }"
  18. effect="creative"
  19. :creativeEffect="{
  20. prev: {
  21. shadow: true,
  22. translate: ['-120%', 0, -500],
  23. rotate: [0, 0, -90],
  24. opacity: 0,
  25. },
  26. next: {
  27. shadow: true,
  28. translate: ['120%', 0, -500],
  29. rotate: [0, 0, 90],
  30. opacity: 0,
  31. },
  32. }"
  33. :speed="1000"
  34. :grabCursor="true"
  35. :parallax="true"
  36. class="h-[320px] sm:h-[320px] md:h-[768px] lg:h-[900px] swiper-container-1"
  37. >
  38. <SwiperSlide>
  39. <div
  40. class="max-w-screen-2xl mx-auto h-full relative"
  41. :style="{
  42. backgroundImage: `url(${homeA1Webp})`,
  43. backgroundSize: 'cover',
  44. backgroundPosition: 'center',
  45. backgroundRepeat: 'no-repeat',
  46. }"
  47. >
  48. <div
  49. class="w-full h-full flex-col justify-center hidden md:flex relative z-10"
  50. >
  51. <div
  52. class="rounded border border-white w-11 h-6 leading-none justify-center flex items-center text-white text-sm font-normal"
  53. >
  54. SSD
  55. </div>
  56. <div class="justify-center">
  57. <span class="text-white text-6xl font-normal leading-[78px]">{{
  58. t("home.carousel.one.title")
  59. }}</span>
  60. <span class="text-white text-6xl font-normal leading-[78px]">{{
  61. t("home.carousel.one.description")
  62. }}</span>
  63. <br />
  64. <span class="text-white text-6xl font-normal leading-[78px]">{{
  65. t("home.carousel.one.description2")
  66. }}</span
  67. ><br />
  68. <span
  69. class="text-cyan-400 text-6xl font-normal leading-[78px]"
  70. >{{ t("home.carousel.one.description3") }}</span
  71. >
  72. </div>
  73. <div class="flex flex-col gap-2 mt-4">
  74. <div
  75. class="flex items-center gap-2 text-stone-50 text-xl font-normal"
  76. >
  77. <div class="w-2 h-2 bg-white rounded-full"></div>
  78. {{ t("home.carousel.one.description4") }}
  79. </div>
  80. <div
  81. class="flex items-center gap-2 text-stone-50 text-xl font-normal"
  82. >
  83. <div class="w-2 h-2 bg-white rounded-full"></div>
  84. {{ t("home.carousel.one.description5") }}
  85. </div>
  86. </div>
  87. <div
  88. class="w-36 h-14 mt-12 flex items-center justify-center bg-[#35F1FF] rounded-lg hover:bg-[#35F1FF]/80 transition-colors duration-300"
  89. >
  90. <nuxt-link
  91. :to="`${homepagePath}/products/HE80-2TNLHS`"
  92. class="w-full h-full !flex items-center justify-center text-zinc-900"
  93. >
  94. {{ t("products.view_details") }}
  95. </nuxt-link>
  96. </div>
  97. </div>
  98. </div>
  99. </SwiperSlide>
  100. <SwiperSlide>
  101. <div
  102. class="max-w-screen-2xl mx-auto h-full relative"
  103. :style="{
  104. backgroundImage: `url(${homeA2Webp})`,
  105. backgroundSize: 'cover',
  106. backgroundPosition: 'center',
  107. backgroundRepeat: 'no-repeat',
  108. }"
  109. >
  110. <div
  111. class="w-full h-full flex-col justify-center hidden md:flex relative z-10"
  112. >
  113. <div class="justify-center">
  114. <span class="text-white text-6xl font-normal leading-[78px]">{{
  115. t("home.carousel.two.title")
  116. }}</span>
  117. <span class="text-white text-6xl font-normal leading-[78px]">{{
  118. t("home.carousel.two.description")
  119. }}</span>
  120. <br />
  121. <span class="text-white text-6xl font-normal leading-[78px]">{{
  122. t("home.carousel.two.description2")
  123. }}</span
  124. ><br />
  125. <span
  126. class="text-cyan-400 text-6xl font-normal leading-[78px]"
  127. >{{ t("home.carousel.two.description3") }}</span
  128. >
  129. </div>
  130. <div class="flex flex-col gap-2 mt-4">
  131. <div
  132. class="flex items-center gap-2 text-stone-50 text-xl font-normal"
  133. >
  134. <div class="w-2 h-2 bg-white rounded-full"></div>
  135. {{ t("home.carousel.two.description4") }}
  136. </div>
  137. <div
  138. class="flex items-center gap-2 text-stone-50 text-xl font-normal"
  139. >
  140. <div class="w-2 h-2 bg-white rounded-full"></div>
  141. {{ t("home.carousel.two.description5") }}
  142. </div>
  143. </div>
  144. <div
  145. class="w-36 h-14 mt-12 flex items-center justify-center bg-[#35F1FF] rounded-lg hover:bg-[#35F1FF]/80 transition-colors duration-300"
  146. >
  147. <nuxt-link
  148. :to="`${homepagePath}/products`"
  149. class="w-full h-full !flex items-center justify-center text-zinc-900"
  150. >
  151. {{ t("products.view_details") }}
  152. </nuxt-link>
  153. </div>
  154. </div>
  155. </div>
  156. </SwiperSlide>
  157. <SwiperSlide v-if="!isMobile">
  158. <div class="max-w-screen-2xl mx-auto h-full relative">
  159. <video
  160. :src="homeA3Webp"
  161. autoplay
  162. muted
  163. loop
  164. class="w-full h-full object-cover"
  165. ></video>
  166. <div
  167. class="w-full h-full flex-col justify-center hidden md:flex absolute top-0 left-0 z-10"
  168. >
  169. <div class="justify-center">
  170. <span class="text-white text-6xl font-normal leading-[78px]">{{
  171. t("home.carousel.three.title")
  172. }}</span>
  173. <span class="text-white text-6xl font-normal leading-[78px]">{{
  174. t("home.carousel.three.description")
  175. }}</span>
  176. <br />
  177. <span class="text-white text-6xl font-normal leading-[78px]">{{
  178. t("home.carousel.three.description2")
  179. }}</span
  180. ><br />
  181. <span
  182. class="text-cyan-400 text-6xl font-normal leading-[78px]"
  183. >{{ t("home.carousel.three.description3") }}</span
  184. >
  185. </div>
  186. <div class="flex flex-col gap-2 mt-4">
  187. <div
  188. class="flex items-center gap-2 text-stone-50 text-xl font-normal"
  189. >
  190. <div class="w-2 h-2 bg-white rounded-full"></div>
  191. {{ t("home.carousel.three.description4") }}
  192. </div>
  193. <div
  194. class="flex items-center gap-2 text-stone-50 text-xl font-normal"
  195. >
  196. <div class="w-2 h-2 bg-white rounded-full"></div>
  197. {{ t("home.carousel.three.description5") }}
  198. </div>
  199. </div>
  200. <div
  201. class="w-36 h-14 mt-12 flex items-center justify-center bg-[#35F1FF] rounded-lg hover:bg-[#35F1FF]/80 transition-colors duration-300"
  202. >
  203. <nuxt-link
  204. :to="`${homepagePath}/about`"
  205. class="w-full h-full !flex items-center justify-center text-zinc-900"
  206. >
  207. {{ t("products.view_details") }}
  208. </nuxt-link>
  209. </div>
  210. </div>
  211. </div>
  212. </SwiperSlide>
  213. <div class="max-w-screen-2xl mx-auto relative">
  214. <div
  215. class="swiper-pagination swiper-pagination-1 text-left bottom-1 top-0"
  216. ></div>
  217. </div>
  218. </Swiper>
  219. </section>
  220. <!-- 按用途产品展示 -->
  221. <section class="max-w-full mb-12 md:mb-32 xl:px-8 lg:px-6 md:px-4 px-4">
  222. <div class="max-w-screen-2xl mx-auto relative">
  223. <div
  224. class="justify-center text-cyan-400 text-base font-normal leading-tight mb-4"
  225. >
  226. {{ t("products.usage") }}
  227. </div>
  228. <div
  229. class="justify-center text-white font-normal mb-8 md:mb-16 text-xl sm:text-2xl md:text-4xl lg:text-6xl"
  230. >
  231. {{ t("products.usage_title") }}
  232. </div>
  233. </div>
  234. <div class="max-w-screen-2xl mx-auto">
  235. <div class="w-full mb-8">
  236. <div class="flex flex-wrap items-center gap-2">
  237. <div
  238. v-for="(usage, index) in typedUsageList"
  239. :key="usage.id"
  240. class="cursor-pointer select-none px-4 sm:px-7 py-2 sm:py-3 rounded-full border border-zinc-700 text-white transition-all duration-300 relative group"
  241. :class="{
  242. 'bg-gradient-to-r from-blue-700 to-blue-400 text-white border-zinc-900 pointer-events-none':
  243. activeIndex === index,
  244. 'hover:border-zinc-600': activeIndex !== index,
  245. }"
  246. @click="handleUsageClick(usage.id)"
  247. >
  248. <div
  249. class="usage-name text-center text-xs sm:text-sm font-normal leading-tight md:text-base transition-colors duration-300 relative z-10"
  250. >
  251. {{ usage.name }}
  252. <!-- 用途名称 -->
  253. </div>
  254. <div
  255. class="absolute inset-0 rounded-full bg-cyan-400/20 scale-0 transition-transform duration-300 group-hover:scale-100"
  256. ></div>
  257. </div>
  258. <div class="flex items-center justify-center gap-4 ml-auto">
  259. <div
  260. class="swiper-button-prev-2 bg-zinc-700 w-8 h-8 sm:w-10 sm:h-10 rounded-full flex items-center justify-center cursor-pointer hover:bg-zinc-600 transition-colors duration-200"
  261. >
  262. <i
  263. class="icon-arrow-left text-zinc-300 text-xs sm:text-sm font-normal"
  264. ></i>
  265. </div>
  266. <div
  267. class="swiper-button-next-2 bg-zinc-700 w-8 h-8 sm:w-10 sm:h-10 rounded-full flex items-center justify-center cursor-pointer hover:bg-zinc-600 transition-colors duration-200"
  268. >
  269. <i
  270. class="icon-arrow-right text-zinc-300 text-xs sm:text-sm font-normal"
  271. ></i>
  272. </div>
  273. </div>
  274. </div>
  275. </div>
  276. </div>
  277. <div class="max-w-screen-2xl mx-auto">
  278. <div
  279. class="w-full h-[380px] sm:h-[300px] md:h-[350px] lg:h-[360px] xl:h-[380px] 2xl:h-[460px] relative"
  280. >
  281. <TransitionGroup name="slide-fade" tag="div" class="relative h-full">
  282. <div :key="activeUsageId" class="w-full h-full">
  283. <Swiper
  284. :modules="[Navigation]"
  285. :spaceBetween="30"
  286. :slidesPerView="4"
  287. :breakpoints="{
  288. 320: { slidesPerView: 1, spaceBetween: 10 },
  289. 448: { slidesPerView: 2, spaceBetween: 10 },
  290. 640: { slidesPerView: 3, spaceBetween: 20 },
  291. 1024: { slidesPerView: 4, spaceBetween: 20 },
  292. 1280: { slidesPerView: 4, spaceBetween: 30 },
  293. 1536: { slidesPerView: 4, spaceBetween: 30 },
  294. }"
  295. :navigation="{
  296. prevEl: '.swiper-button-prev-2',
  297. nextEl: '.swiper-button-next-2',
  298. }"
  299. class="h-full"
  300. >
  301. <SwiperSlide
  302. v-for="product in activeProducts"
  303. :key="product.id"
  304. class="w-full sm:w-1/2 md:w-1/3 lg:w-1/4"
  305. >
  306. <div class="w-full h-full p-2">
  307. <nuxt-link :to="product.link" class="block w-full h-full">
  308. <div
  309. class="w-full h-full bg-zinc-900 rounded-2xl p-4 flex flex-col items-center justify-start relative overflow-hidden group hover:bg-zinc-800 transition-all duration-300 hover:shadow-lg hover:shadow-cyan-400/10"
  310. >
  311. <!-- 图片加载占位 -->
  312. <div
  313. v-if="!isImageLoaded[product.id]"
  314. class="absolute inset-0 bg-gradient-to-br from-zinc-800 via-zinc-700 to-zinc-800 animate-gradient"
  315. >
  316. <div
  317. class="absolute inset-0 flex items-center justify-center"
  318. >
  319. <div
  320. class="w-8 h-8 border-4 border-cyan-400/20 border-t-cyan-400 rounded-full animate-spin"
  321. ></div>
  322. </div>
  323. </div>
  324. <!-- 图片容器 -->
  325. <div
  326. class="w-full aspect-square relative transition-all duration-300 overflow-hidden rounded-lg"
  327. :class="{ 'opacity-0': !isImageLoaded[product.id] }"
  328. >
  329. <img
  330. :src="product.image"
  331. :alt="product.title"
  332. class="w-full h-full object-cover transition-all duration-500 group-hover:scale-110"
  333. @load="handleImageLoad(product.id)"
  334. @error="handleImageError(product.id)"
  335. loading="lazy"
  336. />
  337. <div
  338. class="absolute inset-0 bg-gradient-to-t from-black/60 via-black/20 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300"
  339. ></div>
  340. <!-- 添加查看详情按钮 -->
  341. <div
  342. class="absolute inset-0 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-all duration-300 transform translate-y-4 group-hover:translate-y-0"
  343. >
  344. <div
  345. class="px-4 py-2 bg-cyan-400/20 backdrop-blur-sm rounded-full text-white text-sm font-medium border border-cyan-400/30 transform transition-transform duration-300 group-hover:scale-105"
  346. >
  347. {{ t("products.view_details") }}
  348. </div>
  349. </div>
  350. </div>
  351. <!-- 文字内容 -->
  352. <div
  353. class="w-full mt-4 min-h-[80px] transition-all duration-300 transform"
  354. :class="{
  355. 'opacity-0 translate-y-4':
  356. !isImageLoaded[product.id],
  357. 'opacity-100 translate-y-0':
  358. isImageLoaded[product.id],
  359. }"
  360. >
  361. <div
  362. class="text-center text-white text-base font-bold leading-tight mb-2 line-clamp-2 group-hover:text-cyan-400 transition-colors duration-300"
  363. >
  364. {{ product.title }}
  365. </div>
  366. <div
  367. class="text-center text-zinc-400 text-sm font-normal leading-tight line-clamp-2 group-hover:text-zinc-300 transition-colors duration-300"
  368. >
  369. {{ product.description }}
  370. </div>
  371. </div>
  372. </div>
  373. </nuxt-link>
  374. </div>
  375. </SwiperSlide>
  376. </Swiper>
  377. </div>
  378. </TransitionGroup>
  379. </div>
  380. </div>
  381. </section>
  382. <!-- 按分类栏目展示 -->
  383. <section class="max-w-full mb-12 md:mb-32 xl:px-8 lg:px-6 md:px-4 px-4">
  384. <div class="max-w-screen-2xl mx-auto relative">
  385. <div
  386. class="justify-center text-cyan-400 text-base font-normal leading-tight mb-4"
  387. >
  388. {{ t("home.useCategoryTitle") }}
  389. </div>
  390. <div
  391. class="justify-center text-white font-normal mb-8 md:mb-16 text-xl sm:text-2xl md:text-4xl lg:text-6xl"
  392. >
  393. {{ t("home.useCategoryDescription") }}
  394. </div>
  395. </div>
  396. <div class="max-w-screen-2xl mx-auto">
  397. <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
  398. <nuxt-link
  399. v-for="category in typedCategoryList"
  400. :key="category.id"
  401. :to="category.link"
  402. class="bg-zinc-950/10 backdrop-blur-[50px] border border-white/10 rounded-lg flex gap-8 p-4 sm:p-8 justify-between category-item group hover:border-cyan-400/30 transition-all duration-300"
  403. >
  404. <div class="col-span-1 flex flex-col gap-4">
  405. <div
  406. class="flex flex-col gap-2 opacity-80 group-hover:opacity-100 transition-opacity duration-300"
  407. >
  408. <div
  409. v-for="capacitie in category.capacities"
  410. :key="capacitie"
  411. class="text-white text-sm md:text-base font-normal leading-tight flex gap-2 items-center group-hover:text-cyan-400 transition-colors duration-300"
  412. >
  413. <i
  414. class="icon-star text-sm group-hover:scale-110 transition-transform duration-300"
  415. ></i>
  416. <span>{{ capacitie }}</span>
  417. </div>
  418. </div>
  419. <div
  420. class="p-2 sm:p-4 mt-auto bg-zinc-500/20 rounded-lg outline outline-1 outline-offset-[-1px] outline-white/10 backdrop-blur-xl inline-flex justify-center items-center gap-3 overflow-hidden group-hover:bg-cyan-400/10 group-hover:outline-cyan-400/30 transition-all duration-300"
  421. >
  422. <div
  423. class="justify-start text-neutral-200 text-xs md:text-sm font-medium uppercase leading-relaxed group-hover:text-cyan-400 transition-colors duration-300"
  424. >
  425. {{ category.title }}
  426. </div>
  427. </div>
  428. </div>
  429. <div
  430. class="w-32 h-32 md:w-44 md:h-44 relative overflow-hidden rounded-lg"
  431. >
  432. <img
  433. :src="category.image"
  434. :alt="category.title"
  435. class="w-full h-full object-contain transition-transform duration-500 group-hover:scale-110"
  436. />
  437. </div>
  438. </nuxt-link>
  439. </div>
  440. </div>
  441. </section>
  442. <!-- 核心展示 -->
  443. <section class="max-w-full mb-12 md:mb-32 xl:px-8 lg:px-6 md:px-4 px-4">
  444. <div
  445. class="max-w-screen-2xl mx-auto grid grid-cols-1 lg:grid-cols-3 md:grid-cols-2 sm:grid-cols-1 gap-4"
  446. >
  447. <div class="inline-flex justify-start items-center gap-5">
  448. <div
  449. class="w-12 h-12 md:w-16 md:h-16 relative bg-gradient-to-b from-neutral-600 to-slate-400 rounded-xl border-b-[1.50px] border-neutral-700 overflow-hidden"
  450. >
  451. <div class="w-full h-full flex items-center justify-center">
  452. <i class="icon-h1 text-white text-5xl"></i>
  453. </div>
  454. </div>
  455. <div class="inline-flex flex-col justify-center items-start flex-1">
  456. <div
  457. class="justify-start text-white font-medium text-1xl md:text-lg"
  458. >
  459. {{ t("products.support") }}
  460. </div>
  461. <div
  462. class="justify-start text-zinc-300 text-xs font-normal md:text-sm"
  463. >
  464. {{ t("products.support_description") }}
  465. </div>
  466. </div>
  467. </div>
  468. <div class="inline-flex justify-start items-center gap-5">
  469. <div
  470. class="w-12 h-12 md:w-16 md:h-16 relative bg-gradient-to-b from-neutral-600 to-slate-400 rounded-xl border-b-[1.50px] border-neutral-700 overflow-hidden"
  471. >
  472. <div class="w-full h-full flex items-center justify-center">
  473. <i class="icon-h2 text-white text-5xl"></i>
  474. </div>
  475. </div>
  476. <div class="inline-flex flex-col justify-center items-start flex-1">
  477. <div
  478. class="justify-start text-white font-medium text-1xl md:text-lg"
  479. >
  480. {{ t("products.development") }}
  481. </div>
  482. <div
  483. class="justify-start text-zinc-300 text-xs font-normal md:text-sm"
  484. >
  485. {{ t("products.development_description") }}
  486. </div>
  487. </div>
  488. </div>
  489. <div class="inline-flex justify-start items-center gap-5">
  490. <div
  491. class="w-12 h-12 md:w-16 md:h-16 relative bg-gradient-to-b from-neutral-600 to-slate-400 rounded-xl border-b-[1.50px] border-neutral-700 overflow-hidden"
  492. >
  493. <div class="w-full h-full flex items-center justify-center">
  494. <i class="icon-h3 text-white text-5xl"></i>
  495. </div>
  496. </div>
  497. <div class="inline-flex flex-col justify-center items-start flex-1">
  498. <div
  499. class="justify-start text-white font-medium text-1xl md:text-lg"
  500. >
  501. {{ t("products.develop") }}
  502. </div>
  503. <div
  504. class="justify-start text-zinc-300 text-xs font-normal md:text-sm"
  505. >
  506. {{ t("products.develop_description") }}
  507. </div>
  508. </div>
  509. </div>
  510. </div>
  511. </section>
  512. <!-- 关于我们 -->
  513. <section class="max-w-full mb-12 md:mb-32 xl:px-8 lg:px-6 md:px-4 px-4">
  514. <div class="max-w-screen-2xl mx-auto relative">
  515. <div
  516. class="justify-center text-cyan-400 text-base font-normal leading-tight mb-4"
  517. >
  518. {{ t("products.strong_point") }}
  519. </div>
  520. <div
  521. class="justify-center text-white font-normal mb-8 md:mb-16 text-xl sm:text-2xl md:text-4xl lg:text-6xl"
  522. >
  523. {{ t("products.strong_point_title") }}
  524. </div>
  525. <div
  526. class="absolute right-0 top-1/2 -translate-y-1/2 z-10 lg:block hidden"
  527. >
  528. <div class="flex items-center justify-center gap-4">
  529. <div
  530. class="swiper-button-prev-3 bg-zinc-700 w-10 h-10 rounded-full flex items-center justify-center cursor-pointer hover:bg-zinc-600 transition-colors duration-200"
  531. >
  532. <i class="icon-arrow-left text-zinc-300 text-sm font-normal"></i>
  533. </div>
  534. <div
  535. class="swiper-button-next-3 bg-zinc-700 w-10 h-10 rounded-full flex items-center justify-center cursor-pointer hover:bg-zinc-600 transition-colors duration-200"
  536. >
  537. <i class="icon-arrow-right text-zinc-300 text-sm font-normal"></i>
  538. </div>
  539. </div>
  540. </div>
  541. </div>
  542. <div class="max-w-screen-2xl mx-auto">
  543. <div class="w-full relative max-w-full">
  544. <Swiper
  545. :modules="[Navigation, Pagination]"
  546. slides-per-view="auto"
  547. :space-between="30"
  548. :pagination="{ el: '.swiper-pagination-3', clickable: true }"
  549. :navigation="{
  550. prevEl: '.swiper-button-prev-3',
  551. nextEl: '.swiper-button-next-3',
  552. }"
  553. class="h-[320px] sm:h-[320px] md:h-[480px] lg:h-[720px] max-w-full"
  554. >
  555. <SwiperSlide class="!max-w-screen-2xl !w-full">
  556. <div
  557. class="w-full h-full flex items-center px-0 md:px-20"
  558. :style="{
  559. backgroundImage: `url(${homeC1Webp})`,
  560. backgroundSize: 'cover',
  561. backgroundPosition: 'center',
  562. backgroundRepeat: 'no-repeat',
  563. }"
  564. >
  565. <div
  566. class="w-full lg:w-[50%] h-full md:h-auto bg-white/5 rounded-0 md:rounded-2xl backdrop-blur-[50px] px-4 py-8 md:py-12 md:px-8 flex flex-col gap-8 border border-white/10"
  567. >
  568. <div
  569. class="opacity-90 justify-start text-white text-2xl font-normal md:text-4xl"
  570. >
  571. {{ t("about.companyInfo.name") }}
  572. </div>
  573. <div
  574. class="opacity-70 justify-start text-white text-base md:text-lg font-normal leading-relaxed whitespace-pre-wrap"
  575. >
  576. {{ t("about.companyInfo.description") }}
  577. </div>
  578. </div>
  579. </div>
  580. </SwiperSlide>
  581. </Swiper>
  582. </div>
  583. <div class="max-w-screen-2xl mx-auto relative">
  584. <div class="swiper-pagination swiper-pagination-3"></div>
  585. </div>
  586. </div>
  587. </section>
  588. <!-- 产品咨询 -->
  589. <section class="max-w-full h-[240px] md:h-[480px] bg-black/80 md:block">
  590. <div class="h-full relative">
  591. <div
  592. class="absolute top-0 left-0 w-full h-full flex flex-col gap-6 items-center justify-center z-10"
  593. >
  594. <h1
  595. class="text-center justify-start text-white font-normal text-xl sm:text-2xl md:text-3xl px-2"
  596. >
  597. {{ t("products.consultation") }}
  598. </h1>
  599. <nuxt-link
  600. :to="`${homepagePath}/contact`"
  601. class="w-32 h-10 md:w-40 md:h-11 bg-zinc-300/10 rounded-lg outline outline-1 flex items-center justify-center gap-2 outline-white/20 backdrop-blur-[10px] cursor-pointer hover:bg-zinc-300/20 transition-colors duration-200"
  602. >
  603. <span class="text-xs md:text-sm font-normal">{{
  604. t("products.consultation_button")
  605. }}</span>
  606. <i class="icon-arrow-right text-sm font-normal"></i>
  607. </nuxt-link>
  608. </div>
  609. <img
  610. v-if="isMobile"
  611. :src="videoWebp"
  612. alt="video"
  613. class="w-full h-full object-cover opacity-20"
  614. />
  615. <video
  616. v-else
  617. :src="videoSrc"
  618. autoplay
  619. muted
  620. loop
  621. :poster="videoWebp"
  622. class="w-full h-full object-cover opacity-20"
  623. ></video>
  624. </div>
  625. </section>
  626. </div>
  627. </template>
  628. <script setup lang="ts">
  629. import { Swiper, SwiperSlide } from "swiper/vue";
  630. import {
  631. Navigation,
  632. Pagination,
  633. Autoplay,
  634. EffectCreative,
  635. } from "swiper/modules";
  636. import "swiper/css";
  637. import "swiper/css/navigation";
  638. import "swiper/css/pagination";
  639. import { useBreakpoints, breakpointsTailwind } from "@vueuse/core";
  640. import { useI18n, useRoute, useAsyncData, queryCollection } from "#imports";
  641. import video from "@/assets/videos/video.mp4";
  642. import videoWebp from "@/assets/videos/video.webp";
  643. import homeA1Webp from "@/assets/images/home-a-1.webp";
  644. import homeA2Webp from "@/assets/images/home-a-2.webp";
  645. import homeA3Webp from "@/assets/videos/banner03.mp4";
  646. import homeC1Webp from "@/assets/images/home-c-1.webp";
  647. // 数据类型定义
  648. interface Product {
  649. id: number;
  650. title: string;
  651. image: string;
  652. link: string;
  653. description?: string;
  654. }
  655. interface Usage {
  656. id: number;
  657. name: string;
  658. category?: string;
  659. products: Product[];
  660. }
  661. interface Category {
  662. id: number;
  663. title: string;
  664. description: string;
  665. capacities: string[];
  666. summary: string;
  667. sort: number;
  668. image: string;
  669. link: string;
  670. }
  671. // 使用i18n
  672. const { t, locale } = useI18n();
  673. // 默认语言
  674. const defaultLocale = "zh";
  675. // 获取路由
  676. const route = useRoute();
  677. // 断点
  678. const breakpoints = useBreakpoints(breakpointsTailwind);
  679. // 是否移动端
  680. const isMobile = breakpoints.smaller("md");
  681. const videoSrc = ref(video);
  682. /**
  683. * 使用计算属性获取当前语言的数据文件URL
  684. */
  685. const usageDataUrl = computed(() => {
  686. return `/data/usages-${locale.value}.json`;
  687. });
  688. const categoryDataUrl = computed(() => {
  689. return `/data/categories-${locale.value}.json`;
  690. });
  691. const productsDataUrl = computed(() => {
  692. return `/data/products-${locale.value}.json`;
  693. });
  694. const homepagePath = computed(() => {
  695. return locale.value === "zh" ? "" : `/${locale.value}`;
  696. });
  697. // 获取按用途产品数据
  698. const usageList = ref<Usage[]>([]);
  699. const isLoadingUsage = ref(true);
  700. const activeUsageId = ref(1);
  701. // 获取按分类栏目数据
  702. const categoryList = ref<Category[]>([]);
  703. const isLoadingCategory = ref(true);
  704. // 加载用途数据
  705. const loadUsageData = async () => {
  706. try {
  707. isLoadingUsage.value = true;
  708. // 使用fetch获取数据
  709. if (process.client) {
  710. const response = await fetch(usageDataUrl.value);
  711. if (!response.ok) {
  712. throw new Error(`加载用途数据失败: ${response.status}`);
  713. }
  714. const usageData = await response.json();
  715. // 加载对应的产品数据
  716. const productsResponse = await fetch(productsDataUrl.value);
  717. if (!productsResponse.ok) {
  718. throw new Error(`加载产品数据失败: ${productsResponse.status}`);
  719. }
  720. const productsData = await productsResponse.json();
  721. // 处理数据
  722. usageList.value = usageData
  723. .map((usage: any) => {
  724. // 为每种用途找到对应的产品
  725. const usageProducts = [];
  726. // 按照正确的设计模式:使用用途的title与产品的usage数组进行匹配
  727. // 找出所有usage属性包含当前用途title的产品
  728. const matchedProducts = productsData.filter(
  729. (product: any) =>
  730. product.usage &&
  731. Array.isArray(product.usage) &&
  732. product.usage.includes(usage.title)
  733. );
  734. // 将匹配的产品添加到列表
  735. if (matchedProducts.length > 0) {
  736. matchedProducts.forEach((product: any) => {
  737. usageProducts.push({
  738. id: product.id,
  739. title: product.title,
  740. image: product.image,
  741. link: `${homepagePath.value}/products/${product.id}`,
  742. description: product.summary,
  743. });
  744. });
  745. } else {
  746. // 如果没有找到匹配的产品,添加一个占位产品
  747. usageProducts.push({
  748. id: `placeholder-${usage.id}`,
  749. title: usage.title,
  750. image: ``,
  751. link: `${homepagePath.value}/products?usage=${encodeURIComponent(
  752. usage.title
  753. )}`,
  754. description: "",
  755. });
  756. }
  757. return {
  758. id: parseInt(usage.id) || 0,
  759. name: usage.title,
  760. category: usage.category || "",
  761. products: usageProducts,
  762. };
  763. })
  764. .sort((a: any, b: any) => a.id - b.id);
  765. // 设置默认选中的用途
  766. if (usageList.value.length > 0) {
  767. activeUsageId.value = usageList.value[0].id;
  768. }
  769. }
  770. } catch (error) {
  771. console.error("Error loading usage data:", error);
  772. } finally {
  773. isLoadingUsage.value = false;
  774. }
  775. };
  776. // 加载分类数据
  777. const loadCategoryData = async () => {
  778. try {
  779. isLoadingCategory.value = true;
  780. // 使用fetch获取数据
  781. if (process.client) {
  782. const response = await fetch(categoryDataUrl.value);
  783. if (!response.ok) {
  784. throw new Error(`加载分类数据失败: ${response.status}`);
  785. }
  786. const data = await response.json();
  787. // 处理数据
  788. categoryList.value = data
  789. .map((category: any) => {
  790. return {
  791. id: parseInt(category.id) || 0,
  792. title: category.title || "",
  793. description: category.description || "",
  794. image: category.image || "",
  795. link: `${homepagePath.value}/products?category=${encodeURIComponent(
  796. category.title
  797. )}`,
  798. capacities: category.capacities || [],
  799. summary: category.summary || "",
  800. sort: category.sort || 0,
  801. };
  802. })
  803. .sort((a: any, b: any) => a.id - b.id);
  804. }
  805. } catch (error) {
  806. console.error("Error loading category data:", error);
  807. } finally {
  808. isLoadingCategory.value = false;
  809. }
  810. };
  811. // 当页面加载或语言改变时加载数据
  812. onMounted(() => {
  813. loadUsageData();
  814. loadCategoryData();
  815. });
  816. watch(locale, () => {
  817. loadUsageData();
  818. loadCategoryData();
  819. });
  820. // 计算当前用途列表
  821. const typedUsageList = computed(() => {
  822. return usageList.value as Usage[];
  823. });
  824. // 计算当前激活的索引
  825. const activeIndex = computed(() => {
  826. return typedUsageList.value.findIndex(
  827. (item) => item.id === activeUsageId.value
  828. );
  829. });
  830. const activeProducts = computed(() => {
  831. const currentUsage = typedUsageList.value.find(
  832. (item: Usage) => item.id === activeUsageId.value
  833. );
  834. return currentUsage?.products || [];
  835. });
  836. // 图片加载状态
  837. const isImageLoaded = ref<Record<number, boolean>>({});
  838. const imageErrors = ref<Record<number, boolean>>({});
  839. // 监听图片加载状态
  840. watch(
  841. activeProducts,
  842. (newProducts: Product[]) => {
  843. if (process.client) {
  844. newProducts.forEach((product: Product) => {
  845. if (product.image) {
  846. const img = new window.Image();
  847. img.onload = () => handleImageLoad(product.id);
  848. img.onerror = () => handleImageError(product.id);
  849. img.src = product.image;
  850. }
  851. });
  852. }
  853. },
  854. { immediate: true }
  855. );
  856. // 处理图片加载
  857. const handleImageLoad = (id: number) => {
  858. if (process.client) {
  859. isImageLoaded.value[id] = true;
  860. imageErrors.value[id] = false;
  861. }
  862. };
  863. // 处理图片加载错误
  864. const handleImageError = (id: number) => {
  865. if (process.client) {
  866. console.error(`Failed to load image for product ${id}`);
  867. isImageLoaded.value[id] = true;
  868. imageErrors.value[id] = true;
  869. }
  870. };
  871. // 处理用途点击
  872. const handleUsageClick = (id: number) => {
  873. if (process.client) {
  874. // 重置图片加载状态
  875. isImageLoaded.value = {};
  876. imageErrors.value = {};
  877. activeUsageId.value = id;
  878. }
  879. };
  880. // 计算当前分类列表
  881. const typedCategoryList = computed(() => {
  882. return categoryList.value as Category[];
  883. });
  884. // SEO优化
  885. useHead({
  886. title: t("home.title") + " - Hanye",
  887. meta: [
  888. {
  889. name: "description",
  890. content: t("home.description"),
  891. },
  892. {
  893. name: "keywords",
  894. content: t("home.keywords"),
  895. },
  896. ],
  897. });
  898. </script>
  899. <style lang="scss" scoped>
  900. :deep(.swiper-pagination-3) {
  901. margin: auto;
  902. position: static;
  903. padding: 1rem 0;
  904. }
  905. :deep(.swiper-pagination-bullet) {
  906. background-color: var(--color-bg); /* Example color */
  907. border: 2px solid var(--color-text);
  908. }
  909. :deep(.swiper-pagination-bullet-active) {
  910. background-color: var(--color-text); /* Example color */
  911. }
  912. .category-item {
  913. background-image: url("@/assets/images/home-b-1.webp");
  914. background-size: cover;
  915. background-position: center;
  916. background-repeat: no-repeat;
  917. opacity: 0.8;
  918. transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  919. position: relative;
  920. overflow: hidden;
  921. &:hover {
  922. opacity: 1;
  923. transform: translateY(-2px);
  924. box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
  925. &::before {
  926. opacity: 1;
  927. }
  928. }
  929. &::before {
  930. content: "";
  931. position: absolute;
  932. inset: 0;
  933. background: linear-gradient(45deg, rgba(6, 182, 212, 0.1), transparent);
  934. opacity: 0;
  935. transition: opacity 0.3s ease;
  936. pointer-events: none;
  937. }
  938. }
  939. // 优化过渡动画
  940. .slide-fade-enter-active,
  941. .slide-fade-leave-active {
  942. transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  943. position: absolute;
  944. width: 100%;
  945. height: 300px;
  946. }
  947. @media (min-width: 640px) {
  948. .slide-fade-enter-active,
  949. .slide-fade-leave-active {
  950. height: 350px;
  951. }
  952. }
  953. @media (min-width: 768px) {
  954. .slide-fade-enter-active,
  955. .slide-fade-leave-active {
  956. height: 400px;
  957. }
  958. }
  959. @media (min-width: 1024px) {
  960. .slide-fade-enter-active,
  961. .slide-fade-leave-active {
  962. height: 450px;
  963. }
  964. }
  965. .slide-fade-enter-from {
  966. opacity: 0;
  967. transform: translateX(30px);
  968. }
  969. .slide-fade-leave-to {
  970. opacity: 0;
  971. transform: translateX(-30px);
  972. }
  973. // 添加响应式优化
  974. @media (max-width: 640px) {
  975. .slide-fade-enter-from,
  976. .slide-fade-leave-to {
  977. transform: translateX(15px);
  978. }
  979. }
  980. // 优化图片加载动画
  981. @keyframes gradient {
  982. 0% {
  983. background-position: 0% 50%;
  984. }
  985. 50% {
  986. background-position: 100% 50%;
  987. }
  988. 100% {
  989. background-position: 0% 50%;
  990. }
  991. }
  992. .animate-gradient {
  993. background-size: 200% 200%;
  994. animation: gradient 3s ease infinite;
  995. }
  996. // 移除 pagination 相关样式
  997. :deep(.swiper-pagination-2) {
  998. display: none;
  999. }
  1000. // 添加导航按钮禁用样式
  1001. :deep(.swiper-button-disabled) {
  1002. opacity: 0.35;
  1003. cursor: not-allowed;
  1004. pointer-events: none;
  1005. }
  1006. // 优化轮播图样式
  1007. :deep(.swiper-container-1) {
  1008. .swiper-slide {
  1009. transition: all 0.5s ease;
  1010. transform-origin: center center;
  1011. backface-visibility: hidden;
  1012. perspective: 1000px;
  1013. }
  1014. .swiper-pagination-bullet {
  1015. width: 12px;
  1016. height: 12px;
  1017. background: transparent;
  1018. border: 2px solid rgba(255, 255, 255, 0.5);
  1019. opacity: 1;
  1020. transition: all 0.3s ease;
  1021. margin: 0 8px !important;
  1022. &-active {
  1023. background: #fff;
  1024. border-color: #fff;
  1025. transform: scale(1.2);
  1026. }
  1027. }
  1028. .swiper-pagination {
  1029. display: flex;
  1030. justify-content: center;
  1031. align-items: center;
  1032. padding: 20px 0;
  1033. }
  1034. }
  1035. // 添加轮播图遮罩效果
  1036. .swiper-slide {
  1037. &::before {
  1038. content: "";
  1039. position: absolute;
  1040. top: 0;
  1041. left: 0;
  1042. right: 0;
  1043. bottom: 0;
  1044. background: linear-gradient(
  1045. to bottom,
  1046. rgba(0, 0, 0, 0.2) 0%,
  1047. rgba(0, 0, 0, 0.4) 100%
  1048. );
  1049. z-index: 1;
  1050. }
  1051. }
  1052. // 优化图片加载动画
  1053. @keyframes fadeIn {
  1054. from {
  1055. opacity: 0;
  1056. transform: scale(1.1);
  1057. }
  1058. to {
  1059. opacity: 1;
  1060. transform: scale(1);
  1061. }
  1062. }
  1063. .swiper-slide-active {
  1064. img {
  1065. animation: fadeIn 0.8s ease-out forwards;
  1066. }
  1067. }
  1068. // 优化产品卡片动画和交互
  1069. .swiper-slide {
  1070. a {
  1071. text-decoration: none;
  1072. display: block;
  1073. height: 100%;
  1074. &:hover {
  1075. text-decoration: none;
  1076. }
  1077. > div {
  1078. position: relative;
  1079. z-index: 1;
  1080. cursor: pointer;
  1081. transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  1082. &:hover {
  1083. transform: translateY(-2px);
  1084. box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
  1085. }
  1086. }
  1087. }
  1088. }
  1089. // 移除卡片抖动动画
  1090. @keyframes cardHover {
  1091. 0% {
  1092. transform: translateY(0);
  1093. }
  1094. 100% {
  1095. transform: translateY(-2px);
  1096. }
  1097. }
  1098. </style>