Commit cebe6b62b85329de35cae08a1592036d65eada2e

Authored by boyang
2 parents 4f32bba1 fa35f0cf

Merge branch 'by'

components/CategoryList.vue
... ... @@ -79,7 +79,9 @@ import { useProductListStore } from "@/stores/product_list";
79 79 import type { CategoryRootType } from "@/type";
80 80 import { computed } from "vue";
81 81 import { useRouter, useRoute } from "vue-router";
  82 +import { useRouteQuery } from "@/stores/route_query";
82 83  
  84 +const routeQuery = useRouteQuery();
83 85 const route = useRoute();
84 86 const router = useRouter();
85 87  
... ... @@ -91,11 +93,13 @@ watchEffect(async () => {
91 93 productStore.updateKeyword("");
92 94 const categories = route.query.categories.split(",");
93 95 const mainCategory = categories[0].trim(); // 取第一个值
94   - const subCategoryName = categories[1] ? categories[1].trim() : null; // 取第二个值(如果存在)
  96 + const subCategoryName = categories[1]
  97 + ? categories[1].trim()
  98 + : "Not specified"; // 取第二个值(如果存在)
95 99  
96 100 // 2. 更新选中的主分类
97 101 categoryStore.updateCategory(mainCategory);
98   -
  102 + routeQuery.updateCategories(mainCategory + "," + subCategoryName);
99 103 // 3. 如果有子分类名称,查找其对应的 ID
100 104 if (subCategoryName) {
101 105 const subCategoryList = computed(() => {
... ... @@ -123,6 +127,7 @@ watchEffect(async () => {
123 127 // 5. 判断 query 中是否存在 function,并查找对应的 ID
124 128 if (route.query.function) {
125 129 const functionName = route.query.function.trim();
  130 + routeQuery.updateFunction(functionName);
126 131 const funcCategoryList = computed(() => {
127 132 if (categoryStore.selectedCategory) {
128 133 const tmp = categoryStore.list.filter(
... ... @@ -152,8 +157,23 @@ watchEffect(async () => {
152 157 // // 使用找到的 funcCategoryId
153 158 // categoryStore.updateFuncCategory(funcCategoryId);
154 159 // }
  160 + } else if (route.query.categories.includes("Energy materials")) {
  161 + const defaultCategory = categoryStore.list[0];
  162 + const defaultFuncCategory = defaultCategory.productFunctions[0];
  163 + if (defaultFuncCategory) {
  164 + categoryStore.updateFuncCategory(defaultFuncCategory.id);
  165 + }
  166 + router.push({
  167 + query: {
  168 + categories: route.query.categories,
  169 + function: defaultFuncCategory.name,
  170 + },
  171 + });
155 172 }
156   - } else if (Object.keys(route.query).length === 0) {
  173 + } else if (
  174 + Object.keys(route.query).length === 0 &&
  175 + !route.path.includes("/products/detail")
  176 + ) {
157 177 // 检查是否有默认的分类
158 178 const defaultCategory = categoryStore.list[0]; // 假设第一个分类是默认的
159 179  
... ...
components/ProductDetail.vue
1 1 <template>
2 2 <v-container>
  3 + <div>
  4 + <v-breadcrumbs divider="/" style="padding-top: 0">
  5 + <template v-for="(item, index) in items" :key="index">
  6 + <v-breadcrumbs-item
  7 + :disabled="item.disabled"
  8 + :href="item.href"
  9 + :class="{
  10 + 'breadcrumb-disabled': item.disabled,
  11 + 'breadcrumb-active': !item.disabled,
  12 + }"
  13 + >
  14 + {{ item.title }}
  15 + </v-breadcrumbs-item>
  16 +
  17 + <!-- 添加分隔符,排除最后一个 item -->
  18 + <span v-if="index < items.length - 1" class="breadcrumb-divider"
  19 + >/</span
  20 + >
  21 + </template>
  22 + <span class="breadcrumb-divider">/</span>
  23 + <span style="margin-left: 5px">{{ info.name }}</span>
  24 + </v-breadcrumbs>
  25 + </div>
3 26 <v-row class="mb-16 ma-0">
4   - <v-col cols="12" sm="5">
  27 + <v-col cols="12" sm="5" class="carousel-container">
5 28 <v-carousel
6   - class="tw-float-left"
  29 + class="tw-float-left tw-sticky tw-top-[16px]"
7 30 height="450"
8 31 v-model="slide"
9 32 hide-delimiter-background
  33 + style="top: 16px"
10 34 >
11 35 <v-carousel-item
12 36 cover
... ... @@ -18,10 +42,11 @@
18 42 </v-carousel-item>
19 43 </v-carousel>
20 44 </v-col>
21   - <v-col cols="12" sm="7">
22   - <v-row class="bg-white mb-sm-10 text-h4 font-weight-medium">
  45 + <v-col cols="12" sm="7" class="table-container">
  46 + <!-- <v-row class="bg-white mb-sm-10 text-h4 font-weight-medium">
23 47 <v-col>{{ info.name }}</v-col>
24   - </v-row>
  48 + </v-row> -->
  49 + <h1>{{ info.name }}</h1>
25 50 <div class="tw-flex tw-flex-wrap">
26 51 <div class="tw-w-1/2">
27 52 <span class="tw-leading-[10px] tw-m-[16px]">
... ... @@ -65,10 +90,15 @@
65 90 >
66 91 </div>
67 92 </div>
68   - <v-table
  93 + <!-- <v-table
69 94 density="comfortable"
70 95 class="table1 tw-mt-[32px]"
71 96 v-if="info.ticketTypes?.length"
  97 + > -->
  98 + <v-table
  99 + density="comfortable"
  100 + class="table1 tw-mt-[32px] tw-overflow-x-auto"
  101 + v-if="info.ticketTypes?.length"
72 102 >
73 103 <thead>
74 104 <tr class="bg-grey-lighten-3">
... ... @@ -145,7 +175,7 @@
145 175 <v-divider class="tw-mb-[12px]"></v-divider>
146 176 <div v-html="info.physicalproperty"></div>
147 177 </div>
148   - <div v-if="info.advantage" class="tw-mb-[24px]">
  178 + <div v-if="info.storage" class="tw-mb-[24px]">
149 179 <div class="text-h6">Storage</div>
150 180 <v-divider class="tw-mb-[12px]"></v-divider>
151 181 <div v-html="info.storage"></div>
... ... @@ -155,7 +185,7 @@
155 185 <v-divider class="tw-mb-[12px]"></v-divider>
156 186 <div v-html="info.introduction"></div>
157 187 </div>
158   - <div v-if="info.advantage" class="tw-mb-[24px]">
  188 + <div v-if="info.description" class="tw-mb-[24px]">
159 189 <div class="text-h6">Description</div>
160 190 <v-divider class="tw-mb-[12px]"></v-divider>
161 191 <div v-html="info.description"></div>
... ... @@ -185,20 +215,116 @@
185 215 import type { Product, ProductImage } from "~/type";
186 216 import { onMounted, ref } from "vue";
187 217 import { useDialogStore } from "~/stores/dialog";
  218 +import { useRouter, useRoute } from "vue-router";
  219 +import { useRouteQuery } from "@/stores/route_query";
  220 +
  221 +const route = useRoute();
  222 +const router = useRouter();
  223 +const routeQuery = useRouteQuery();
188 224 const dialogStore = useDialogStore();
  225 +const href1 = ref("/products");
  226 +const href2 = ref("/products");
  227 +// 定义单个 item 的接口
  228 +interface BreadcrumbItem {
  229 + title: string; // 标题
  230 + disabled: boolean; // 是否禁用
  231 + href: string; // 链接地址
  232 +}
  233 +
  234 +// 示例数据
  235 +const items = ref<BreadcrumbItem[]>([
  236 + {
  237 + title: "Products",
  238 + disabled: false,
  239 + href: "/products",
  240 + },
  241 + {
  242 + title: "CATEGORY",
  243 + disabled: false,
  244 + href: href1.value,
  245 + },
  246 + {
  247 + title: "DEVICE TYPE",
  248 + disabled: false,
  249 + href: href2.value,
  250 + },
  251 + {
  252 + title: "FUNCTION",
  253 + disabled: false,
  254 + href: "/products",
  255 + },
  256 + // {
  257 + // title: "TITLE",
  258 + // disabled: false,
  259 + // href: "",
  260 + // },
  261 +]);
189 262  
190 263 const props = defineProps<{
191 264 info: Product;
192 265 }>();
193 266 const info = props.info;
194   -
  267 +watchEffect(() => {
  268 + if (routeQuery.categories) {
  269 + if (!routeQuery.categories.includes("Energy materials")) {
  270 + routeQuery.updateFunction("Not specified");
  271 + }
  272 + const categories = routeQuery.categories.split(",");
  273 + const mainCategory = categories[0].trim(); // 取第一个值
  274 + const subCategoryName = ref(
  275 + categories[1] ? categories[1].trim() : "Not specified"
  276 + ); // 取第二个值(如果存在)
  277 + if (subCategoryName.value == "Accessories & fixtures") {
  278 + subCategoryName.value = encodeURIComponent("Accessories & fixtures");
  279 + items.value[2].title = "Accessories & fixtures";
  280 + } else {
  281 + items.value[2].title = subCategoryName.value;
  282 + }
  283 + items.value[1].title = mainCategory;
  284 + items.value[1].href = href1.value + "?categories=" + mainCategory;
  285 + href1.value = href1.value + "?categories=" + mainCategory;
  286 + // items.value[1].title = subCategoryName.value;
  287 + href2.value = href1.value + "," + subCategoryName.value;
  288 + items.value[2].href = href1.value + "," + subCategoryName.value;
  289 + if (routeQuery?.selectedFunction) {
  290 + // items.value.push({
  291 + // title: routeQuery.selectedFunction,
  292 + // disabled: false,
  293 + // href: href2.value + "&function=" + routeQuery.selectedFunction,
  294 + // });
  295 + items.value[3].title = routeQuery.selectedFunction;
  296 + items.value[3].href =
  297 + href2.value + "&function=" + routeQuery.selectedFunction;
  298 + // routeQuery.updateFunction(null);
  299 + }
  300 + } else if (info?.productCrumbsVO?.category1) {
  301 + items.value[1].title = info.productCrumbsVO.category1;
  302 + items.value[1].href =
  303 + href1.value + "?categories=" + info.productCrumbsVO.category1;
  304 + href1.value = href1.value + "?categories=" + info.productCrumbsVO.category1;
  305 + if (info?.productCrumbsVO?.category2) {
  306 + items.value[2].title = info.productCrumbsVO.category2;
  307 + href2.value = href1.value + "," + info.productCrumbsVO.category2;
  308 + items.value[2].href = href1.value + "," + info.productCrumbsVO.category2;
  309 + }
  310 + if (info?.productCrumbsVO?.function) {
  311 + // items.value.push({
  312 + // title: info.productCrumbsVO.function,
  313 + // disabled: false,
  314 + // href: href2.value + "&function=" + info.productCrumbsVO.function,
  315 + // });
  316 + items.value[3].title = info.productCrumbsVO.function;
  317 + items.value[3].href =
  318 + href2.value + "&function=" + info.productCrumbsVO.function;
  319 + }
  320 + }
  321 +});
195 322 // onMounted(() => {
196 323 // dialogStore.updateDialog(true)
197 324 // })
198 325  
199 326 const tab = ref(0);
200 327 const slide = ref(0);
201   -const router = useRouter();
202 328 </script>
203 329  
204 330 <style lang="scss" scoped>
... ... @@ -231,4 +357,42 @@ th {
231 357 border-bottom: 1px solid #dcdcdc !important;
232 358 }
233 359 }
  360 +
  361 +.tw-sticky {
  362 + position: sticky;
  363 +}
  364 +
  365 +.carousel-container {
  366 + position: relative;
  367 +}
  368 +
  369 +.table-container {
  370 + overflow-x: auto; /* 防止表格超出页面宽度 */
  371 +}
  372 +
  373 +.table1 {
  374 + width: 100%;
  375 + min-width: 600px; /* 设置表格最小宽度 */
  376 +}
  377 +
  378 +.tr {
  379 + border-bottom: 1px solid #e0e0e0; /* 表格行样式 */
  380 +}
  381 +
  382 +.headerBorder {
  383 + border-bottom: 2px solid #ccc; /* 表头边框 */
  384 +}
  385 +
  386 +.text-grey-darken-4 {
  387 + color: #333; /* 表格文字颜色 */
  388 +}
  389 +.breadcrumb-disabled {
  390 + color: black;
  391 + pointer-events: none; /* 禁用点击 */
  392 + text-decoration: none; /* 移除链接样式 */
  393 +}
  394 +
  395 +.breadcrumb-active {
  396 + color: gray;
  397 +}
234 398 </style>
... ...
pages/products/detail/[id]/index.vue
... ... @@ -11,7 +11,7 @@ import type { Product, ProductImage } from &quot;~/type&quot;;
11 11 import { useRoute, useRouter } from "vue-router";
12 12  
13 13 const route = useRoute();
14   -
  14 +const router = useRouter();
15 15 const info = ref<Partial<Product>>({
16 16 productimageliststore: [],
17 17 productAttributeList: [],
... ... @@ -44,22 +44,17 @@ watchEffect(() =&gt; {
44 44 },
45 45 {
46 46 name: "keywords",
47   - content:
48   - info.value.name ||
49   - "科路得,Equipment,High-precision,Machining center,Design,Manufacturing capabilities,Equipment supply,Production line planning,Construction services,Battery assembly lines,Pouch cell testing lines",
  47 + content: info.value.name || info.value.metakeywords,
50 48 },
51 49 {
52 50 name: "description",
53   - content:
54   - info.value.name ||
55   - "科路得,助您科研之路势在必得。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!",
  51 + content: info.value.metadescription || info.value.name,
56 52 },
57 53 ],
58 54 });
59 55 });
60 56  
61 57 const newData: Product = resData.value.data;
62   -
63 58 newData.productimageliststore =
64 59 typeof newData.productimageliststore === "string"
65 60 ? JSON.parse(newData.productimageliststore) || []
... ...
pages/products/index.vue
... ... @@ -86,9 +86,21 @@ const productStore = useProductListStore();
86 86 const categoryStore = useCategoryStore();
87 87 const loading = ref(false);
88 88 const route = useRoute(); // 获取路由信息
  89 +const router = useRouter(); // 获取路由信息
  90 +const title = ref("");
  91 +watchEffect(() => {
  92 + // 遍历数组
  93 + if (router.currentRoute.value.query.categories) {
  94 + title.value = `${router.currentRoute.value.query.categories}`;
  95 + }
  96 + if (router.currentRoute.value.query.function) {
  97 + title.value += `,${router.currentRoute.value.query.function}`;
  98 + }
  99 + // document.title = title.value;
  100 +});
89 101  
90 102 useHead({
91   - title: "canrud",
  103 + title: title.value,
92 104 meta: [
93 105 {
94 106 name: "title",
... ... @@ -109,7 +121,6 @@ useHead({
109 121 });
110 122  
111 123 const loadProducts = async () => {
112   - console.log(productStore, "5656productStore");
113 124 let params: any = {
114 125 pageNo: productStore.pageNo,
115 126 pageSize: 20,
... ...
stores/product_list.ts
... ... @@ -32,7 +32,7 @@ export const useProductListStore = defineStore(&quot;productList&quot;, () =&gt; {
32 32 imgList: JSON.parse(
33 33 record.productimageliststore as unknown as string
34 34 ).map((item: ProductImage) => ({
35   - url: `/api/show/image?fileKey=${item.fileKey}&psize=p512`,
  35 + url: `/api/show/image?fileKey=${item.fileKey}&psize=p256`,
36 36 })),
37 37 })) || [];
38 38 total.value = data.value?.data?.total || 0;
... ...
stores/route_query.ts 0 → 100644
  1 +import { ref } from "vue";
  2 +import { defineStore } from "pinia";
  3 +
  4 +export const useRouteQuery = defineStore("routeQuery", () => {
  5 + const categories = ref();
  6 + const selectedFunction = ref();
  7 +
  8 + const updateCategories = (value: string) => {
  9 + categories.value = value;
  10 + };
  11 +
  12 + const updateFunction = (value: string | null) => {
  13 + selectedFunction.value = value;
  14 + };
  15 +
  16 + return {
  17 + categories,
  18 + selectedFunction,
  19 + updateCategories,
  20 + updateFunction,
  21 + };
  22 +});
... ...