refactor(product): 将产品列表从网格布局改为水平列表布局
- 从 2 列网格布局改为单列水平卡片布局 - 图片尺寸从 200rpx 增加到 220rpx - 使用圆形文字按钮替代 NutUI 按钮组件 - 优化标签显示逻辑,显示所有标签而非仅前 2 个 技术细节: - 布局:flex 布局,图片固定宽度 220rpx - 按钮:纯文字按钮,详情为浅蓝背景,计划书为深蓝背景 - 间距:使用 gap、mt-auto 等优化视觉层次 影响文件: - src/pages/product-center/index.vue - components.d.ts (自动更新) - docs/CHANGELOG.md Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Showing
3 changed files
with
75 additions
and
51 deletions
| ... | @@ -35,7 +35,7 @@ declare module 'vue' { | ... | @@ -35,7 +35,7 @@ declare module 'vue' { |
| 35 | PdfPreview: typeof import('./src/components/PdfPreview.vue')['default'] | 35 | PdfPreview: typeof import('./src/components/PdfPreview.vue')['default'] |
| 36 | Picker: typeof import('./src/components/time-picker-data/picker.vue')['default'] | 36 | Picker: typeof import('./src/components/time-picker-data/picker.vue')['default'] |
| 37 | PlanFormContainer: typeof import('./src/components/PlanFormContainer.vue')['default'] | 37 | PlanFormContainer: typeof import('./src/components/PlanFormContainer.vue')['default'] |
| 38 | - PlanPopup: typeof import('./src/components/PlanSchemes/PlanPopup.vue')['default'] | 38 | + PlanPopup: typeof import('./src/components/PlanPopup/index.vue')['default'] |
| 39 | PosterBuilder: typeof import('./src/components/PosterBuilder/index.vue')['default'] | 39 | PosterBuilder: typeof import('./src/components/PosterBuilder/index.vue')['default'] |
| 40 | ProductCard: typeof import('./src/components/ProductCard.vue')['default'] | 40 | ProductCard: typeof import('./src/components/ProductCard.vue')['default'] |
| 41 | QrCode: typeof import('./src/components/qrCode.vue')['default'] | 41 | QrCode: typeof import('./src/components/qrCode.vue')['default'] | ... | ... |
| ... | @@ -5,6 +5,29 @@ | ... | @@ -5,6 +5,29 @@ |
| 5 | 5 | ||
| 6 | --- | 6 | --- |
| 7 | 7 | ||
| 8 | +## [2026-02-06] - 优化产品中心列表UI (布局调整) | ||
| 9 | + | ||
| 10 | +### 优化 | ||
| 11 | +- 增加产品卡片图片和高度(从 200rpx 增加到 220rpx),缓解内容拥挤感 | ||
| 12 | +- 调整标题和标签间距,使布局更紧凑 | ||
| 13 | +- 使用 `mt-auto` 将操作按钮组沉底,确保与上方标签保持合理间距,并使卡片视觉重心更稳 | ||
| 14 | + | ||
| 15 | +### 技术实现 | ||
| 16 | +- 图片容器大小:`w-[220rpx] h-[220rpx]` | ||
| 17 | +- 按钮组:添加 `mt-auto` | ||
| 18 | +- 标题间距:`mb-[12rpx]` | ||
| 19 | +- 标签间距:`mb-[8rpx]` | ||
| 20 | + | ||
| 21 | +## [2026-02-06] - 优化产品中心列表UI | ||
| 22 | + | ||
| 23 | +### 优化 | ||
| 24 | +- 调整产品列表动态标签的间距,修复 gap 属性拼写错误 | ||
| 25 | +- 将产品卡片右侧的图标按钮组改为更直观的纯文字按钮("详情"、"计划书") | ||
| 26 | + | ||
| 27 | +### 技术实现 | ||
| 28 | +- 修复 `gap-[8rpx` 为 `gap-[8rpx]`,增加标签间距 | ||
| 29 | +- 替换 `IconFont` 组件为带样式的 `view` 标签,统一按钮风格 | ||
| 30 | + | ||
| 8 | ## [2026-02-06] - 添加 mock 数据支持并修复滚动加载功能 | 31 | ## [2026-02-06] - 添加 mock 数据支持并修复滚动加载功能 |
| 9 | 32 | ||
| 10 | ### 新增 | 33 | ### 新增 | ... | ... |
| ... | @@ -51,64 +51,65 @@ | ... | @@ -51,64 +51,65 @@ |
| 51 | <text class="text-gray-400 text-[28rpx]">加载中...</text> | 51 | <text class="text-gray-400 text-[28rpx]">加载中...</text> |
| 52 | </view> | 52 | </view> |
| 53 | 53 | ||
| 54 | - <!-- Product Grid --> | 54 | + <!-- Product List --> |
| 55 | - <view v-else class="flex flex-wrap justify-between px-[40rpx]"> | 55 | + <view v-else class="px-[40rpx]"> |
| 56 | <!-- Card Item --> | 56 | <!-- Card Item --> |
| 57 | <view v-for="(item, index) in products" :key="item.id" | 57 | <view v-for="(item, index) in products" :key="item.id" |
| 58 | - class="w-[48%] bg-white rounded-[24rpx] overflow-hidden mb-[24rpx] shadow-sm flex flex-col active:scale-[0.98] transition-transform duration-200" | 58 | + class="bg-white rounded-[24rpx] overflow-hidden mb-[24rpx] shadow-sm active:scale-[0.98] transition-transform duration-200" |
| 59 | :style="{ animationDelay: `${index * 50}ms` }" | 59 | :style="{ animationDelay: `${index * 50}ms` }" |
| 60 | - @tap="handleProductClick(item)"> | 60 | + > |
| 61 | - <!-- Image Container --> | 61 | + <!-- Product Content (Horizontal Layout) --> |
| 62 | - <view class="relative w-full h-[200rpx] product-card-item"> | 62 | + <view class="flex gap-[24rpx]" @tap="handleProductClick(item)"> |
| 63 | - <image :src="item.cover_image" class="w-full h-full object-cover bg-gray-100" mode="aspectFill" /> | 63 | + <!-- Image Container --> |
| 64 | - <!-- Tag --> | 64 | + <view class="relative w-[220rpx] h-[220rpx] flex-shrink-0 product-card-item"> |
| 65 | - <view v-if="item.recommend === 'hot'" | 65 | + <image :src="item.cover_image" class="w-full h-full object-cover bg-gray-100" mode="aspectFill" /> |
| 66 | - class="absolute top-[12rpx] right-[12rpx] bg-red-500 text-white text-[20rpx] px-[12rpx] py-[4rpx] rounded-full"> | 66 | + <!-- Tag --> |
| 67 | - 热卖 | 67 | + <view v-if="item.recommend === 'hot'" |
| 68 | + class="absolute top-[12rpx] right-[12rpx] bg-red-500 text-white text-[20rpx] px-[12rpx] py-[4rpx] rounded-full"> | ||
| 69 | + 热卖 | ||
| 70 | + </view> | ||
| 68 | </view> | 71 | </view> |
| 69 | - </view> | ||
| 70 | 72 | ||
| 71 | - <!-- Content --> | 73 | + <!-- Content --> |
| 72 | - <view class="p-[20rpx] flex flex-col flex-1"> | 74 | + <view class="flex-1 flex flex-col py-[20rpx] pr-[20rpx]"> |
| 73 | - <!-- Title --> | 75 | + <!-- Title --> |
| 74 | - <view class="text-[#1F2937] text-[28rpx] font-medium leading-[1.4] line-clamp-2 mb-[16rpx]"> | 76 | + <view class="text-[#1F2937] text-[28rpx] font-medium leading-[1.4] line-clamp-2 mb-[12rpx]"> |
| 75 | - {{ item.product_name }} | 77 | + {{ item.product_name }} |
| 76 | - </view> | 78 | + </view> |
| 77 | 79 | ||
| 78 | - <!-- 动态标签 --> | 80 | + <!-- 动态标签 --> |
| 79 | - <view v-if="item.tags && item.tags.length > 0" class="flex flex-wrap gap-[8rpx] mb-[16rpx]"> | 81 | + <view v-if="item.tags && item.tags.length > 0" class="flex flex-wrap gap-[8rpx] mb-[8rpx]"> |
| 80 | - <view | 82 | + <view |
| 81 | - v-for="tag in item.tags.slice(0, 2)" | 83 | + v-for="tag in item.tags" |
| 82 | - :key="tag.id" | 84 | + :key="tag.id" |
| 83 | - class="text-[20rpx] px-[12rpx] py-[4rpx] rounded-full" | 85 | + class="text-[20rpx] px-[12rpx] py-[4rpx] rounded-full" |
| 84 | - :style="{ | 86 | + :style="{ |
| 85 | - backgroundColor: tag.bg_color, | 87 | + backgroundColor: tag.bg_color, |
| 86 | - color: tag.text_color | 88 | + color: tag.text_color |
| 87 | - }" | 89 | + }" |
| 88 | - > | 90 | + > |
| 89 | - {{ tag.name }} | 91 | + {{ tag.name }} |
| 92 | + </view> | ||
| 90 | </view> | 93 | </view> |
| 91 | - </view> | ||
| 92 | 94 | ||
| 93 | - <!-- 按钮组 --> | 95 | + <!-- 按钮组 - 靠右对齐(纯文字按钮) --> |
| 94 | - <view class="flex gap-[12rpx] mt-auto"> | 96 | + <view class="flex gap-[16rpx] ml-auto items-center mt-auto" @tap.stop> |
| 95 | - <nut-button | 97 | + <!-- 详情按钮 --> |
| 96 | - plain | 98 | + <view |
| 97 | - color="#2563EB" | 99 | + class="text-[24rpx] text-[#2563EB] bg-blue-50 px-[24rpx] py-[8rpx] rounded-full active:bg-blue-100 transition-colors duration-200" |
| 98 | - size="small" | 100 | + @tap.stop="handleProductClick(item)" |
| 99 | - class="flex-1 !h-[56rpx] !rounded-[12rpx] !text-[22rpx] !m-0 !border-blue-600" | 101 | + > |
| 100 | - @tap.stop="handleProductClick(item)" | 102 | + 详情 |
| 101 | - > | 103 | + </view> |
| 102 | - 详情 | 104 | + |
| 103 | - </nut-button> | 105 | + <!-- 计划书按钮 --> |
| 104 | - <nut-button | 106 | + <view |
| 105 | - color="#2563EB" | 107 | + class="text-[24rpx] text-white bg-blue-500 px-[24rpx] py-[8rpx] rounded-full active:bg-blue-600 transition-colors duration-200" |
| 106 | - size="small" | 108 | + @tap.stop="openPlanPopup(item)" |
| 107 | - class="flex-1 !h-[56rpx] !rounded-[12rpx] !text-[22rpx] !m-0" | 109 | + > |
| 108 | - @tap.stop="openPlanPopup(item)" | 110 | + 计划书 |
| 109 | - > | 111 | + </view> |
| 110 | - 计划书 | 112 | + </view> |
| 111 | - </nut-button> | ||
| 112 | </view> | 113 | </view> |
| 113 | </view> | 114 | </view> |
| 114 | </view> | 115 | </view> | ... | ... |
-
Please register or login to post a comment