From 9503080c8548995d19f6cbe95e6a9e4ed8d033b5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=A4=A7=E8=84=8F=E7=8B=BC?= <786316265@qq.com>
Date: Tue, 26 Aug 2025 16:15:46 +0800
Subject: [PATCH] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E4=BA=86=E5=8A=A0=E8=BD=BD?=
=?UTF-8?q?=E5=95=86=E5=93=81=E6=97=B6=E7=BD=91=E9=A1=B5=E9=A2=91=E7=B9=81?=
=?UTF-8?q?=E9=97=AA=E7=83=81=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/views/ProductSummary.vue | 123 +++++++++++++++++++++++++++++++++--
1 file changed, 116 insertions(+), 7 deletions(-)
diff --git a/src/views/ProductSummary.vue b/src/views/ProductSummary.vue
index bbac9db..deade2b 100644
--- a/src/views/ProductSummary.vue
+++ b/src/views/ProductSummary.vue
@@ -8,7 +8,16 @@
+
+
-
@@ -74,6 +91,8 @@ const products = ref([])
const firstProduct = ref([])
const productDetail = ref([])
const productDetailsCache = ref({}) // 缓存所有商品详情
+const loading = ref(true) // 添加加载状态
+const detailsLoaded = ref(false) // 商品详情是否加载完成
const route = useRoute()
const productId = ref(null)
@@ -130,6 +149,8 @@ const getFirstProduct = async () => {
} catch (error) {
ElMessage.error('获取商品详情失败')
console.log(error)
+ } finally {
+ loading.value = false
}
}
@@ -159,21 +180,44 @@ const getProductDetail = async (productId) => {
const loadAllProductDetails = async () => {
const uniqueProductIds = [...new Set(products.value.map(p => p.id))]
- for (const id of uniqueProductIds) {
+ // 并行加载所有商品详情,避免逐个加载时的多次渲染
+ const loadPromises = uniqueProductIds.map(async (id) => {
try {
- await getProductDetail(id)
+ const response = await api.get(`/products/${id}`)
+ if (response.data && response.data.data && response.data.data.product) {
+ return { id, product: response.data.data.product }
+ }
} catch (error) {
console.warn(`Failed to load details for product ${id}:`, error)
+ return null
}
- }
+ })
+
+ // 等待所有请求完成
+ const results = await Promise.all(loadPromises)
+
+ // 一次性更新缓存,避免多次触发响应式更新
+ const newCache = { ...productDetailsCache.value }
+ results.forEach(result => {
+ if (result) {
+ newCache[result.id] = result.product
+ }
+ })
+
+ // 一次性更新缓存和加载状态
+ productDetailsCache.value = newCache
+ detailsLoaded.value = true
}
// 添加生命周期钩子来调用函数
-onMounted(() => {
+onMounted(async () => {
productId.value = route.params.id
console.log('Product ID:', productId.value)
- getProducts()
- getFirstProduct()
+ loading.value = true
+
+ // 先加载第一个商品,再加载商品列表,确保数据同步
+ await getFirstProduct()
+ await getProducts()
})
@@ -351,6 +395,71 @@ onMounted(() => {
}
/* 修改部分结束 */
+/* 骨架屏样式 */
+.carousel-skeleton {
+ position: relative;
+ width: 100%;
+ height: 300px;
+ border-radius: 8px;
+ overflow: hidden;
+ background: #f5f5f5;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.skeleton-image {
+ width: 80%;
+ height: 80%;
+ background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
+ background-size: 200% 100%;
+ animation: skeleton-loading 1.5s infinite;
+ border-radius: 8px;
+}
+
+.skeleton-indicators {
+ position: absolute;
+ bottom: 15px;
+ left: 50%;
+ transform: translateX(-50%);
+ display: flex;
+ gap: 8px;
+}
+
+.skeleton-dot {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background: #d0d0d0;
+ animation: skeleton-pulse 1.5s infinite;
+}
+
+.skeleton-dot:nth-child(2) {
+ animation-delay: 0.2s;
+}
+
+.skeleton-dot:nth-child(3) {
+ animation-delay: 0.4s;
+}
+
+@keyframes skeleton-loading {
+ 0% {
+ background-position: -200% 0;
+ }
+ 100% {
+ background-position: 200% 0;
+ }
+}
+
+@keyframes skeleton-pulse {
+ 0%, 100% {
+ opacity: 0.4;
+ }
+ 50% {
+ opacity: 0.8;
+ }
+}
+
/* 轮播图样式调整 */
:deep(.el-carousel) {
border-radius: 8px;