Commit c9fecebbb4f5b1a82f11ac43f66d5b35740b0f0a

Authored by boyang
1 parent a4b10b4c

feat: 开发热销商品

components/Footer.vue
... ... @@ -5,7 +5,9 @@
5 5 <v-col cols="12" lg="3" sm="12" md="6">
6 6 <b>Solution</b>
7 7 <p><router-link to="/equipment">Lab Device</router-link></p>
8   - <p><router-link to="/customize">Customized BatterTesting</router-link></p>
  8 + <p>
  9 + <router-link to="/customize">Customized BatterTesting</router-link>
  10 + </p>
9 11 <p><router-link to="/pack">Pack</router-link></p>
10 12 </v-col>
11 13 <v-col cols="12" lg="3" sm="12" md="6">
... ... @@ -16,6 +18,18 @@
16 18 <v-col cols="12" lg="3" sm="12" md="6">
17 19 <b>About</b>
18 20 <p><router-link to="/about">About us</router-link></p>
  21 + <p>
  22 + <a
  23 + href="https://www.linkedin.com/company/canrd/"
  24 + rel="noopener noreferrer"
  25 + >LinkedIn</a
  26 + >
  27 + </p>
  28 + <p>
  29 + <a href="https://x.com/canrdenerge?s=11" rel="noopener noreferrer"
  30 + >Twitter</a
  31 + >
  32 + </p>
19 33 </v-col>
20 34 <v-col cols="12" lg="3" sm="12" md="6">
21 35 <div class="tw-w-[250px] tw-float-left tw-mr-[8px]">
... ... @@ -24,7 +38,12 @@
24 38 <p>Phone: +86 19867737979</p>
25 39 <p>Wechat: contactcanrd</p>
26 40 </div>
27   - <img class="tw-float-left" src="/wechat.jpg" alt="canrud-wechat" width="80" />
  41 + <img
  42 + class="tw-float-left"
  43 + src="/wechat.jpg"
  44 + alt="canrud-wechat"
  45 + width="80"
  46 + />
28 47 </v-col>
29 48 </v-row>
30 49 </v-container>
... ...
components/MobileCategoryList.vue
... ... @@ -200,7 +200,7 @@ watchEffect(async () =&gt; {
200 200 const foundFuncCategory = funcCategoryList.value.find(
201 201 (func) => func.name === functionName
202 202 );
203   - console.log(foundFuncCategory, "5656functionName");
  203 + console.log(foundFuncCategory, "functionName");
204 204  
205 205 if (foundFuncCategory) {
206 206 const funcCategoryId = foundFuncCategory.id;
... ...
components/ProductDetail.vue
... ... @@ -208,30 +208,15 @@
208 208 <div
209 209 v-for="(imageObj, index) in recommendImages.slice(0, 5)"
210 210 :key="'row1-' + index"
211   - style="
212   - display: inline-block;
213   - margin: 0 5px;
214   - text-align: center;
215   - width: 200px;
216   - "
  211 + class="imageTotal"
217 212 >
218 213 <a v-if="imageObj" :href="imageObj[0]?.productUrl" target="_blank">
219 214 <img
220 215 :src="imageObj[0]?.url"
221 216 :alt="'Image ' + (index + 1)"
222   - style="width: 200px; height: 200px; margin-right: 10px"
  217 + class="item-imgHot"
223 218 />
224   - <span
225   - style="
226   - display: block;
227   - margin-top: 5px;
228   - font-size: 16px;
229   - width: 180px;
230   - color: #555;
231   - text-align: left;
232   - margin-left: 10px;
233   - "
234   - >
  219 + <span class="image-name">
235 220 {{ imageObj[0]?.name }}
236 221 </span>
237 222 </a>
... ... @@ -249,30 +234,15 @@
249 234 <div
250 235 v-for="(imageObj, index) in recommendImages.slice(5, 10)"
251 236 :key="'row2-' + index"
252   - style="
253   - display: inline-block;
254   - margin: 0 5px;
255   - text-align: center;
256   - width: 200px;
257   - "
  237 + class="imageTotal"
258 238 >
259 239 <a v-if="imageObj" :href="imageObj[0]?.productUrl" target="_blank">
260 240 <img
261 241 :src="imageObj[0]?.url"
262 242 :alt="'Image ' + (index + 6)"
263   - style="width: 200px; height: 200px; margin-right: 10px"
  243 + class="item-imgHot"
264 244 />
265   - <span
266   - style="
267   - display: block;
268   - margin-top: 5px;
269   - font-size: 16px;
270   - color: #555;
271   - text-align: left;
272   - width: 180px;
273   - margin-left: 10px;
274   - "
275   - >
  245 + <span class="image-name">
276 246 {{ imageObj[0]?.name }}
277 247 </span>
278 248 </a>
... ... @@ -291,63 +261,6 @@
291 261 />
292 262 </div>
293 263 </div>
294   -
295   - <!-- <div class="tw-pb-[64px]">
296   - <v-tabs
297   - class="tabs"
298   - v-model="tab"
299   - color="white"
300   - bg-color="#eeeeee"
301   - slider-color="blue-lighten-1"
302   - selected-class="active"
303   - >
304   - <v-tab :value="1">Product Details</v-tab>
305   - <v-tab :value="2">Specification</v-tab>
306   - </v-tabs>
307   - <v-window v-model="tab" class="tw-p-[24px]">
308   - <v-window-item key="1" :value="1">
309   - <div v-if="info.advantage" class="tw-mb-[24px]">
310   - <div class="text-h6">Advantage</div>
311   - <v-divider class="tw-mb-[12px]"></v-divider>
312   - <div v-html="info.advantage"></div>
313   - </div>
314   - <div v-if="info.physicalproperty" class="tw-mb-[24px]">
315   - <div class="text-h6">Physical Property</div>
316   - <v-divider class="tw-mb-[12px]"></v-divider>
317   - <div v-html="info.physicalproperty"></div>
318   - </div>
319   - <div v-if="info.storage" class="tw-mb-[24px]">
320   - <div class="text-h6">Storage</div>
321   - <v-divider class="tw-mb-[12px]"></v-divider>
322   - <div v-html="info.storage"></div>
323   - </div>
324   - <div v-if="info.introduction" class="tw-mb-[24px]">
325   - <div class="text-h6">Introduction</div>
326   - <v-divider class="tw-mb-[12px]"></v-divider>
327   - <div v-html="info.introduction"></div>
328   - </div>
329   - <div v-if="info.description" class="tw-mb-[24px]">
330   - <div class="text-h6">Description</div>
331   - <v-divider class="tw-mb-[12px]"></v-divider>
332   - <div v-html="info.description"></div>
333   - </div>
334   - </v-window-item>
335   - <v-window-item key="2" :value="2">
336   - <v-table density="compact" class="table2">
337   - <tbody>
338   - <tr
339   - class="tr"
340   - v-for="item in info.productAttributeList || []"
341   - :key="item.name"
342   - >
343   - <td class="td tw-w-[400px]">{{ item.name }}</td>
344   - <td class="td">{{ item.value }}</td>
345   - </tr>
346   - </tbody>
347   - </v-table>
348   - </v-window-item>
349   - </v-window>
350   - </div> -->
351 264 <div style="display: flex">
352 265 <div class="tw-pb-[64px]" style="width: 70%; margin-right: 10px">
353 266 <v-tabs
... ... @@ -416,81 +329,82 @@
416 329 selected-class="active"
417 330 grow
418 331 >
419   - <v-tab value="one">Blog recommendation</v-tab>
  332 + <v-tab value="one">Journal Recommendation</v-tab>
420 333 </v-tabs>
421   -<!-- <v-list lines="three">-->
422   -<!-- <v-list-item-->
423   -<!-- v-for="item in info.journals"-->
424   -<!-- :key="item.id"-->
425   -<!-- :subtitle="item.title"-->
426   -<!-- @click="navigateToUrl(item.link)"-->
427   -<!-- lines="three"-->
428   -<!-- style="font-size: 24px"-->
429   -<!-- ></v-list-item>-->
430   -<!-- </v-list>-->
431 334 <v-list>
432 335 <v-list-item
433   - v-for="item in info.journals"
434   - :key="item.id"
435   - @click="navigateToUrl(item.link)"
436   - @mouseenter="hoveredItem = item.id"
437   - @mouseleave="hoveredItem = null"
  336 + v-for="item in info.journals"
  337 + :key="item.id"
  338 + @click="navigateToUrl(item.link)"
  339 + @mouseenter="hoveredItem = item.id"
  340 + @mouseleave="hoveredItem = null"
438 341 >
439 342 <v-list-item-title>
440   - <span
441   - :class="['title', { 'full-title': hoveredItem === item.id }]"
442   - >
443   - {{ item.title }}
444   - </span>
  343 + <span
  344 + :class="['title', { 'full-title': hoveredItem === item.id }]"
  345 + >
  346 + {{ item.title }}
  347 + </span>
445 348 </v-list-item-title>
446 349 </v-list-item>
447 350 </v-list>
448   - <!-- <v-list rounded>
449   - <v-list-item-group v-model="selectedItem" color="primary">
450   - <v-list-item
451   - v-for="item in info.journals"
452   - :key="item.id"
453   - @click="navigateToUrl(item.link)"
454   - >
455   - <v-list-item-content>
456   - <v-list-item-title v-text="item.title"></v-list-item-title>
457   - </v-list-item-content>
458   - </v-list-item>
459   - </v-list-item-group>
460   - </v-list> -->
461   -<!-- <v-list rounded>-->
462   -<!-- <v-list-item-group v-model="selectedItem" color="primary">-->
463   -<!-- <v-list-item-->
464   -<!-- v-for="item in info.journals"-->
465   -<!-- :key="item.id"-->
466   -<!-- @click="navigateToUrl(item.link)"-->
467   -<!-- >-->
468   -<!-- <v-list-item-content>-->
469   -<!-- <v-hover v-slot:default="{ isHovering, props }">-->
470   -<!-- <div v-bind="props">-->
471   -<!-- <v-list-item-title-->
472   -<!-- v-text="item.title"-->
473   -<!-- style="-->
474   -<!-- overflow: hidden;-->
475   -<!-- text-overflow: ellipsis;-->
476   -<!-- white-space: nowrap;-->
477   -<!-- "-->
478   -<!-- ></v-list-item-title>-->
479   -<!-- <span v-if="isHovering" bottom style="color: #1e88e5">{{-->
480   -<!-- item.title-->
481   -<!-- }}</span>-->
482   -<!-- <v-tooltip v-if="isHovering" bottom>-->
483   -<!-- <template v-slot:activator="{ props: tooltipProps }">-->
484   -<!-- <span v-bind="tooltipProps">{{ item.title }}</span>-->
485   -<!-- </template>-->
486   -<!-- <span>{{ item.title }}</span>-->
487   -<!-- </v-tooltip>-->
488   -<!-- </div>-->
489   -<!-- </v-hover>-->
490   -<!-- </v-list-item-content>-->
491   -<!-- </v-list-item>-->
492   -<!-- </v-list-item-group>-->
493   -<!-- </v-list>-->
  351 + </div>
  352 + </div>
  353 + <v-tabs
  354 + class="tabs"
  355 + v-model="tabRecomHot"
  356 + style="margin-top: 25px"
  357 + color="white"
  358 + bg-color="#eeeeee"
  359 + slider-color="blue-lighten-1"
  360 + selected-class="active"
  361 + v-if="recommendImagesHot[0] !== null"
  362 + >
  363 + <v-tab :value="1">Best Sellers</v-tab>
  364 + <!-- <v-tab :value="3">商品百科</v-tab> -->
  365 + </v-tabs>
  366 + <div id="image-container" v-if="recommendImagesHot[0] !== null">
  367 + <div class="recommend-left-box">
  368 + <v-img
  369 + src="https://m-canrd.oss-cn-shenzhen.aliyuncs.com/crmebimage/public/maintain/2024/09/14/76c987e13a334be481a346c19c2284f3qy4tjnxps7.png"
  370 + alt="往左移"
  371 + class="recommend-img-left"
  372 + @click="toggleRowLeft"
  373 + />
  374 + </div>
  375 + <div class="image-row" id="row1">
  376 + <!-- <img
  377 + v-for="(imageObj, index) in recommendImages.slice(0, 5)"
  378 + :key="'row1-' + index"
  379 + :src="imageObj[0]?.url"
  380 + :alt="'Image ' + (index + 1)"
  381 + style="margin: 0 5px; width: 200px; height: 200px"
  382 + /> -->
  383 + <div
  384 + v-for="(imageObj, index) in recommendImagesHot"
  385 + :key="'row1-' + index"
  386 + class="imageTotal"
  387 + >
  388 + <a v-if="imageObj" :href="imageObj[0]?.productUrl" target="_blank">
  389 + <img
  390 + :src="imageObj[0]?.url"
  391 + :alt="'Image ' + (index + 1)"
  392 + class="item-imgHot"
  393 + />
  394 + <span class="image-name">
  395 + {{ imageObj[0]?.name }}
  396 + </span>
  397 + </a>
  398 + <div v-else style="width: 200px; height: 200px"></div>
  399 + </div>
  400 + </div>
  401 + <div class="recommend-right-box">
  402 + <v-img
  403 + src="https://m-canrd.oss-cn-shenzhen.aliyuncs.com/crmebimage/public/maintain/2024/09/14/b5daa0a8f2f140f5b406e984c730a453iznzlekysg.png"
  404 + alt="往右移"
  405 + class="recommend-img-right"
  406 + @click="toggleRowRight"
  407 + />
494 408 </div>
495 409 </div>
496 410 <div class="social-share-container">
... ... @@ -545,21 +459,12 @@ const href1 = ref(&quot;/products&quot;);
545 459 const href2 = ref("/products");
546 460 const idHref = ref("/products");
547 461 const hoveredItem = ref(null);
548   -const itemsss = [
549   - {
550   - name: "Item #1",
551   - id: 1,
552   - },
553   - {
554   - name: "Item #2",
555   - id: 2,
556   - },
557   - {
558   - name: "Item #3",
559   - id: 3,
560   - },
561   -];
562 462 const productStore = useProductListStore();
  463 +const maxPage = ref(1);
  464 +const tabRecomHot = ref();
  465 +const recommendListHot = ref();
  466 +const recommendImagesHot = ref();
  467 +const currentIndexHot = ref(1);
563 468 const currentUrl = ref("https://www.canrud.com/products");
564 469 // 定义单个 item 的接口
565 470 interface BreadcrumbItem {
... ... @@ -610,6 +515,70 @@ let { data: resData } = await useAsyncData(
610 515 server: true, // 仅在服务器端获取数据
611 516 }
612 517 );
  518 +const loadHotProducts = async () => {
  519 + let { data: hotProducts } = await useAsyncData(
  520 + "hotProducts",
  521 + () =>
  522 + $fetch("/shop/product/hotProducts", {
  523 + method: "GET",
  524 + params: {
  525 + pageNo: currentIndexHot.value,
  526 + pageSize: 5,
  527 + },
  528 + }),
  529 + {
  530 + server: true, // 仅在服务器端获取数据
  531 + }
  532 + );
  533 + recommendListHot.value = hotProducts.value.data.records;
  534 + maxPage.value = hotProducts.value.data.pages;
  535 + // recommendImages.value = recommendList.value.slice(0, 10).map((item) => {
  536 + recommendImagesHot.value = Array.from({ length: 5 }).map((_, index) => {
  537 + const item = recommendListHot.value[index];
  538 + if (!item) {
  539 + return null;
  540 + }
  541 + // 检查 productimageliststore 是否为字符串格式,如果是,则尝试解析
  542 + if (typeof item.productimageliststore === "string") {
  543 + try {
  544 + item.productimageliststore = JSON.parse(item.productimageliststore);
  545 + } catch (error) {
  546 + item.productimageliststore = []; // 解析失败时,设置为空数组
  547 + }
  548 + }
  549 + const ree = (item.productimageliststore = item?.productimageliststore.map(
  550 + (productItem: ProductImage) => ({
  551 + ...productItem,
  552 + // url: `http://112.74.45.244:8100/api/show/image?fileKey=${item.fileKey}`,
  553 + url: `https://www.canrud.com/api/show/image?fileKey=${productItem.fileKey}&psize=p256`,
  554 + name: item.name,
  555 + productUrl: `https://www.canrud.com/products/detail/${item.id}`,
  556 + })
  557 + ));
  558 + return ree;
  559 + });
  560 +};
  561 +const toggleRowLeft = () => {
  562 + if (currentIndex.value !== 1) {
  563 + currentIndex.value--;
  564 + } else if (currentIndex.value == 1) {
  565 + currentIndex.value = maxPage.value;
  566 + }
  567 +};
  568 +const toggleRowRight = () => {
  569 + if (currentIndex.value < maxPage.value) {
  570 + currentIndex.value++;
  571 + } else if (currentIndex.value == maxPage.value) {
  572 + currentIndex.value = 1;
  573 + }
  574 +};
  575 +watch(currentIndexHot, (newIndex) => {
  576 + loadHotProducts(); // Call loadHotProducts when currentIndex changes
  577 +});
  578 +
  579 +// Initial load of hot products
  580 +await loadHotProducts(); // Load hot products the first time
  581 +
613 582 watchEffect(() => {
614 583 currentUrl.value = "https://www.canrud.com/products/detail/" + info.id;
615 584 if (info?.productCrumbsVO?.category1 && productStore.keyword) {
... ... @@ -712,9 +681,9 @@ watchEffect(() =&gt; {
712 681 (productItem: ProductImage) => ({
713 682 ...productItem,
714 683 // url: `http://112.74.45.244:8100/api/show/image?fileKey=${item.fileKey}`,
715   - url: `/api/show/image?fileKey=${productItem.fileKey}&psize=p512`,
  684 + url: `https://www.canrud.com/api/show/image?fileKey=${productItem.fileKey}&psize=p256`,
716 685 name: item.name,
717   - productUrl: `http://www.canrud.com/products/detail/${item.id}`,
  686 + productUrl: `https://www.canrud.com/products/detail/${item.id}`,
718 687 })
719 688 ));
720 689 return ree;
... ... @@ -804,23 +773,80 @@ th {
804 773 color: #1e88e5;
805 774 }
806 775  
807   -#image-container {
808   - display: flex;
809   - align-items: center;
810   - justify-content: center;
811   - height: 320px;
812   - margin-top: 10px;
813   - margin-bottom: 10px;
  776 +@media screen and (min-width: 1537px) {
  777 + #image-container {
  778 + display: flex;
  779 + align-items: center;
  780 + justify-content: center;
  781 + height: 320px;
  782 + margin: 10px auto 100px;
  783 + width: 80%;
  784 + }
  785 +}
  786 +@media screen and (max-width: 1536px) and (min-width: 1281px) {
  787 + #image-container {
  788 + display: flex;
  789 + align-items: center;
  790 + justify-content: center;
  791 + height: 320px;
  792 + margin: 10px auto 0px;
  793 + width: 80%;
  794 + padding: 0;
  795 + }
814 796 }
815   -
816 797 .image-row {
817 798 display: flex;
818 799 height: 245px;
819 800 }
820   -
821   -.image-row img {
822   - width: 120px;
823   - height: 120px;
  801 +@media screen and (min-width: 1537px) {
  802 + .imageTotal {
  803 + display: inline-block;
  804 + margin: 0 5px;
  805 + text-align: center;
  806 + width: 315px;
  807 + }
  808 +}
  809 +@media screen and (max-width: 1536px) and (min-width: 1281px) {
  810 + .imageTotal {
  811 + display: inline-block;
  812 + margin: 0 5px;
  813 + text-align: center;
  814 + width: 200px;
  815 + }
  816 +}
  817 +@media screen and (min-width: 1537px) {
  818 + .image-row img {
  819 + width: 240px;
  820 + height: 240px;
  821 + }
  822 +}
  823 +@media screen and (max-width: 1536px) and (min-width: 1281px) {
  824 + .image-row img {
  825 + width: 140px;
  826 + height: 140px;
  827 + }
  828 +}
  829 +@media screen and (min-width: 1537px) {
  830 + .image-name {
  831 + display: block;
  832 + margin-top: 5px;
  833 + font-size: 16px;
  834 + width: 180px;
  835 + color: #555;
  836 + text-align: left;
  837 + margin-left: 60px;
  838 + }
  839 +}
  840 +@media screen and (max-width: 1536px) and (min-width: 1281px) {
  841 + .image-name {
  842 + display: block;
  843 + margin-top: 5px;
  844 + font-size: 16px;
  845 + width: 180px;
  846 + color: #555;
  847 + text-align: left;
  848 + margin-left: 10px;
  849 + }
824 850 }
825 851  
826 852 button .recommendButton {
... ... @@ -857,6 +883,7 @@ button .recommendButton {
857 883 display: flex;
858 884 flex-direction: row; /* 父容器横向排列 */
859 885 gap: 1rem; /* 设置每个分享项之间的间距 */
  886 + margin-top: 40px;
860 887 }
861 888  
862 889 .social-share-item {
... ... @@ -873,11 +900,11 @@ button .recommendButton {
873 900  
874 901 .title {
875 902 font-size: 15px; /* 设置字体大小为24px */
876   - color: black; /* 设置字体颜色为黑色 */
  903 + color: black; /* 设置字体颜色为黑色 */
877 904 display: -webkit-box; /* 使用盒模型显示多行文本 */
878 905 -webkit-line-clamp: 2; /* 限制为两行 */
879 906 -webkit-box-orient: vertical; /* 盒子方向为垂直 */
880   - overflow: hidden; /* 超过部分隐藏 */
  907 + overflow: hidden; /* 超过部分隐藏 */
881 908 transition: max-height 0.3s ease; /* 过渡效果 */
882 909 }
883 910  
... ... @@ -885,6 +912,6 @@ button .recommendButton {
885 912 display: block; /* 当悬浮时显示为块级元素 */
886 913 color: #1e88e5;
887 914 white-space: normal; /* 允许换行 */
888   - overflow: visible; /* 显示全部内容 */
  915 + overflow: visible; /* 显示全部内容 */
889 916 }
890 917 </style>
... ...
nuxt.config.ts
... ... @@ -41,8 +41,8 @@ export default defineNuxtConfig({
41 41 nitro: {
42 42 devProxy: {
43 43 "/shop": {
44   - target: "http://47.89.254.121:8002/shop", // 线上代理地址
45   - // target: "http://127.0.0.1:8002/shop",
  44 + // target: "http://47.89.254.121:8002/shop", // 线上代理地址
  45 + target: "http://127.0.0.1:8002/shop",
46 46 // target: process.env.BASE_URL || 'http://39.108.227.113:8002/shop', // 目标接口域名
47 47 changeOrigin: true, // 表示是否跨域
48 48 },
... ... @@ -50,8 +50,8 @@ export default defineNuxtConfig({
50 50 // 该配置用于服务端请求转发
51 51 routeRules: {
52 52 "/shop/**": {
53   - proxy: "http://47.89.254.121:8002/shop/**",
54   - // proxy: "http://127.0.0.1:8002/shop/**",
  53 + // proxy: "http://47.89.254.121:8002/shop/**",
  54 + proxy: "http://127.0.0.1:8002/shop/**",
55 55 // proxy: process.env.BASE_URL || 'http://39.108.227.113:8002/shop/**'
56 56 },
57 57 },
... ...
pages/index.vue
1 1 <template>
2 2 <v-rows class="tw-w-full">
3   - <v-carousel hide-delimiter-background show-arrows="hover" height="auto" v-if="!isMobile()">
4   - <v-carousel-item v-for="banner in banners" :src="banner" cover alt="canrud" :key="banner">
  3 + <v-carousel
  4 + hide-delimiter-background
  5 + show-arrows="hover"
  6 + height="auto"
  7 + v-if="!isMobile()"
  8 + >
  9 + <v-carousel-item
  10 + v-for="banner in banners"
  11 + :src="banner"
  12 + cover
  13 + alt="canrud"
  14 + :key="banner"
  15 + >
5 16 </v-carousel-item>
6 17 </v-carousel>
7   - <v-carousel hide-delimiter-background show-arrows="hover" height="auto" v-if="isMobile()">
8   - <v-carousel-item v-for="banner in mobileBanners" :src="banner" cover alt="canrud" :key="banner">
  18 + <v-carousel
  19 + hide-delimiter-background
  20 + show-arrows="hover"
  21 + height="auto"
  22 + v-if="isMobile()"
  23 + >
  24 + <v-carousel-item
  25 + v-for="banner in mobileBanners"
  26 + :src="banner"
  27 + cover
  28 + alt="canrud"
  29 + :key="banner"
  30 + >
9 31 </v-carousel-item>
10 32 </v-carousel>
11 33 </v-rows>
12 34 <!-- 能源材料 -->
13 35 <div class="tw-py-8 py-sm-16">
14 36 <v-container>
15   - <MainTitleListOdd title="Material Reagents" :list="materials"
16   - desc="Leading global provider of energy storage research materials and providing other professional/universal experimental materials. " />
  37 + <MainTitleListOdd
  38 + title="Material Reagents"
  39 + :list="materials"
  40 + desc="Leading global provider of energy storage research materials and providing other professional/universal experimental materials. "
  41 + />
17 42 </v-container>
18 43 </div>
19 44  
20 45 <!-- 设备 -->
21 46 <div class="bg-grey-lighten-5 tw-py-8 py-sm-16">
22 47 <v-container>
23   - <MainTitleList title="Lab Device" listType="equipment"
  48 + <MainTitleList
  49 + title="Lab Device"
  50 + listType="equipment"
24 51 :list="lab.list.map((item) => ({ ...item, href: '/products' }))"
25 52 desc="Self-built High-precision Machining Center with Powerful Design and Manufacturing Capabilities. "
26   - href="/equipment" />
  53 + href="/equipment"
  54 + />
27 55 </v-container>
28 56 </div>
29 57  
30 58 <!-- Customized Battery -->
31 59 <div class="tw-py-8 py-sm-16">
32 60 <v-container>
33   - <MainTitleList :title="('Customized Battery')" :list="batteries" href="/customize"
34   - desc="200mAh~10Ah, Winding/Stacking, Unfilled/Filled Electrolyte Cells, Three-Electrode, and More. " />
  61 + <MainTitleList
  62 + :title="'Customized Battery'"
  63 + :list="batteries"
  64 + href="/customize"
  65 + desc="200mAh~10Ah, Winding/Stacking, Unfilled/Filled Electrolyte Cells, Three-Electrode, and More. "
  66 + />
35 67 </v-container>
36 68 </div>
37 69 <!-- Testing -->
38 70 <div class="bg-grey-lighten-5 tw-py-8 py-sm-16">
39 71 <v-container>
40   - <MainTitleList title="Testing" :list="tests" href="/test"
41   - desc="Self built testing center and signed strategic cooperation with ATL, Tsinghua and other units. " />
  72 + <MainTitleList
  73 + title="Testing"
  74 + :list="tests"
  75 + href="/test"
  76 + desc="Self built testing center and signed strategic cooperation with ATL, Tsinghua and other units. "
  77 + />
42 78 </v-container>
43 79 </div>
44 80 <!-- Pack -->
45 81 <div class="pt-8 pb-8 pt pt-sm-16 pb-sm-32">
46 82 <v-container>
47   - <MainTitleList title="Pack" href="/pack" :list="packs"
48   - desc="Focusing on energy materials/new energy storage systems/modules and other fields, mastering advanced technologies to provide high-quality services. " />
  83 + <MainTitleList
  84 + title="Pack"
  85 + href="/pack"
  86 + :list="packs"
  87 + desc="Focusing on energy materials/new energy storage systems/modules and other fields, mastering advanced technologies to provide high-quality services. "
  88 + />
49 89 </v-container>
50 90 </div>
  91 + <v-tabs
  92 + class="tabs"
  93 + v-model="tabRecom"
  94 + color="white"
  95 + bg-color="#eeeeee"
  96 + slider-color="blue-lighten-1"
  97 + selected-class="active"
  98 + v-if="recommendImages[0] !== null && !isMobile()"
  99 + >
  100 + <v-tab :value="1">Best Sellers</v-tab>
  101 + <!-- <v-tab :value="3">商品百科</v-tab> -->
  102 + </v-tabs>
  103 + <div id="image-container" v-if="recommendImages[0] !== null && !isMobile()">
  104 + <div class="recommend-left-box">
  105 + <v-img
  106 + src="https://m-canrd.oss-cn-shenzhen.aliyuncs.com/crmebimage/public/maintain/2024/09/14/76c987e13a334be481a346c19c2284f3qy4tjnxps7.png"
  107 + alt="往左移"
  108 + class="recommend-img-left"
  109 + @click="toggleRowLeft"
  110 + />
  111 + </div>
  112 + <div class="image-row" id="row1">
  113 + <!-- <img
  114 + v-for="(imageObj, index) in recommendImages.slice(0, 5)"
  115 + :key="'row1-' + index"
  116 + :src="imageObj[0]?.url"
  117 + :alt="'Image ' + (index + 1)"
  118 + style="margin: 0 5px; width: 200px; height: 200px"
  119 + /> -->
  120 + <div
  121 + v-for="(imageObj, index) in recommendImages"
  122 + :key="'row1-' + index"
  123 + class="imageTotal"
  124 + >
  125 + <a v-if="imageObj" :href="imageObj[0]?.productUrl" target="_blank">
  126 + <img
  127 + :src="imageObj[0]?.url"
  128 + :alt="'Image ' + (index + 1)"
  129 + class="item-imgHot"
  130 + />
  131 + <span class="image-name">
  132 + {{ imageObj[0]?.name }}
  133 + </span>
  134 + </a>
  135 + <div v-else style="width: 200px; height: 200px"></div>
  136 + </div>
  137 + </div>
  138 + <div class="recommend-right-box">
  139 + <v-img
  140 + src="https://m-canrd.oss-cn-shenzhen.aliyuncs.com/crmebimage/public/maintain/2024/09/14/b5daa0a8f2f140f5b406e984c730a453iznzlekysg.png"
  141 + alt="往右移"
  142 + class="recommend-img-right"
  143 + @click="toggleRowRight"
  144 + />
  145 + </div>
  146 + </div>
51 147 </template>
52 148  
53 149 <script setup lang="ts">
54   -import MainTitleList from '../components/MainTitleList.vue'
55   -import MainTitleListOdd from '../components/MainTitleListOdd.vue'
56   -import { useCategoryStore } from '../stores/category'
57   -import { computed } from 'vue'
58   -import { isMobile } from '../utils'
  150 +import MainTitleList from "../components/MainTitleList.vue";
  151 +import MainTitleListOdd from "../components/MainTitleListOdd.vue";
  152 +import { useCategoryStore } from "../stores/category";
  153 +import { computed, onMounted, reactive, ref } from "vue";
  154 +import { isMobile } from "../utils";
  155 +
  156 +const maxPage = ref(1);
  157 +const tabRecom = ref();
  158 +const recommendList = ref();
  159 +const recommendImages = ref();
  160 +const currentIndex = ref(1);
  161 +const flag = ref(false);
  162 +const loadHotProducts = async () => {
  163 + let { data: hotProducts } = await useAsyncData(
  164 + "hotProducts",
  165 + () =>
  166 + $fetch("/shop/product/hotProducts", {
  167 + method: "GET",
  168 + params: {
  169 + pageNo: currentIndex.value,
  170 + pageSize: 5,
  171 + },
  172 + }),
  173 + {
  174 + server: true, // 仅在服务器端获取数据
  175 + }
  176 + );
  177 + recommendList.value = hotProducts.value.data.records;
  178 + maxPage.value = hotProducts.value.data.pages;
  179 + // recommendImages.value = recommendList.value.slice(0, 10).map((item) => {
  180 + recommendImages.value = Array.from({ length: 5 }).map((_, index) => {
  181 + const item = recommendList.value[index];
  182 + if (!item) {
  183 + return null;
  184 + }
  185 + // 检查 productimageliststore 是否为字符串格式,如果是,则尝试解析
  186 + if (typeof item.productimageliststore === "string") {
  187 + try {
  188 + item.productimageliststore = JSON.parse(item.productimageliststore);
  189 + } catch (error) {
  190 + item.productimageliststore = []; // 解析失败时,设置为空数组
  191 + }
  192 + }
  193 + const ree = (item.productimageliststore = item?.productimageliststore.map(
  194 + (productItem: ProductImage) => ({
  195 + ...productItem,
  196 + // url: `http://112.74.45.244:8100/api/show/image?fileKey=${item.fileKey}`,
  197 + url: `https://www.canrud.com/api/show/image?fileKey=${productItem.fileKey}&psize=p256`,
  198 + name: item.name,
  199 + productUrl: `https://www.canrud.com/products/detail/${item.id}`,
  200 + })
  201 + ));
  202 + return ree;
  203 + });
  204 +};
  205 +const toggleRowLeft = () => {
  206 + if (currentIndex.value !== 1) {
  207 + currentIndex.value--;
  208 + } else if (currentIndex.value == 1) {
  209 + currentIndex.value = maxPage.value;
  210 + }
  211 +};
  212 +const toggleRowRight = () => {
  213 + if (currentIndex.value < maxPage.value) {
  214 + currentIndex.value++;
  215 + } else if (currentIndex.value == maxPage.value) {
  216 + currentIndex.value = 1;
  217 + }
  218 +};
  219 +watch(currentIndex, (newIndex) => {
  220 + loadHotProducts(); // Call loadHotProducts when currentIndex changes
  221 +});
  222 +
  223 +// Initial load of hot products
  224 +await loadHotProducts(); // Load hot products the first time
  225 +
59 226 onMounted(() => {
60   - console.log('%c [ onMounted ]-10', 'font-size:13px; background:pink; color:#bf2c9f;', 111)
61   -})
  227 + console.log(
  228 + "%c [ onMounted ]-10",
  229 + "font-size:13px; background:pink; color:#bf2c9f;",
  230 + 111
  231 + );
  232 +});
62 233 useHead({
63   - title: 'canrud',
  234 + title: "canrud",
64 235 meta: [
65 236 {
66   - name: 'title',
67   - content: "科路得,助您科研之路势在必得。Canrd aims to be the world's leading one-stop service provider in new energy research. With a dedication to excellence, we offer Material Reagents, Lab Devices, Customized Batteries, Testing, and Advanced Packaging for energy materials and storage systems. We master advanced technologies to provide high-quality solutions. Our team's quick responses ensure tailored and professional services to meet your unique needs. Contact us at contact@canrd.com or call +86 19867737979 to explore our innovative offerings. Together, let's shape a greener, brighter world!"
68   - }, {
69   - name: 'keywords',
  237 + name: "title",
70 238 content:
71   - '科路得,canrd,canrud,Energy Storage Research,Lithium Batteries Research,Material Reagents,Lab Device,Customized Battery,Testing,Pack',
72   - }, {
  239 + "科路得,助您科研之路势在必得。Canrd aims to be the world's leading one-stop service provider in new energy research. With a dedication to excellence, we offer Material Reagents, Lab Devices, Customized Batteries, Testing, and Advanced Packaging for energy materials and storage systems. We master advanced technologies to provide high-quality solutions. Our team's quick responses ensure tailored and professional services to meet your unique needs. Contact us at contact@canrd.com or call +86 19867737979 to explore our innovative offerings. Together, let's shape a greener, brighter world!",
  240 + },
  241 + {
  242 + name: "keywords",
  243 + content:
  244 + "科路得,canrd,canrud,Energy Storage Research,Lithium Batteries Research,Material Reagents,Lab Device,Customized Battery,Testing,Pack",
  245 + },
  246 + {
73 247 name: "description",
74 248 content:
75   - "科路得,助您科研之路势在必得。Canrd aims to be the world's leading one-stop service provider in new energy research. With a dedication to excellence, we offer Material Reagents, Lab Devices, Customized Batteries, Testing, and Advanced Packaging for energy materials and storage systems. We master advanced technologies to provide high-quality solutions. Our team's quick responses ensure tailored and professional services to meet your unique needs. Contact us at contact@canrd.com or call +86 19867737979 to explore our innovative offerings. Together, let's shape a greener, brighter world!"
76   - }],
77   - link: [
78   - { rel: 'preload', href: '/banner/banner1.jpg', as: 'image' }
79   - ]
80   -})
  249 + "科路得,助您科研之路势在必得。Canrd aims to be the world's leading one-stop service provider in new energy research. With a dedication to excellence, we offer Material Reagents, Lab Devices, Customized Batteries, Testing, and Advanced Packaging for energy materials and storage systems. We master advanced technologies to provide high-quality solutions. Our team's quick responses ensure tailored and professional services to meet your unique needs. Contact us at contact@canrd.com or call +86 19867737979 to explore our innovative offerings. Together, let's shape a greener, brighter world!",
  250 + },
  251 + ],
  252 + link: [{ rel: "preload", href: "/banner/banner1.jpg", as: "image" }],
  253 +});
81 254  
82 255 // useAsyncData(async ({ app }) => {
83 256 // console.log('%c [ app ]-70', 'font-size:13px; background:pink; color:#bf2c9f;', app)
... ... @@ -85,76 +258,245 @@ useHead({
85 258 // app.head.meta = [
86 259 // {
87 260 // name: 'description',
88   -// content: "科路得,助您科研之路势在必得。Canrd aims to be the world's leading one-stop service provider in new energy research. With a dedication to excellence, we offer Material Reagents, Lab Devices, Customized Batteries, Testing, and Advanced Packaging for energy materials and storage systems. We master advanced technologies to provide high-quality solutions. Our team's quick responses ensure tailored and professional services to meet your unique needs. Contact us at
  261 +// content: "科路得,助您科研之路势在必得。Canrd aims to be the world's leading one-stop service provider in new energy research. With a dedication to excellence, we offer Material Reagents, Lab Devices, Customized Batteries, Testing, and Advanced Packaging for energy materials and storage systems. We master advanced technologies to provide high-quality solutions. Our team's quick responses ensure tailored and professional services to meet your unique needs. Contact us at
89 262 // }]
90 263 // })
91   -console.log(11)
  264 +console.log(11);
92 265  
93   -const store = useCategoryStore()
  266 +const store = useCategoryStore();
94 267  
95 268 const lab = computed(
96 269 () =>
97 270 store?.list?.[3] || {
98   - categoryDisplayName: '',
99   - list: []
  271 + categoryDisplayName: "",
  272 + list: [],
100 273 }
101   -)
  274 +);
102 275  
103 276 const banners = [
104   - '/banner/banner1.jpg',
105   - '/banner/banner2.jpg',
106   - '/banner/banner3.jpg',
107   - '/banner/banner5.jpg'
108   -]
  277 + "/banner/banner1.jpg",
  278 + "/banner/banner2.jpg",
  279 + "/banner/banner3.jpg",
  280 + "/banner/banner5.jpg",
  281 +];
109 282  
110 283 const mobileBanners = [
111   - '/mobile/banner-index1.png',
112   - '/mobile/banner-index2.png',
113   - '/mobile/banner-index3.png'
114   -]
  284 + "/mobile/banner-index1.png",
  285 + "/mobile/banner-index2.png",
  286 + "/mobile/banner-index3.png",
  287 +];
115 288  
116 289 const materials = [
117   - { name: 'Energy materials', imageUrl: '/home/1.jpg', href: '/products' },
  290 + { name: "Energy materials", imageUrl: "/home/1.jpg", href: "/products" },
118 291 {
119   - name: 'Laboratory consumables',
120   - imageUrl: '/home/2-Universal-consumables.png',
121   - href: '/products'
  292 + name: "Laboratory consumables",
  293 + imageUrl: "/home/2-Universal-consumables.png",
  294 + href: "/products",
122 295 },
123 296 {
124   - name: 'Low-dimensional materials',
125   - imageUrl: '/home/3-Low-dimensional-materials.png',
126   - href: '/products'
127   - }
128   -]
  297 + name: "Low-dimensional materials",
  298 + imageUrl: "/home/3-Low-dimensional-materials.png",
  299 + href: "/products",
  300 + },
  301 +];
129 302  
130 303 const tests = [
131 304 {
132   - name: 'Electrochemical performance',
133   - imageUrl: '/home/8_Electrochemical_performance.svg',
134   - href: '/test'
  305 + name: "Electrochemical performance",
  306 + imageUrl: "/home/8_Electrochemical_performance.svg",
  307 + href: "/test",
  308 + },
  309 + {
  310 + name: "Reliability testing",
  311 + imageUrl: "/home/9 Reliability testing.svg",
  312 + href: "/test",
135 313 },
136   - { name: 'Reliability testing', imageUrl: '/home/9 Reliability testing.svg', href: '/test' },
137   - { name: 'Material testing', imageUrl: '/home/10 Material testing.svg', href: '/test' },
138   - { name: 'Calibration', imageUrl: '/home/11 Calibration.svg', href: '/test' }
139   -]
  314 + {
  315 + name: "Material testing",
  316 + imageUrl: "/home/10 Material testing.svg",
  317 + href: "/test",
  318 + },
  319 + { name: "Calibration", imageUrl: "/home/11 Calibration.svg", href: "/test" },
  320 +];
140 321 const batteries = [
141   - { name: 'Material evaluation', imageUrl: '/home/4-Material-evaluation.png', href: '/customize' },
142   - { name: 'R&D foundry', imageUrl: '/home/5-R&D-foundry.png', href: '/customize' },
143   - { name: 'Chemical system', imageUrl: '/home/6-Chemical-system.png', href: '/customize' },
144 322 {
145   - name: 'Semi product customization',
146   - imageUrl: '/home/7-Semi-product-customization.png',
147   - href: '/customize'
148   - }
149   -]
  323 + name: "Material evaluation",
  324 + imageUrl: "/home/4-Material-evaluation.png",
  325 + href: "/customize",
  326 + },
  327 + {
  328 + name: "R&D foundry",
  329 + imageUrl: "/home/5-R&D-foundry.png",
  330 + href: "/customize",
  331 + },
  332 + {
  333 + name: "Chemical system",
  334 + imageUrl: "/home/6-Chemical-system.png",
  335 + href: "/customize",
  336 + },
  337 + {
  338 + name: "Semi product customization",
  339 + imageUrl: "/home/7-Semi-product-customization.png",
  340 + href: "/customize",
  341 + },
  342 +];
150 343 const packs = [
151   - { name: 'Power bank', imageUrl: '/home/12-power-bank.png', href: '/pack' },
152   - { name: 'Energy storage', imageUrl: '/home/13-Energy-storage.png', href: '/pack' },
153   - { name: 'power tool', imageUrl: '/home/3-powertool.png', href: '/pack' },
  344 + { name: "Power bank", imageUrl: "/home/12-power-bank.png", href: "/pack" },
154 345 {
155   - name: 'portable energy storage',
156   - imageUrl: '/home/4-portableenergystorage.png',
157   - href: '/pack'
158   - }
159   -]
  346 + name: "Energy storage",
  347 + imageUrl: "/home/13-Energy-storage.png",
  348 + href: "/pack",
  349 + },
  350 + { name: "power tool", imageUrl: "/home/3-powertool.png", href: "/pack" },
  351 + {
  352 + name: "portable energy storage",
  353 + imageUrl: "/home/4-portableenergystorage.png",
  354 + href: "/pack",
  355 + },
  356 +];
160 357 </script>
  358 +<style scoped>
  359 +@media screen and (min-width: 1537px) {
  360 + .tabs {
  361 + border-bottom: 2px solid #1f88e5;
  362 + margin: 10px auto 100px;
  363 + width: 85%;
  364 + }
  365 +}
  366 +@media screen and (max-width: 1536px) and (min-width: 1281px) {
  367 + .tabs {
  368 + border-bottom: 2px solid #1f88e5;
  369 + margin: 10px auto 20px;
  370 + width: 80%;
  371 + }
  372 +}
  373 +
  374 +.active {
  375 + background-color: #1086e8;
  376 +}
  377 +
  378 +/* #image-container {
  379 + display: flex;
  380 + align-items: center;
  381 + justify-content: center;
  382 + height: 320px;
  383 + margin: 10px auto 50px;
  384 + width: 80%;
  385 +} */
  386 +
  387 +@media screen and (min-width: 1537px) {
  388 + #image-container {
  389 + display: flex;
  390 + align-items: center;
  391 + justify-content: center;
  392 + height: 320px;
  393 + margin: 10px auto 100px;
  394 + width: 80%;
  395 + }
  396 +}
  397 +@media screen and (max-width: 1536px) and (min-width: 1281px) {
  398 + #image-container {
  399 + display: flex;
  400 + align-items: center;
  401 + justify-content: center;
  402 + height: 320px;
  403 + margin: 10px auto 0px;
  404 + width: 80%;
  405 + }
  406 +}
  407 +.image-row {
  408 + display: flex;
  409 + height: 305px;
  410 +}
  411 +@media screen and (min-width: 1537px) {
  412 + .image-row {
  413 + display: flex;
  414 + height: 305px;
  415 + }
  416 +}
  417 +@media screen and (max-width: 1536px) and (min-width: 1281px) {
  418 + .image-row {
  419 + display: flex;
  420 + height: 245px;
  421 + }
  422 +}
  423 +@media screen and (min-width: 1537px) {
  424 + .imageTotal {
  425 + display: inline-block;
  426 + margin: 0 5px;
  427 + text-align: center;
  428 + width: 290px;
  429 + }
  430 +}
  431 +@media screen and (max-width: 1536px) and (min-width: 1281px) {
  432 + .imageTotal {
  433 + display: inline-block;
  434 + margin: 0 5px;
  435 + text-align: center;
  436 + width: 210px;
  437 + }
  438 +}
  439 +@media screen and (min-width: 1537px) {
  440 + .image-row img {
  441 + width: 240px;
  442 + height: 240px;
  443 + }
  444 +}
  445 +@media screen and (max-width: 1536px) and (min-width: 1281px) {
  446 + .image-row img {
  447 + width: 140px;
  448 + height: 140px;
  449 + }
  450 +}
  451 +@media screen and (min-width: 1537px) {
  452 + .image-name {
  453 + display: block;
  454 + margin-top: 5px;
  455 + font-size: 16px;
  456 + width: 180px;
  457 + color: #555;
  458 + text-align: left;
  459 + margin-left: 50px;
  460 + }
  461 +}
  462 +@media screen and (max-width: 1536px) and (min-width: 1281px) {
  463 + .image-name {
  464 + display: block;
  465 + margin-top: 5px;
  466 + font-size: 16px;
  467 + width: 180px;
  468 + color: #555;
  469 + text-align: left;
  470 + margin-left: 10px;
  471 + }
  472 +}
  473 +button .recommendButton {
  474 + margin: 0 0px;
  475 + cursor: pointer;
  476 +}
  477 +
  478 +.recommend-left-box {
  479 +}
  480 +
  481 +.recommend-img-left {
  482 + width: 26px;
  483 + height: 27px;
  484 + margin-right: 30px;
  485 +}
  486 +
  487 +.recommend-img-left:hover {
  488 + cursor: pointer;
  489 +}
  490 +.recommend-right-box {
  491 +}
  492 +
  493 +.recommend-img-right {
  494 + width: 26px;
  495 + height: 27px;
  496 + margin-left: 30px;
  497 +}
  498 +
  499 +.recommend-img-right:hover {
  500 + cursor: pointer;
  501 +}
  502 +</style>
... ...
pages/products/index.vue
1 1 <template>
2   - <div class="tw-m-auto tw-pb-[64px]">
  2 + <div class="tw-m-auto tw-pb-[64px]" style="padding-bottom: 0px">
3 3 <CategoryList v-if="categoryStore.categoryVisible && !isMobile()" />
4 4 <MobileCategoryList v-if="categoryStore.categoryVisible && isMobile()" />
5 5 <v-container class="">
... ... @@ -70,11 +70,72 @@
70 70 total-visible="5"
71 71 ></v-pagination></v-col
72 72 ></v-row>
  73 + <v-tabs
  74 + class="tabs"
  75 + v-model="tabRecom"
  76 + style="margin-top: 25px"
  77 + color="white"
  78 + bg-color="#eeeeee"
  79 + slider-color="blue-lighten-1"
  80 + selected-class="active"
  81 + v-if="recommendImages[0] !== null && !isMobile()"
  82 + >
  83 + <v-tab :value="1">Best Sellers</v-tab>
  84 + <!-- <v-tab :value="3">商品百科</v-tab> -->
  85 + </v-tabs>
  86 + <div
  87 + id="image-container"
  88 + v-if="recommendImages[0] !== null && !isMobile()"
  89 + >
  90 + <div class="recommend-left-box">
  91 + <v-img
  92 + src="https://m-canrd.oss-cn-shenzhen.aliyuncs.com/crmebimage/public/maintain/2024/09/14/76c987e13a334be481a346c19c2284f3qy4tjnxps7.png"
  93 + alt="往左移"
  94 + class="recommend-img-left"
  95 + @click="toggleRowLeft"
  96 + />
  97 + </div>
  98 + <div class="image-row" id="row1">
  99 + <!-- <img
  100 + v-for="(imageObj, index) in recommendImages.slice(0, 5)"
  101 + :key="'row1-' + index"
  102 + :src="imageObj[0]?.url"
  103 + :alt="'Image ' + (index + 1)"
  104 + style="margin: 0 5px; width: 200px; height: 200px"
  105 + /> -->
  106 + <div
  107 + v-for="(imageObj, index) in recommendImages"
  108 + :key="'row1-' + index"
  109 + class="imageTotal"
  110 + >
  111 + <a v-if="imageObj" :href="imageObj[0]?.productUrl" target="_blank">
  112 + <img
  113 + :src="imageObj[0]?.url"
  114 + :alt="'Image ' + (index + 1)"
  115 + class="item-imgHot"
  116 + />
  117 + <span class="image-name">
  118 + {{ imageObj[0]?.name }}
  119 + </span>
  120 + </a>
  121 + <div v-else style="width: 200px; height: 200px"></div>
  122 + </div>
  123 + </div>
  124 + <div class="recommend-right-box">
  125 + <v-img
  126 + src="https://m-canrd.oss-cn-shenzhen.aliyuncs.com/crmebimage/public/maintain/2024/09/14/b5daa0a8f2f140f5b406e984c730a453iznzlekysg.png"
  127 + alt="往右移"
  128 + class="recommend-img-right"
  129 + @click="toggleRowRight"
  130 + />
  131 + </div>
  132 + </div>
73 133 </v-container>
74 134 </div>
75 135 </template>
76 136  
77 137 <script setup lang="ts">
  138 +import type { ProductImage } from "~/type";
78 139 import { isMobile, isEqual } from "~/utils";
79 140 import { useProductListStore } from "~/stores/product_list";
80 141 import { useCategoryStore } from "~/stores/category";
... ... @@ -89,7 +150,76 @@ const route = useRoute(); // 获取路由信息
89 150 const router = useRouter(); // 获取路由信息
90 151 const title = ref("");
91 152 const keywordTitle = ref("");
  153 +const maxPage = ref(1);
  154 +const tabRecom = ref();
  155 +const recommendList = ref();
  156 +const recommendImages = ref();
  157 +const currentIndex = ref(1);
92 158 const isOrNotMobile = isMobile();
  159 +const loadHotProducts = async () => {
  160 + let { data: hotProducts } = await useAsyncData(
  161 + "hotProducts",
  162 + () =>
  163 + $fetch("/shop/product/hotProducts", {
  164 + method: "GET",
  165 + params: {
  166 + pageNo: currentIndex.value,
  167 + pageSize: 5,
  168 + },
  169 + }),
  170 + {
  171 + server: true, // 仅在服务器端获取数据
  172 + }
  173 + );
  174 + recommendList.value = hotProducts.value.data.records;
  175 + maxPage.value = hotProducts.value.data.pages;
  176 + // recommendImages.value = recommendList.value.slice(0, 10).map((item) => {
  177 + recommendImages.value = Array.from({ length: 5 }).map((_, index) => {
  178 + const item = recommendList.value[index];
  179 + if (!item) {
  180 + return null;
  181 + }
  182 + // 检查 productimageliststore 是否为字符串格式,如果是,则尝试解析
  183 + if (typeof item.productimageliststore === "string") {
  184 + try {
  185 + item.productimageliststore = JSON.parse(item.productimageliststore);
  186 + } catch (error) {
  187 + item.productimageliststore = []; // 解析失败时,设置为空数组
  188 + }
  189 + }
  190 + const ree = (item.productimageliststore = item?.productimageliststore.map(
  191 + (productItem: ProductImage) => ({
  192 + ...productItem,
  193 + // url: `http://112.74.45.244:8100/api/show/image?fileKey=${item.fileKey}`,
  194 + url: `https://www.canrud.com/api/show/image?fileKey=${productItem.fileKey}&psize=p256`,
  195 + name: item.name,
  196 + productUrl: `https://www.canrud.com/products/detail/${item.id}`,
  197 + })
  198 + ));
  199 + return ree;
  200 + });
  201 +};
  202 +const toggleRowLeft = () => {
  203 + if (currentIndex.value !== 1) {
  204 + currentIndex.value--;
  205 + } else if (currentIndex.value == 1) {
  206 + currentIndex.value = maxPage.value;
  207 + }
  208 +};
  209 +const toggleRowRight = () => {
  210 + if (currentIndex.value < maxPage.value) {
  211 + currentIndex.value++;
  212 + } else if (currentIndex.value == maxPage.value) {
  213 + currentIndex.value = 1;
  214 + }
  215 +};
  216 +watch(currentIndex, (newIndex) => {
  217 + loadHotProducts(); // Call loadHotProducts when currentIndex changes
  218 +});
  219 +
  220 +// Initial load of hot products
  221 +await loadHotProducts(); // Load hot products the first time
  222 +
93 223 watchEffect(() => {
94 224 // 遍历数组
95 225 if (router.currentRoute.value.query.categories) {
... ... @@ -285,4 +415,118 @@ const length = computed(() =&gt;
285 415 -webkit-line-clamp: 2;
286 416 -webkit-box-orient: vertical;
287 417 }
  418 +
  419 +.tabs {
  420 + border-bottom: 2px solid #1f88e5;
  421 +}
  422 +
  423 +.active {
  424 + background-color: #1086e8;
  425 +}
  426 +
  427 +@media screen and (min-width: 1537px) {
  428 + #image-container {
  429 + display: flex;
  430 + align-items: center;
  431 + justify-content: center;
  432 + height: 320px;
  433 + margin: 10px auto 100px;
  434 + width: 80%;
  435 + }
  436 +}
  437 +@media screen and (max-width: 1536px) and (min-width: 1281px) {
  438 + #image-container {
  439 + display: flex;
  440 + align-items: center;
  441 + justify-content: center;
  442 + height: 320px;
  443 + margin: 10px auto 0px;
  444 + width: 80%;
  445 + padding: 0;
  446 + }
  447 +}
  448 +.image-row {
  449 + display: flex;
  450 + height: 245px;
  451 +}
  452 +@media screen and (min-width: 1537px) {
  453 + .imageTotal {
  454 + display: inline-block;
  455 + margin: 0 5px;
  456 + text-align: center;
  457 + width: 300px;
  458 + }
  459 +}
  460 +@media screen and (max-width: 1536px) and (min-width: 1281px) {
  461 + .imageTotal {
  462 + display: inline-block;
  463 + margin: 0 5px;
  464 + text-align: center;
  465 + width: 200px;
  466 + }
  467 +}
  468 +@media screen and (min-width: 1537px) {
  469 + .image-row img {
  470 + width: 240px;
  471 + height: 240px;
  472 + }
  473 +}
  474 +@media screen and (max-width: 1536px) and (min-width: 1281px) {
  475 + .image-row img {
  476 + width: 140px;
  477 + height: 140px;
  478 + }
  479 +}
  480 +@media screen and (min-width: 1537px) {
  481 + .image-name {
  482 + display: block;
  483 + margin-top: 5px;
  484 + font-size: 16px;
  485 + width: 180px;
  486 + color: #555;
  487 + text-align: left;
  488 + margin-left: 50px;
  489 + }
  490 +}
  491 +@media screen and (max-width: 1536px) and (min-width: 1281px) {
  492 + .image-name {
  493 + display: block;
  494 + margin-top: 5px;
  495 + font-size: 16px;
  496 + width: 180px;
  497 + color: #555;
  498 + text-align: left;
  499 + margin-left: 10px;
  500 + }
  501 +}
  502 +
  503 +button .recommendButton {
  504 + margin: 0 0px;
  505 + cursor: pointer;
  506 +}
  507 +
  508 +.recommend-left-box {
  509 +}
  510 +
  511 +.recommend-img-left {
  512 + width: 26px;
  513 + height: 27px;
  514 + margin-right: 30px;
  515 +}
  516 +
  517 +.recommend-img-left:hover {
  518 + cursor: pointer;
  519 +}
  520 +.recommend-right-box {
  521 +}
  522 +
  523 +.recommend-img-right {
  524 + width: 26px;
  525 + height: 27px;
  526 + margin-left: 30px;
  527 +}
  528 +
  529 +.recommend-img-right:hover {
  530 + cursor: pointer;
  531 +}
288 532 </style>
... ...