Commit 5010e9d9de03d2426c2b46cc7ab63e3e0e7970b0

Authored by boyang
1 parent 9b642ad1

feat: title对应产品名,meta动态获取

components/ProductDetail.vue
... ... @@ -2,9 +2,19 @@
2 2 <v-container>
3 3 <v-row class="mb-16 ma-0">
4 4 <v-col cols="12" sm="5">
5   - <v-carousel class="tw-float-left" height="450" v-model="slide" hide-delimiter-background>
6   - <v-carousel-item cover v-for="(slide, i) in info.productimageliststore" :src="slide.url" :key="i"
7   - :alt="info.name">
  5 + <v-carousel
  6 + class="tw-float-left"
  7 + height="450"
  8 + v-model="slide"
  9 + hide-delimiter-background
  10 + >
  11 + <v-carousel-item
  12 + cover
  13 + v-for="(slide, i) in info.productimageliststore"
  14 + :src="slide.url"
  15 + :key="i"
  16 + :alt="info.name"
  17 + >
8 18 </v-carousel-item>
9 19 </v-carousel>
10 20 </v-col>
... ... @@ -14,42 +24,90 @@
14 24 </v-row>
15 25 <div class="tw-flex tw-flex-wrap">
16 26 <div class="tw-w-1/2">
17   - <span class="tw-leading-[10px] tw-m-[16px]"> Brand:{{ info.brandName }} </span>
  27 + <span class="tw-leading-[10px] tw-m-[16px]">
  28 + Brand:{{ info.brandName }}
  29 + </span>
18 30 </div>
19 31 <div class="tw-w-1/2 tw-mb-[12px]">
20   - <span class="tw-leading-[10px] tw-m-[16px]">Product Model:{{ info.model }}</span>
  32 + <span class="tw-leading-[10px] tw-m-[16px]"
  33 + >Product Model:{{ info.model }}</span
  34 + >
21 35 </div>
22 36 <div class="tw-w-1/2 tw-mb-[12px]" v-if="info.basename1">
23   - <span class="tw-leading-[10px] tw-m-[16px]">{{ info.basename1 }}:{{ info.basecore1 }}</span>
  37 + <span class="tw-leading-[10px] tw-m-[16px]"
  38 + >{{ info.basename1 }}:{{ info.basecore1 }}</span
  39 + >
24 40 </div>
25 41 <div class="tw-w-1/2 tw-mb-[12px]" v-if="info.basename2">
26   - <span class="tw-leading-[10px] tw-m-[16px]">{{ info.basename2 }}:{{ info.basecore2 }}</span>
  42 + <span class="tw-leading-[10px] tw-m-[16px]"
  43 + >{{ info.basename2 }}:{{ info.basecore2 }}</span
  44 + >
27 45 </div>
28 46 <div class="tw-w-1/2 tw-mb-[12px]" v-if="info.basename3">
29   - <span class="tw-leading-[10px] tw-m-[16px]">{{ info.basename3 }}:{{ info.basecore3 }}</span>
  47 + <span class="tw-leading-[10px] tw-m-[16px]"
  48 + >{{ info.basename3 }}:{{ info.basecore3 }}</span
  49 + >
30 50 </div>
31 51 </div>
32   - <div class="tw-flex tw-flex-wrap" v-if="info.productAttributeList && info.productAttributeList.length > 0">
33   - <div v-for="(attribute, index) in info.productAttributeList" :key="index" class="tw-w-1/2 tw-mb-[12px]">
34   - <span class="tw-leading-[10px] tw-m-[16px]">{{ attribute.name }}:{{ attribute.value }}</span>
  52 + <div
  53 + class="tw-flex tw-flex-wrap"
  54 + v-if="
  55 + info.productAttributeList && info.productAttributeList.length > 0
  56 + "
  57 + >
  58 + <div
  59 + v-for="(attribute, index) in info.productAttributeList"
  60 + :key="index"
  61 + class="tw-w-1/2 tw-mb-[12px]"
  62 + >
  63 + <span class="tw-leading-[10px] tw-m-[16px]"
  64 + >{{ attribute.name }}:{{ attribute.value }}</span
  65 + >
35 66 </div>
36 67 </div>
37   - <v-table density="comfortable" class="table1 tw-mt-[32px]" v-if="info.ticketTypes?.length">
  68 + <v-table
  69 + density="comfortable"
  70 + class="table1 tw-mt-[32px]"
  71 + v-if="info.ticketTypes?.length"
  72 + >
38 73 <thead>
39 74 <tr class="bg-grey-lighten-3">
40   - <th class="text-left headerBorder text-grey-darken-1">Product Name / Code</th>
41   - <th class="text-left headerBorder text-grey-darken-1">Specification and model</th>
42   - <th v-if="info.priceShow!==undefined && info.priceShow" class="text-left headerBorder text-grey-darken-1">Price</th>
  75 + <th class="text-left headerBorder text-grey-darken-1">
  76 + Product Name / Code
  77 + </th>
  78 + <th class="text-left headerBorder text-grey-darken-1">
  79 + Specification and model
  80 + </th>
  81 + <th
  82 + v-if="info.priceShow !== undefined && info.priceShow"
  83 + class="text-left headerBorder text-grey-darken-1"
  84 + >
  85 + Price
  86 + </th>
43 87 <th class="text-left headerBorder text-grey-darken-1">Actions</th>
44 88 </tr>
45 89 </thead>
46 90 <tbody>
47   - <tr class="tr" v-for="item in info.ticketTypes || []" :key="item.rank">
48   - <td class="td text-grey-darken-4 font-weight-medium">{{ item.rank }}</td>
49   - <td class="td text-grey-darken-4 font-weight-medium">{{ item.typeName }}</td>
50   - <td v-if="item.priceShow" class="td">{{ item.price+" "+item.priceUnit }}</td>
  91 + <tr
  92 + class="tr"
  93 + v-for="item in info.ticketTypes || []"
  94 + :key="item.rank"
  95 + >
  96 + <td class="td text-grey-darken-4 font-weight-medium">
  97 + {{ item.rank }}
  98 + </td>
  99 + <td class="td text-grey-darken-4 font-weight-medium">
  100 + {{ item.typeName }}
  101 + </td>
  102 + <td v-if="item.priceShow" class="td">
  103 + {{ item.price + " " + item.priceUnit }}
  104 + </td>
51 105 <td class="td">
52   - <v-btn size="small" color="blue-darken-1" @click="router.push('/contact')">
  106 + <v-btn
  107 + size="small"
  108 + color="blue-darken-1"
  109 + @click="router.push('/contact')"
  110 + >
53 111 <!-- Quotation Inquiry -->
54 112 Quote
55 113 </v-btn>
... ... @@ -63,8 +121,14 @@
63 121 </v-col>
64 122 </v-row>
65 123 <div class="tw-pb-[64px]">
66   - <v-tabs class="tabs" v-model="tab" color="white" bg-color="#eeeeee" slider-color="blue-lighten-1"
67   - selected-class="active">
  124 + <v-tabs
  125 + class="tabs"
  126 + v-model="tab"
  127 + color="white"
  128 + bg-color="#eeeeee"
  129 + slider-color="blue-lighten-1"
  130 + selected-class="active"
  131 + >
68 132 <v-tab :value="1">Product Details</v-tab>
69 133 <v-tab :value="2">Specification</v-tab>
70 134 <!-- <v-tab :value="3">商品百科</v-tab> -->
... ... @@ -100,7 +164,11 @@
100 164 <v-window-item key="2" :value="2">
101 165 <v-table density="compact" class="table2">
102 166 <tbody>
103   - <tr class="tr" v-for="item in info.productAttributeList || []" :key="item.name">
  167 + <tr
  168 + class="tr"
  169 + v-for="item in info.productAttributeList || []"
  170 + :key="item.name"
  171 + >
104 172 <td class="td tw-w-[400px]">{{ item.name }}</td>
105 173 <td class="td">{{ item.value }}</td>
106 174 </tr>
... ... @@ -114,23 +182,23 @@
114 182 </template>
115 183  
116 184 <script setup lang="ts">
117   -import type { Product, ProductImage } from '~/type'
118   -import { onMounted, ref } from 'vue'
119   -import { useDialogStore } from '~/stores/dialog'
120   -const dialogStore = useDialogStore()
  185 +import type { Product, ProductImage } from "~/type";
  186 +import { onMounted, ref } from "vue";
  187 +import { useDialogStore } from "~/stores/dialog";
  188 +const dialogStore = useDialogStore();
121 189  
122 190 const props = defineProps<{
123   - info: Product
124   -}>()
125   -const info = props.info
  191 + info: Product;
  192 +}>();
  193 +const info = props.info;
126 194  
127 195 // onMounted(() => {
128 196 // dialogStore.updateDialog(true)
129 197 // })
130 198  
131   -const tab = ref(0)
132   -const slide = ref(0)
133   -const router = useRouter()
  199 +const tab = ref(0);
  200 +const slide = ref(0);
  201 +const router = useRouter();
134 202 </script>
135 203  
136 204 <style lang="scss" scoped>
... ...
nuxt.config.ts
1 1 // https://nuxt.com/docs/api/configuration/nuxt-config
2 2 // Nuxt config file
3   -import { defineNuxtConfig } from 'nuxt/config'
  3 +import { defineNuxtConfig } from "nuxt/config";
4 4  
5 5 export default defineNuxtConfig({
6 6 app: {
7 7 head: {
8   - link: [
9   - { rel: 'icon', type: 'image/x-icon', href: '/fav.ico' }
10   - ]
11   - }
  8 + link: [{ rel: "icon", type: "image/x-icon", href: "/fav.ico" }],
  9 + },
12 10 },
13   - css: ['~/assets/css/main.css'],
  11 + css: ["~/assets/css/main.css"],
14 12 postcss: {
15 13 plugins: {
16 14 tailwindcss: {},
... ... @@ -22,45 +20,40 @@ export default defineNuxtConfig({
22 20 // baseURL: 'http://47.89.254.121:8002/shop' || 'http://39.108.227.113:8002' // Exposed to the frontend as well.
23 21 // }
24 22 // },
25   - modules: [
26   - 'vuetify-nuxt-module',
27   - '@pinia/nuxt',
28   - '@nuxtjs/i18n',
29   - ],
  23 + modules: ["vuetify-nuxt-module", "@pinia/nuxt", "@nuxtjs/i18n"],
30 24 vuetify: {
31 25 moduleOptions: {
32 26 /* module specific options */
33 27 },
34 28 vuetifyOptions: {
35 29 /* vuetify options */
36   - }
  30 + },
37 31 },
38   - nitro:{
  32 + nitro: {
39 33 devProxy: {
40   - '/shop': {
41   - target: 'http://47.89.254.121:8002/shop', // 线上代理地址
42   - // target: 'http://127.0.0.1:8002/shop/**',
  34 + "/shop": {
  35 + // target: "http://47.89.254.121:8002/shop", // 线上代理地址
  36 + target: "http://127.0.0.1:8002/shop/**",
43 37 // target: process.env.BASE_URL || 'http://39.108.227.113:8002/shop', // 目标接口域名
44 38 changeOrigin: true, // 表示是否跨域
45   - }
  39 + },
46 40 },
47   - // 该配置用于服务端请求转发
48   - routeRules: {
49   - '/shop/**': {
50   - proxy: 'http://47.89.254.121:8002/shop/**'
51   - // proxy: 'http://127.0.0.1:8002/shop/**'
  41 + // 该配置用于服务端请求转发
  42 + routeRules: {
  43 + "/shop/**": {
  44 + // proxy: "http://47.89.254.121:8002/shop/**",
  45 + proxy: "http://127.0.0.1:8002/shop/**",
52 46 // proxy: process.env.BASE_URL || 'http://39.108.227.113:8002/shop/**'
53   - }
54   - }
  47 + },
  48 + },
55 49 },
56 50 i18n: {
57 51 locales: [
58   - { code: 'en', iso: 'en-US', file: 'en.json' },
59   - { code: 'zh', iso: 'zh-CN', file: 'zh.json' }
  52 + { code: "en", iso: "en-US", file: "en.json" },
  53 + { code: "zh", iso: "zh-CN", file: "zh.json" },
60 54 ],
61 55 lazy: true,
62   - langDir: 'locales/',
63   - defaultLocale: 'zh',
  56 + langDir: "locales/",
  57 + defaultLocale: "zh",
64 58 },
65   -})
66   -
  59 +});
... ...
pages/products/detail/[id]/index.vue
... ... @@ -4,59 +4,73 @@
4 4 </template>
5 5  
6 6 <script setup lang="ts">
7   -import { onMounted } from 'vue'
8   -import ProductDetail from '~/components/ProductDetail.vue'
9   -import MobileProductDetail from '~/components/MobileProductDetail.vue'
10   -import type { Product, ProductImage } from '~/type'
11   -import { useRoute } from 'vue-router'
  7 +import { onMounted } from "vue";
  8 +import ProductDetail from "~/components/ProductDetail.vue";
  9 +import MobileProductDetail from "~/components/MobileProductDetail.vue";
  10 +import type { Product, ProductImage } from "~/type";
  11 +import { useRoute, useRouter } from "vue-router";
12 12  
13   -const route = useRoute()
  13 +const route = useRoute();
14 14  
15 15 const info = ref<Partial<Product>>({
16 16 productimageliststore: [],
17 17 productAttributeList: [],
18   - name: '',
19   - ticketTypes: []
20   -})
  18 + name: "",
  19 + ticketTypes: [],
  20 +});
21 21  
22   -let { data: resData } = await useAsyncData('detail', () => $fetch('/shop/product/detail', {
23   - method: 'GET',
24   - params: {
25   - id: route.params.id
  22 +let { data: resData } = await useAsyncData(
  23 + "detail",
  24 + () =>
  25 + $fetch("/shop/product/detail", {
  26 + method: "GET",
  27 + params: {
  28 + id: route.params.id,
  29 + },
  30 + }),
  31 + {
  32 + server: true, // 仅在服务器端获取数据
26 33 }
27   -}), {
28   - server: true // 仅在服务器端获取数据
29   -})
  34 +);
  35 +watchEffect(() => {
  36 + console.log(info.value, "5656infovalue2/resData.value.", resData.value);
  37 + useHead({
  38 + title: info.value.name || "canrud",
  39 + meta: [
  40 + {
  41 + name: "title",
  42 + content:
  43 + info.value.name ||
  44 + "科路得,Equipment,High-precision,Machining center,Design,Manufacturing capabilities,Equipment supply,Production line planning,Construction services,Battery assembly lines,Pouch cell testing lines",
  45 + },
  46 + {
  47 + name: "keywords",
  48 + content:
  49 + info.value.metakeywords ||
  50 + "科路得,Equipment,High-precision,Machining center,Design,Manufacturing capabilities,Equipment supply,Production line planning,Construction services,Battery assembly lines,Pouch cell testing lines",
  51 + },
  52 + {
  53 + name: "description",
  54 + content:
  55 + info.value.metadescription ||
  56 + "科路得,助您科研之路势在必得。Equipment Business: With our self-built high-precision machining center, we possess robust design and manufacturing capabilities. We offer comprehensive equipment supply, production line planning, and construction services, including battery assembly lines, pouch cell testing lines, and more. Our aim is to provide complete equipment solutions that cater to the diverse needs of our clients. Expect top-quality equipment and professional services that will help you stand out in a fiercely competitive market!",
  57 + },
  58 + ],
  59 + });
  60 +});
30 61  
31   -useHead({
32   - title: info.name || 'canrud',
33   - meta: [
34   - {
35   - name: 'title',
36   - content:
37   - '科路得,Equipment,High-precision,Machining center,Design,Manufacturing capabilities,Equipment supply,Production line planning,Construction services,Battery assembly lines,Pouch cell testing lines',
38   - }, {
39   - name: 'keywords',
40   - content:
41   - '科路得,Equipment,High-precision,Machining center,Design,Manufacturing capabilities,Equipment supply,Production line planning,Construction services,Battery assembly lines,Pouch cell testing lines',
42   - }, {
43   - name: 'description',
44   - content:
45   - '科路得,助您科研之路势在必得。Equipment Business: With our self-built high-precision machining center, we possess robust design and manufacturing capabilities. We offer comprehensive equipment supply, production line planning, and construction services, including battery assembly lines, pouch cell testing lines, and more. Our aim is to provide complete equipment solutions that cater to the diverse needs of our clients. Expect top-quality equipment and professional services that will help you stand out in a fiercely competitive market!'
46   - },
47   - ],
48   -})
49   -
50   -const newData: Product = resData.value.data
51   -
52   -newData.productimageliststore = typeof newData.productimageliststore === 'string' ?
53   - (JSON.parse(newData.productimageliststore) || []) :
54   - newData.productimageliststore as ProductImage[]
55   -newData.productimageliststore = newData?.productimageliststore.map((item: ProductImage) => ({
56   - ...item,
57   - // url: `http://112.74.45.244:8100/api/show/image?fileKey=${item.fileKey}`
58   - url: `/api/show/image?fileKey=${item.fileKey}`
59   -}))
60   -info.value = { ...newData }
  62 +const newData: Product = resData.value.data;
61 63  
  64 +newData.productimageliststore =
  65 + typeof newData.productimageliststore === "string"
  66 + ? JSON.parse(newData.productimageliststore) || []
  67 + : (newData.productimageliststore as ProductImage[]);
  68 +newData.productimageliststore = newData?.productimageliststore.map(
  69 + (item: ProductImage) => ({
  70 + ...item,
  71 + // url: `http://112.74.45.244:8100/api/show/image?fileKey=${item.fileKey}`
  72 + url: `/api/show/image?fileKey=${item.fileKey}&psize=p256`,
  73 + })
  74 +);
  75 +info.value = { ...newData };
62 76 </script>
... ...
pages/products/index.vue
... ... @@ -4,14 +4,31 @@
4 4 <MobileCategoryList v-if="categoryStore.categoryVisible && isMobile()" />
5 5 <v-container class="">
6 6 <div class="tw-text-center" v-if="loading">
7   - <v-progress-circular color="blue-lighten-2" indeterminate size="64" class="tw-m-auto"></v-progress-circular>
  7 + <v-progress-circular
  8 + color="blue-lighten-2"
  9 + indeterminate
  10 + size="64"
  11 + class="tw-m-auto"
  12 + ></v-progress-circular>
8 13 </div>
9 14 <v-item-group multiple>
10 15 <v-row v-if="!loading">
11   - <v-col v-for="(item, i) in productStore.list" :key="i" cols="6" lg="3" md="4" sm="6">
  16 + <v-col
  17 + v-for="(item, i) in productStore.list"
  18 + :key="i"
  19 + cols="6"
  20 + lg="3"
  21 + md="4"
  22 + sm="6"
  23 + >
12 24 <v-hover v-slot="{ isHovering, props }" open-delay="200">
13   - <v-card :elevation="isHovering ? 16 : 2" :class="{ 'on-hover': isHovering }" class="mx-auto"
14   - v-bind="props" :to="`/products/detail/${item.id}`">
  25 + <v-card
  26 + :elevation="isHovering ? 16 : 2"
  27 + :class="{ 'on-hover': isHovering }"
  28 + class="mx-auto"
  29 + v-bind="props"
  30 + :to="`/products/detail/${item.id}`"
  31 + >
15 32 <v-img :src="item.imgList[0].url" :alt="item.name">
16 33 <!-- <v-expand-transition>
17 34 <div
... ... @@ -24,100 +41,113 @@
24 41 </v-expand-transition> -->
25 42 </v-img>
26 43 <v-card-text class="tw-text-left font-weight-medium title">
27   - <h4>{{
28   - item.name
29   - }}</h4>
  44 + <h4>{{ item.name }}</h4>
30 45 </v-card-text>
31 46 </v-card>
32 47 </v-hover>
33 48 </v-col>
34 49 </v-row>
35   - <div v-if="!productStore.total && !loading" class="text-medium-emphasis text-body-1 tw-text-center tw-m-[64px]">
  50 + <div
  51 + v-if="!productStore.total && !loading"
  52 + class="text-medium-emphasis text-body-1 tw-text-center tw-m-[64px]"
  53 + >
36 54 no data
37 55 </div>
38 56 </v-item-group>
39 57 <v-row>
40 58 <v-col>
41   - <v-pagination :size="isMobile() ? 'small' : 'default'" v-if="productStore.total" v-model="productStore.pageNo"
42   - @update:modelValue="productStore.updatePageNo" :length="length" rounded="0"
43   - class="tw-float-right tw-mt-[32px]" total-visible="5"></v-pagination></v-col></v-row>
  59 + <v-pagination
  60 + :size="isMobile() ? 'small' : 'default'"
  61 + v-if="productStore.total"
  62 + v-model="productStore.pageNo"
  63 + @update:modelValue="productStore.updatePageNo"
  64 + :length="length"
  65 + rounded="0"
  66 + class="tw-float-right tw-mt-[32px]"
  67 + total-visible="5"
  68 + ></v-pagination></v-col
  69 + ></v-row>
44 70 </v-container>
45 71 </div>
46 72 </template>
47 73  
48 74 <script setup lang="ts">
49   -import { isMobile, isEqual } from '~/utils'
50   -import { useProductListStore } from '~/stores/product_list'
51   -import { useCategoryStore } from '~/stores/category'
52   -import CategoryList from '~/components/CategoryList.vue'
53   -import MobileCategoryList from '~/components/MobileCategoryList.vue'
54   -import { watchEffect, computed, ref } from 'vue'
  75 +import { isMobile, isEqual } from "~/utils";
  76 +import { useProductListStore } from "~/stores/product_list";
  77 +import { useCategoryStore } from "~/stores/category";
  78 +import CategoryList from "~/components/CategoryList.vue";
  79 +import MobileCategoryList from "~/components/MobileCategoryList.vue";
  80 +import { watchEffect, computed, ref } from "vue";
55 81  
56   -const productStore = useProductListStore()
57   -const categoryStore = useCategoryStore()
58   -const loading = ref(false)
59   -const route = useRoute() // 获取路由信息
60   -useHead({
61   - title: 'canrud',
62   - meta: [{
63   - name: 'title',
64   - 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!"
65   - }, {
66   - name: 'keywords',
67   - content:
68   - '科路得,canrd,canrud,Energy Storage Research,Lithium Batteries Research,Material Reagents,Lab Device,Customized Battery,Testing,Pack',
69   - },
70   - {
71   - name: 'description',
72   - content:
73   - '科路得,助您科研之路势在必得。We offer a wide range of research materials and related equipment, technical services, and battery material performance evaluation in areas such as pouch cells, lithium-ion batteries, supercapacitors, lithium-sulfur batteries, fuel cells, lithium-air batteries, and sodium-ion batteries.'
74   - }
75   - ]
76   -})
  82 +const productStore = useProductListStore();
  83 +const categoryStore = useCategoryStore();
  84 +const loading = ref(false);
  85 +const route = useRoute(); // 获取路由信息
77 86  
  87 +useHead({
  88 + title: "canrud",
  89 + meta: [
  90 + {
  91 + name: "title",
  92 + content:
  93 + "科路得,助您科研之路势在必得。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!",
  94 + },
  95 + {
  96 + name: "keywords",
  97 + content:
  98 + "科路得,canrd,canrud,Energy Storage Research,Lithium Batteries Research,Material Reagents,Lab Device,Customized Battery,Testing,Pack",
  99 + },
  100 + {
  101 + name: "description",
  102 + content:
  103 + "科路得,助您科研之路势在必得。We offer a wide range of research materials and related equipment, technical services, and battery material performance evaluation in areas such as pouch cells, lithium-ion batteries, supercapacitors, lithium-sulfur batteries, fuel cells, lithium-air batteries, and sodium-ion batteries.",
  104 + },
  105 + ],
  106 +});
78 107  
79 108 const loadProducts = async () => {
80 109 let params: any = {
81 110 pageNo: productStore.pageNo,
82   - pageSize: 20
83   - }
  111 + pageSize: 20,
  112 + };
84 113  
85   - loading.value = true
  114 + loading.value = true;
86 115 if (productStore.keyword && !isEqual(productStore.params, params)) {
87   - params.keyword = productStore.keyword
88   - productStore.updateParams(params)
89   - await productStore.getList(params)
90   - loading.value = false
91   - return
  116 + params.keyword = productStore.keyword;
  117 + productStore.updateParams(params);
  118 + await productStore.getList(params);
  119 + loading.value = false;
  120 + return;
92 121 }
93 122  
94   - params.productCategoryId = categoryStore.selectedSubCategory
  123 + params.productCategoryId = categoryStore.selectedSubCategory;
95 124 // productCategoryId: '78b86c6e917841cf9a292234f2805e24',
96 125  
97 126 if (categoryStore.selectedFuncCategory) {
98   - params.productFunctionId = categoryStore.selectedFuncCategory
  127 + params.productFunctionId = categoryStore.selectedFuncCategory;
99 128 }
100 129  
101   - if (categoryStore.selectedSubCategory && !isEqual(productStore.params, params)) {
102   - productStore.updateParams(params)
  130 + if (
  131 + categoryStore.selectedSubCategory &&
  132 + !isEqual(productStore.params, params)
  133 + ) {
  134 + productStore.updateParams(params);
103 135  
104   - await productStore.getList(params)
  136 + await productStore.getList(params);
105 137 }
106   - loading.value = false
107   -}
108   -
109   -
  138 + loading.value = false;
  139 +};
110 140  
111 141 watchEffect(async () => {
112   - if(route.query.keyword !== undefined){
113   - productStore.keyword = route.query.keyword
  142 + if (route.query.keyword !== undefined) {
  143 + productStore.keyword = route.query.keyword;
114 144 }
115 145 loadProducts();
116   -})
  146 +});
117 147  
118 148 const length = computed(() =>
119 149 productStore.total ? Math.ceil(productStore.total / productStore.pageSize) : 0
120   -)
  150 +);
121 151 </script>
122 152  
123 153 <style scoped>
... ...
stores/product_list.ts
1   -import { getProductList } from './../service'
2   -import { ref, watchEffect } from 'vue'
3   -import { defineStore } from 'pinia'
4   -import type { Product, ProductImage, ProductListQuery } from '@/type'
  1 +import { getProductList } from "./../service";
  2 +import { ref, watchEffect } from "vue";
  3 +import { defineStore } from "pinia";
  4 +import type { Product, ProductImage, ProductListQuery } from "@/type";
5 5  
6   -export const useProductListStore = defineStore('productList', () => {
7   - const list = ref<Product[]>([])
8   - const productCategoryId = ref('') // 选中的类别
9   - const keyword = ref()
10   - const pageNo = ref(1)
11   - const pageSize = ref(20)
12   - const total = ref(0)
13   - const params = ref()
  6 +export const useProductListStore = defineStore("productList", () => {
  7 + const list = ref<Product[]>([]);
  8 + const productCategoryId = ref(""); // 选中的类别
  9 + const keyword = ref();
  10 + const pageNo = ref(1);
  11 + const pageSize = ref(20);
  12 + const total = ref(0);
  13 + const params = ref();
14 14  
15 15 const getList = async (params: ProductListQuery) => {
16 16 if (params.productCategoryId || params.keyword) {
17   - const { data } = await useAsyncData('product', () => $fetch('/shop/product/list', {
18   - method: 'GET',
19   - params: {
20   - ...params,
21   - pageNo: pageNo.value,
22   - pageSize: pageSize.value
23   - }
24   - }));
25   -
  17 + const { data } = await useAsyncData("product", () =>
  18 + $fetch("/shop/product/list", {
  19 + method: "GET",
  20 + params: {
  21 + ...params,
  22 + pageNo: pageNo.value,
  23 + pageSize: pageSize.value,
  24 + },
  25 + })
  26 + );
  27 +
26 28 list.value =
27 29 (data.value?.data?.records || []).map((record: Product) => ({
28 30 ...record,
29 31 // http://112.74.45.244:8100/api/show/image?fileKey=ac82abea34243b7f7a56e5c3ca03f3a9
30   - imgList: JSON.parse(record.productimageliststore as unknown as string).map(
31   - (item: ProductImage) => ({
32   - url: `/api/show/image?fileKey=${item.fileKey}&psize=p256`
33   - })
34   - )
35   - })) || []
36   - total.value = data.value?.data?.total || 0
  32 + imgList: JSON.parse(
  33 + record.productimageliststore as unknown as string
  34 + ).map((item: ProductImage) => ({
  35 + url: `/api/show/image?fileKey=${item.fileKey}&psize=p256`,
  36 + })),
  37 + })) || [];
  38 + total.value = data.value?.data?.total || 0;
37 39 }
38   - }
  40 + };
39 41  
40 42 const updatePageNo = (value: number) => {
41   - pageNo.value = value
42   - }
  43 + pageNo.value = value;
  44 + };
43 45  
44 46 const updateCategory = (value: string) => {
45   - productCategoryId.value = value
46   - }
  47 + productCategoryId.value = value;
  48 + };
47 49  
48 50 const updateParams = (value: any) => {
49   - params.value = value
50   - }
  51 + params.value = value;
  52 + };
51 53  
52 54 const updateKeyword = (value: string) => {
53   - keyword.value = value
54   - }
  55 + keyword.value = value;
  56 + };
55 57  
56 58 return {
57 59 pageNo,
... ... @@ -64,6 +66,6 @@ export const useProductListStore = defineStore(&#39;productList&#39;, () =&gt; {
64 66 updateCategory,
65 67 updatePageNo,
66 68 updateParams,
67   - updateKeyword
68   - }
69   -})
  69 + updateKeyword,
  70 + };
  71 +});
... ...