You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

559 lines
14 KiB

2 months ago
<template>
<div class="product-grid-page">
2 months ago
<!-- 筛选排序区 -->
2 months ago
<div class="filter-bar" v-if="showFilter">
2 months ago
<!-- 分类弹框 -->
2 months ago
<el-select
v-model="selectedCategory"
2 months ago
placeholder="全部分类"
2 months ago
class="filter-select"
2 months ago
@change="handleCategoryChange"
2 months ago
>
<el-option
v-for="cat in categories"
:key="cat.value"
:label="cat.label"
:value="cat.value"
></el-option>
</el-select>
2 months ago
<!-- 排序选项 -->
2 months ago
<el-select
v-model="selectedSort"
2 months ago
placeholder="综合排序"
2 months ago
class="filter-select"
2 months ago
@change="handleSortChange"
2 months ago
>
2 months ago
<el-option label="综合排序" value="default"></el-option>
<el-option label="销量↑" value="sales_asc"></el-option>
<el-option label="销量↓" value="sales_desc"></el-option>
<el-option label="价格↑" value="price_asc"></el-option>
<el-option label="价格↓" value="price_desc"></el-option>
2 months ago
</el-select>
2 months ago
</div>
2 months ago
2 months ago
<!-- 搜索结果统计 -->
<div class="result-stats" v-if="type == 'search'">
<span>全部结果 ></span>
<span class="keyword" v-if="searchKeyword">"{{ searchKeyword }}"</span>
<span
v-if="
selectedCategory &&
categories.find((cat) => cat.value === selectedCategory)
"
class="category"
2 months ago
>
2 months ago
"{{ categories.find((cat) => cat.value === selectedCategory).label }}"
</span>
<span>{{ totalProducts }}个结果</span>
2 months ago
</div>
<!-- 商品网格 -->
<div class="product-grid">
<div
class="product-card"
v-for="(product, index) in visibleProducts"
2 months ago
:key="product.id"
2 months ago
@click="goToDetail(product.id)"
>
<el-image
v-lazy="product.image"
:alt="product.name"
class="product-img"
lazy
fit="cover"
>
<div slot="placeholder" class="image-placeholder">
<i class="el-icon-loading"></i>
</div>
</el-image>
<div
class="tag"
v-if="product.tag"
:style="{ backgroundColor: product.tagColor }"
>
{{ product.tag }}
</div>
<div class="product-info">
<div class="product-name">{{ product.name }}</div>
<div class="price-row">
2 months ago
<span class="current-price">¥{{ product.price.toFixed(2) }}</span>
2 months ago
<span class="original-price" v-if="product.originalPrice"
2 months ago
>¥{{ product.originalPrice.toFixed(2) }}</span
2 months ago
>
</div>
2 months ago
<div class="sales-volume" v-if="product.sales > 0">
<i class="el-icon-shopping-cart"></i> 已售 {{ product.sales }}
</div>
2 months ago
<el-button
type="primary"
size="mini"
class="cart-btn"
@click.prevent="addToCart(product)"
>
加入购物车
</el-button>
</div>
</div>
<div class="empty-state" v-if="visibleProducts.length === 0">
2 months ago
<el-empty description="暂无符合条件的商品"></el-empty>
2 months ago
</div>
</div>
<!-- 分页组件 -->
2 months ago
<div class="pagination-container" v-if="totalProducts > 0">
2 months ago
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[12, 24, 36]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="totalProducts"
></el-pagination>
</div>
</div>
</template>
<script>
2 months ago
import { mapGetters } from "vuex";
2 months ago
export default {
name: "ProductGridPage",
data() {
return {
2 months ago
type: "",
// 搜索关键词
2 months ago
searchKeyword: "",
2 months ago
// 筛选/排序条件
selectedCategory: "",
selectedSort: "default", // 默认综合排序
showFilter: true,
2 months ago
// 分页控制
currentPage: 1,
2 months ago
pageSize: 12,
// 商品数据
2 months ago
products: [
{
id: 1,
2 months ago
name: "无线蓝牙耳机 主动降噪长续航",
image: "https://picsum.photos/id/101/300/300",
price: 359.0,
originalPrice: 499.0,
category: "digital",
2 months ago
tag: "限时折扣",
tagColor: "#FF6B6B",
2 months ago
sales: 120,
2 months ago
},
{
id: 2,
2 months ago
name: "智能手表 心率监测运动计步",
image: "https://picsum.photos/id/102/300/300",
price: 259.0,
originalPrice: 329.0,
category: "digital",
2 months ago
tag: "新品",
tagColor: "#4ECDC4",
2 months ago
sales: 86,
2 months ago
},
{
id: 3,
2 months ago
name: "纯棉短袖T恤 宽松休闲",
image: "https://picsum.photos/id/103/300/300",
price: 89.0,
originalPrice: 129.0,
category: "life",
sales: 320,
2 months ago
},
{
id: 4,
2 months ago
name: "新鲜水果礼盒 当季混合装",
image: "https://picsum.photos/id/104/300/300",
price: 159.0,
category: "food",
tag: "热销",
tagColor: "#FF9F1C",
sales: 215,
2 months ago
},
{
id: 5,
2 months ago
name: "全自动咖啡机 家用小型",
image: "https://picsum.photos/id/105/300/300",
price: 1299.0,
originalPrice: 1599.0,
category: "life",
sales: 45,
2 months ago
},
{
id: 6,
2 months ago
name: "高清投影仪 家用办公两用",
image: "https://picsum.photos/id/106/300/300",
price: 2499.0,
category: "digital",
tag: "推荐",
tagColor: "#2EC4B6",
sales: 78,
2 months ago
},
{
id: 7,
2 months ago
name: "进口红酒 赤霞珠干红",
image: "https://picsum.photos/id/107/300/300",
price: 199.0,
originalPrice: 258.0,
category: "food",
sales: 63,
2 months ago
},
{
id: 8,
2 months ago
name: "瑜伽垫 防滑专业健身垫",
image: "https://picsum.photos/id/108/300/300",
price: 129.0,
category: "life",
sales: 156,
2 months ago
},
{
id: 9,
2 months ago
name: "机械键盘 青轴游戏专用",
image: "https://picsum.photos/id/109/300/300",
price: 299.0,
originalPrice: 399.0,
category: "digital",
2 months ago
tag: "限时折扣",
tagColor: "#FF6B6B",
2 months ago
sales: 92,
2 months ago
},
{
id: 10,
2 months ago
name: "有机蔬菜礼盒 新鲜配送",
image: "https://picsum.photos/id/110/300/300",
price: 89.0,
category: "food",
sales: 205,
2 months ago
},
{
id: 11,
2 months ago
name: "北欧风落地灯 客厅卧室",
image: "https://picsum.photos/id/111/300/300",
price: 199.0,
category: "life",
sales: 57,
2 months ago
},
{
id: 12,
2 months ago
name: "便携式充电宝 20000mAh",
image: "https://picsum.photos/id/112/300/300",
price: 129.0,
originalPrice: 169.0,
category: "digital",
sales: 310,
2 months ago
},
],
2 months ago
// 分类选项
2 months ago
categories: [
{ label: "全部", value: "" },
{ label: "美食", value: "food" },
{ label: "生活", value: "life" },
{ label: "数码", value: "digital" },
],
};
},
computed: {
2 months ago
...mapGetters(["getSearchText"]),
2 months ago
// 筛选后商品
filteredProducts() {
return this.products.filter((product) => {
2 months ago
// 分类筛选
2 months ago
const categoryMatch = this.selectedCategory
? product.category === this.selectedCategory
: true;
2 months ago
// 关键词搜索筛选
2 months ago
const keywordMatch = this.searchKeyword
2 months ago
? product.name
.toLowerCase()
.includes(this.searchKeyword.toLowerCase())
2 months ago
: true;
2 months ago
2 months ago
return categoryMatch && keywordMatch;
});
},
// 排序处理
sortedProducts() {
2 months ago
const sorted = [...this.filteredProducts];
console.log(...this.filteredProducts, sorted);
switch (this.selectedSort) {
case "price_asc":
return sorted.sort((a, b) => a.price - b.price);
case "price_desc":
return sorted.sort((a, b) => b.price - a.price);
case "sales_asc":
return sorted.sort((a, b) => a.sales - b.sales);
case "sales_desc":
return sorted.sort((a, b) => b.sales - a.sales);
default: // 综合排序(默认按ID)
return sorted.sort((a, b) => a.id - b.id);
2 months ago
}
},
// 分页后商品
visibleProducts() {
const start = (this.currentPage - 1) * this.pageSize;
const end = start + this.pageSize;
return this.sortedProducts.slice(start, end);
},
// 商品总数
totalProducts() {
return this.sortedProducts.length;
},
},
2 months ago
watch: {
// 监听搜索词变化
getSearchText(newVal, oldVal) {
if (newVal !== oldVal) {
this.searchKeyword = newVal;
this.fetchProducts(); // 调用接口获取数据
}
},
},
created() {
this.type = this.$route.query?.type;
this.searchKeyword = this.getSearchText;
this.fetchProducts();
},
2 months ago
methods: {
2 months ago
// 获取列表
async fetchProducts() {
console.log(this.getSearchText);
// const response = await this.$axios.get('/api/products', { params });
},
// 搜索处理
2 months ago
handleSearch() {
2 months ago
this.currentPage = 1; // 搜索后重置到第一页
},
// 分类变更处理
handleCategoryChange() {
this.currentPage = 1; // 切换分类后重置到第一页
},
// 排序变更处理
handleSortChange() {
this.currentPage = 1; // 切换排序后重置到第一页
2 months ago
},
// 分页大小改变
handleSizeChange(val) {
this.pageSize = val;
this.currentPage = 1;
},
// 当前页改变
handleCurrentChange(val) {
this.currentPage = val;
2 months ago
// 滚动到页面顶部
window.scrollTo(0, 0);
2 months ago
},
// 加入购物车
addToCart(product) {
this.$message.success(`${product.name} 已加入购物车`);
2 months ago
// 实际项目中这里会调用购物车API
2 months ago
},
2 months ago
// 跳转详情页
2 months ago
goToDetail(id) {
this.$router.push(`/product/${id}`);
},
},
};
</script>
<style lang="scss" scoped>
.product-grid-page {
padding: 20px;
2 months ago
background-color: #f5f7fa;
max-width: 1400px;
margin: 0 auto;
2 months ago
2 months ago
// 筛选栏样式
2 months ago
.filter-bar {
display: flex;
gap: 15px;
margin-bottom: 20px;
flex-wrap: wrap;
2 months ago
align-items: center;
padding: 15px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
.search-input {
flex: 1;
min-width: 200px;
}
2 months ago
.filter-select {
2 months ago
min-width: 140px;
2 months ago
}
2 months ago
}
2 months ago
2 months ago
// 搜索结果统计样式
.result-stats {
margin: 0 0 15px 5px;
color: #666;
font-size: 14px;
padding: 5px 0;
.keyword,
.category {
color: #ff4d4f;
font-weight: 500;
margin: 0 5px;
2 months ago
}
}
2 months ago
// 商品网格布局
2 months ago
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 20px;
2 months ago
margin-bottom: 30px;
2 months ago
}
// 商品卡片
.product-card {
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
overflow: hidden;
transition: transform 0.3s, box-shadow 0.3s;
cursor: pointer;
position: relative;
&:hover {
transform: translateY(-5px);
2 months ago
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
2 months ago
}
.product-img {
width: 100%;
height: 200px;
2 months ago
background-color: #f5f5f5;
}
.image-placeholder {
width: 100%;
height: 200px;
display: flex;
align-items: center;
justify-content: center;
background-color: #f5f5f5;
2 months ago
}
.tag {
position: absolute;
top: 10px;
left: 10px;
2 months ago
padding: 3px 8px;
2 months ago
font-size: 12px;
2 months ago
color: #fff;
border-radius: 4px;
2 months ago
z-index: 1;
}
.product-info {
padding: 15px;
.product-name {
font-size: 14px;
2 months ago
color: #333;
margin-bottom: 10px;
height: 40px;
2 months ago
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
2 months ago
overflow: hidden;
2 months ago
}
.price-row {
display: flex;
2 months ago
align-items: center;
margin-bottom: 8px;
2 months ago
.current-price {
color: #ff4d4f;
font-weight: bold;
2 months ago
font-size: 16px;
2 months ago
}
.original-price {
color: #999;
2 months ago
font-size: 12px;
2 months ago
text-decoration: line-through;
2 months ago
margin-left: 8px;
2 months ago
}
}
2 months ago
.sales-volume {
2 months ago
font-size: 12px;
2 months ago
color: #666;
margin-bottom: 10px;
display: flex;
align-items: center;
i {
font-size: 12px;
margin-right: 4px;
}
2 months ago
}
2 months ago
.cart-btn {
width: 100%;
}
}
2 months ago
}
2 months ago
// 空状态样式
2 months ago
.empty-state {
2 months ago
grid-column: 1 / -1;
padding: 60px 0;
2 months ago
text-align: center;
}
// 分页容器
.pagination-container {
display: flex;
justify-content: center;
margin-top: 20px;
2 months ago
padding: 10px;
2 months ago
}
}
2 months ago
// 响应式调整
2 months ago
@media (max-width: 768px) {
2 months ago
.product-grid-page {
padding: 10px;
2 months ago
2 months ago
.filter-bar {
padding: 10px;
gap: 10px;
}
.product-grid {
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
gap: 10px;
}
.product-card {
.product-img {
height: 140px;
}
.image-placeholder {
height: 140px;
}
}
2 months ago
}
}
2 months ago
</style>