Files
inkreach-uni/pages/products/components/ProductGrid.vue
T
2026-08-25 11:21:21 +08:00

222 lines
5.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<!-- 右侧商品列表区 - 上方子分类 + 下方滚动商品网格 -->
<view class="right-content">
<!-- 子分类(顶部条件) - Figma 1519:250 -->
<view class="sub-categories" v-if="subCategories.length > 0">
<view
class="sub-cat-item"
:class="{ active: activeSubId === item.id }"
v-for="(item, index) in subCategories"
:key="index"
@tap="selectSub(item.id)"
>{{ item.name }}</view>
</view>
<!-- 商品网格滚动区 -->
<scroll-view scroll-y class="product-scroll" :lower-threshold="100" :scroll-top="scrollTopVal" :scroll-with-animation="false" @scrolltolower="onScrollToLower">
<view class="product-grid" v-if="list.length > 0">
<view
class="product-card"
v-for="(item, index) in list"
:key="index"
@tap="onTapProduct(item)"
>
<!-- 图片 135x120 (Figma) -->
<view class="product-img">
<image
class="product-image"
:src="item.image"
mode="aspectFill"
v-if="item.image"
></image>
<view class="product-badges">
<view
class="product-badge"
:style="{ background: tag.bg, color: tag.color }"
v-for="(tag, tIdx) in item.tags"
:key="tIdx"
>{{ tag.text }}</view>
</view>
</view>
<!-- 商品信息 -->
<view class="product-info">
<text class="product-name">{{ item.name }}</text>
<text class="product-price">{{ item.price }}</text>
</view>
</view>
</view>
<!-- 空状态 -->
<view class="product-empty" v-else>
<text class="empty-icon">📦</text>
<text class="empty-text">没有找到相关商品</text>
</view>
<!-- 底部加载提示 -->
<view class="load-tip" v-if="list.length > 0">
<text v-if="loading">加载中...</text>
<text v-else-if="!hasMore">没有更多了</text>
</view>
</scroll-view>
</view>
</template>
<script>
export default {
name: 'ProductGrid',
props: {
list: { type: Array, default: () => [] },
subCategories: { type: Array, default: () => [] },
activeSubId: { type: [String, Number], default: '' },
hasMore: { type: Boolean, default: true },
loading: { type: Boolean, default: false },
scrollTopVal: { type: Number, default: 0 }
},
methods: {
selectSub(id) { this.$emit('sub-select', id) },
onTapProduct(item) { this.$emit('product-click', item) },
onScrollToLower() { this.$emit('scroll-to-lower') }
}
}
</script>
<style scoped>
/* 右侧内容区 - 上下分:顶部条件 + 下方滚动
flex:1 与 height:100% 冲突,二选一(保留 flex:1 */
.right-content {
flex: 1;
min-width: 0;
min-height: 0;
display: flex;
flex-direction: column;
background: #f2f2f2;
overflow: hidden;
}
/* 顶部子分类条件 - padding 6px 10px 圆角 60px */
.sub-categories {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
padding: 20rpx 20rpx;
background: #ffffff;
border-bottom: 1rpx solid #eeeeee;
}
.sub-cat-item {
padding: 12rpx 20rpx;
background: #ffffff;
border-radius: 60rpx;
font-size: 24rpx;
font-weight: 500;
color: #000000;
line-height: 1.2;
}
/* 选中态 - 白底+橙色边框0.5px+橙色文字 */
.sub-cat-item.active {
border: 1rpx solid #ff6800;
color: #ff6800;
}
/* 滚动商品区 - uni-app scroll-view 在 flex 布局里必须同时有 flex:1 + height:0
仅 min-height:0 无法让部分端的 scroll-view 正确计算内部 viewport 高度 */
.product-scroll {
flex: 1;
height: 0;
min-height: 0;
overflow: hidden;
}
/* 商品网格 - 固定2列 grid,不会因商品个数变化而拉伸占行 */
.product-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16rpx;
padding: 20rpx;
}
.product-card {
min-width: 0;
background: #ffffff;
border-radius: 12rpx;
overflow: hidden;
box-sizing: border-box;
}
/* 图片 135x120 - 用 padding-bottom 撑比例 */
.product-img {
position: relative;
width: 100%;
padding-bottom: 88.89%; /* 120/135 */
background: #f7f7f7;
overflow: hidden;
}
.product-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.product-badges {
position: absolute;
top: 12rpx;
left: 12rpx;
display: flex;
flex-direction: column;
gap: 8rpx;
z-index: 1;
}
.product-badge {
padding: 4rpx 12rpx;
border-radius: 8rpx;
font-size: 18rpx;
}
/* 商品信息 - 内边距 10px */
.product-info {
padding: 20rpx;
}
/* 商品名 13px Medium #000000 */
.product-name {
display: block;
font-size: 26rpx;
font-weight: 500;
color: #000000;
line-height: 1.4;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* 价格 15px Heavy #FF0000 红色 */
.product-price {
display: block;
margin-top: 16rpx;
font-size: 30rpx;
font-weight: 900;
color: #ff0000;
line-height: 1.2;
}
/* 底部加载提示 */
.load-tip {
padding: 32rpx;
text-align: center;
font-size: 24rpx;
color: #999999;
}
/* 空状态 */
.product-empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 120rpx 0;
}
.empty-icon {
font-size: 96rpx;
margin-bottom: 24rpx;
}
.empty-text {
font-size: 26rpx;
color: #999999;
}
</style>