daShangDao_miniProgram/components/BookFilterDisplay.vue
2025-11-24 10:25:20 +08:00

552 lines
15 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>
<!-- 筛选按钮 -->
<view class="button-group">
<u-popup :show="popupShow" @close="close" @open="open" mode="bottom" round="10">
<view class="filter-popup">
<view class="filter-section">
<view class="section-title">出版社</view>
<view class="tag-group">
<u-tag v-for="(item, index) in publisherOptions" :key="index" v-if="item.visible"
:text="item.publisher" :plain="!item.checked" size="large" :name="index"
@click="togglePublisherFilter(index)" />
</view>
</view>
<view class="filter-section">
<view class="section-title">作者</view>
<view class="tag-group">
<u-tag v-for="(item, index) in authorOptions" :key="index" v-if="item.visible"
:text="item.author" :plain="!item.checked" size="large" :name="index"
@click="toggleAuthorFilter(index)" />
</view>
</view>
<view class="filter-buttons">
<u-button text="重置" type="info" plain @click="resetFilters" />
<u-button text="确定" type="primary" @click="applyFilters" />
</view>
</view>
</u-popup>
</view>
<view class="book-list">
<view class="label">
<view style="display: inline-block;width: 380rpx;text-align: left;">
在售商品(总价/书价/运费)
</view>
<view class="btn" @click="onSwitchCompareType">
{{ compareType === 'isbn' ? '书名比价' : 'ISBN比价' }}
</view>
<view class="btn" @click="popupShow = true">更多筛序</view>
</view>
<!-- 在售商品展示区域 -->
<view class="container" v-if="(isFiltered ? filteredOnSaleProducts : displayOnSaleProducts).length > 0">
<view class="product-grid">
<view class="product-card"
v-for="(product, index) in isFiltered ? filteredOnSaleProducts : displayOnSaleProducts"
:key="index">
<view class="product-image-container">
<image class="product-image" :src="product.imageUrl" mode="aspectFit"
@click="previewImage(product.imageUrl, isFiltered ? filteredOnSaleProducts : displayOnSaleProducts)">
</image>
<view class="price-details">
<text>{{product.totalPrice}}/{{product.bookPrice}}/{{product.shippingFee}}</text>
</view>
</view>
<view class="product-info">
<text class="product-price"
style="font-size: 26rpx;">{{product.totalPrice}}/{{product.qualityText}}</text>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'book-filter-display',
props: {
// 接收父组件传递的数据
onSaleProducts: {
type: Array,
default: () => []
},
compareType: {
type: String,
default: 'isbn'
},
publisherAuthorMap: {
type: Map,
default: () => new Map()
},
authorPublisherMap: {
type: Map,
default: () => new Map()
}
},
data() {
return {
popupShow: false,
isFiltered: false,
publisherOptions: [],
authorOptions: [],
displayOnSaleProducts: [],
filteredOnSaleProducts: []
};
},
watch: {
onSaleProducts: {
handler(newProducts) {
if (newProducts && newProducts.length > 0) {
// 对商品数据按照总价从低到高排序
const sortedData = [...newProducts].sort((a, b) => {
const priceA = parseFloat(a.totalPrice) || 0;
const priceB = parseFloat(b.totalPrice) || 0;
return priceA - priceB; // 从低到高排序
});
// 只保留前12条数据用于展示
this.displayOnSaleProducts = sortedData.slice(0, 12);
// 提取出版社和作者信息
this.extractPublishersAndAuthors();
} else {
this.displayOnSaleProducts = [];
}
},
immediate: true
}
},
methods: {
open() {
this.popupShow = true;
this.$emit('popup-open');
},
close() {
this.popupShow = false;
this.$emit('popup-close');
},
onSwitchCompareType() {
const newType = this.compareType === 'isbn' ? 'title' : 'isbn';
this.$emit('switch-compare-type', newType);
},
previewImage(currentUrl, productList) {
// 检查productList是否存在且是数组
let urls = [];
if (productList && Array.isArray(productList)) {
// 提取所有图片 URL
urls = productList.map(item => item.imageUrl);
} else {
// 如果productList不存在或不是数组则只使用当前URL
urls = [currentUrl];
}
// 确保urls中至少有一个有效的URL
if (!urls.length || !urls[0]) {
console.error('没有有效的图片URL可预览');
return;
}
// 调用 UniApp 预览接口,添加长按操作
uni.previewImage({
current: currentUrl, // 当前显示图片
urls: urls, // 所有图片列表
longPressActions: {
itemList: ['保存图片', '分享图片'],
success: function(data) {
console.log('选择了第' + (data.tapIndex + 1) + '个按钮');
},
fail: function(err) {
console.log(err.errMsg);
}
},
success: () => {},
fail: (err) => {
console.error('预览失败:', err);
}
});
},
// 从商品数据中提取出版社和作者信息
extractPublishersAndAuthors() {
// 提取出版社
const publishers = new Set();
this.onSaleProducts.forEach(product => {
if (product.publisher) {
publishers.add(product.publisher);
}
});
// 提取作者
const authors = new Set();
this.onSaleProducts.forEach(product => {
if (product.author) {
authors.add(product.author);
}
});
// 转换为选项数组
this.publisherOptions = Array.from(publishers).map(publisher => ({
publisher,
checked: false,
visible: true // 添加可见性属性
}));
this.authorOptions = Array.from(authors).map(author => ({
author,
checked: false,
visible: true // 添加可见性属性
}));
},
// 切换出版社筛选
togglePublisherFilter(index) {
// 切换选中状态
this.publisherOptions[index].checked = !this.publisherOptions[index].checked;
// 获取所有选中的出版社
const selectedPublishers = this.publisherOptions
.filter(item => item.checked)
.map(item => item.publisher);
// 如果没有选中任何出版社,显示所有作者
if (selectedPublishers.length === 0) {
this.authorOptions.forEach(item => {
item.visible = true;
});
} else {
// 获取当前选中的出版社
const currentPublisher = this.publisherOptions[index].publisher;
// 如果取消选中,需要重新计算可见的作者
if (!this.publisherOptions[index].checked) {
// 重置所有作者的可见性
this.authorOptions.forEach(item => {
item.visible = false;
});
// 根据剩余选中的出版社更新作者可见性
selectedPublishers.forEach(publisher => {
if (this.publisherAuthorMap.has(publisher)) {
const relatedAuthors = this.publisherAuthorMap.get(publisher);
this.authorOptions.forEach(item => {
if (relatedAuthors.has(item.author)) {
item.visible = true;
}
});
}
});
} else {
// 如果是新选中,只显示与该出版社相关的作者
this.authorOptions.forEach(item => {
// 检查该作者是否与当前选中的出版社相关
if (this.publisherAuthorMap.has(currentPublisher)) {
const relatedAuthors = this.publisherAuthorMap.get(currentPublisher);
item.visible = relatedAuthors.has(item.author);
} else {
item.visible = false;
}
});
}
}
// 取消选中不可见的作者
this.authorOptions.forEach(item => {
if (!item.visible) {
item.checked = false;
}
});
},
// 切换作者筛选
toggleAuthorFilter(index) {
// 切换选中状态
this.authorOptions[index].checked = !this.authorOptions[index].checked;
// 获取所有选中的作者
const selectedAuthors = this.authorOptions
.filter(item => item.checked)
.map(item => item.author);
// 如果没有选中任何作者,显示所有出版社
if (selectedAuthors.length === 0) {
this.publisherOptions.forEach(item => {
item.visible = true;
});
} else {
// 获取当前选中的作者
const currentAuthor = this.authorOptions[index].author;
// 如果取消选中,需要重新计算可见的出版社
if (!this.authorOptions[index].checked) {
// 重置所有出版社的可见性
this.publisherOptions.forEach(item => {
item.visible = false;
});
// 根据剩余选中的作者更新出版社可见性
selectedAuthors.forEach(author => {
if (this.authorPublisherMap.has(author)) {
const relatedPublishers = this.authorPublisherMap.get(author);
this.publisherOptions.forEach(item => {
if (relatedPublishers.has(item.publisher)) {
item.visible = true;
}
});
}
});
} else {
// 如果是新选中,只显示与该作者相关的出版社
this.publisherOptions.forEach(item => {
// 检查该出版社是否与当前选中的作者相关
if (this.authorPublisherMap.has(currentAuthor)) {
const relatedPublishers = this.authorPublisherMap.get(currentAuthor);
item.visible = relatedPublishers.has(item.publisher);
} else {
item.visible = false;
}
});
}
}
// 取消选中不可见的出版社
this.publisherOptions.forEach(item => {
if (!item.visible) {
item.checked = false;
}
});
},
// 重置筛选
resetFilters() {
// 重置出版社选项
this.publisherOptions.forEach(item => {
item.checked = false;
item.visible = true; // 确保所有出版社选项可见
});
// 重置作者选项
this.authorOptions.forEach(item => {
item.checked = false;
item.visible = true; // 确保所有作者选项可见
});
// 重置筛选状态
this.isFiltered = false;
// 恢复排序后的前十条数据
this.filteredOnSaleProducts = [];
// 关闭弹窗
this.popupShow = false;
// 触发重置事件
this.$emit('reset-filters');
},
// 应用筛选
applyFilters() {
// 获取选中的出版社
const selectedPublishers = this.publisherOptions
.filter(item => item.checked)
.map(item => item.publisher);
// 获取选中的作者
const selectedAuthors = this.authorOptions
.filter(item => item.checked)
.map(item => item.author);
// 如果没有选择任何筛选条件,则显示排序后的前十条数据
if (selectedPublishers.length === 0 && selectedAuthors.length === 0) {
this.filteredOnSaleProducts = [];
this.isFiltered = false;
} else {
// 筛选在售商品
let filteredProducts = this.onSaleProducts.filter(product => {
const matchPublisher = selectedPublishers.length === 0 ||
(product.publisher && selectedPublishers.includes(product.publisher));
const matchAuthor = selectedAuthors.length === 0 ||
(product.author && selectedAuthors.includes(product.author));
return matchPublisher && matchAuthor;
});
// 对筛选后的结果按总价从低到高排序
filteredProducts = filteredProducts.sort((a, b) => {
const priceA = parseFloat(a.totalPrice) || 0;
const priceB = parseFloat(b.totalPrice) || 0;
return priceA - priceB; // 从低到高排序
});
// 只保留前10条数据
this.filteredOnSaleProducts = filteredProducts.slice(0, 10);
this.isFiltered = true;
}
// 关闭弹窗
this.popupShow = false;
// 触发应用筛选事件
this.$emit('apply-filters', {
filteredProducts: this.filteredOnSaleProducts,
selectedPublishers,
selectedAuthors
});
}
}
};
</script>
<style scoped>
.book-list {
margin-top: 20rpx;
display: flex;
flex-wrap: wrap;
}
.book-list>.label {
padding: 10rpx;
display: block;
width: calc(100% - 20rpx);
height: 40rpx;
color: #333;
border-bottom: 2rpx solid #ccc;
}
.book-list>.label>.btn {
display: inline-block;
padding: 10rpx;
text-align: center;
width: 120rpx;
height: 30rpx;
line-height: 30rpx;
color: #fff;
background-color: #3c9cff;
border-radius: 10%;
margin-right: 10rpx;
}
.book-list>.container {
position: relative;
width: 100%;
overflow: hidden;
}
.book-list>.container>.product-grid {
display: flex;
flex-wrap: wrap;
gap: 10rpx;
}
@media screen and (max-width: 768rpx) {
.book-list>.container>.product-grid>.product-card {
width: calc(25% - 7rpx);
}
}
@media screen and (max-width: 480rpx) {
.book-list>.container>.product-grid>.product-card {
width: calc(50% - 5rpx);
}
.book-list>.container>.product-grid>.product-card>.product-image {
height: 200rpx;
}
}
.book-list>.container>.product-grid>.product-card {
width: calc(25% - 8rpx);
background-color: #ffffff;
border-radius: 12rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
overflow: hidden;
flex-shrink: 0;
height: 180rpx;
display: flex;
flex-direction: column;
position: relative;
}
.book-list>.container>.product-grid>.product-card>.product-image-container {
position: relative;
width: 100%;
height: 140rpx;
overflow: hidden;
}
.book-list>.container>.product-grid>.product-card>.product-image-container>.product-image {
width: 100%;
height: 100%;
object-fit: contain;
flex: 0 0 auto;
background-color: #f5f5f5;
}
.book-list>.container>.product-grid>.product-card>.product-image-container>.product-info {
padding: 8rpx;
font-size: 24rpx;
flex: 1;
overflow: hidden;
text-align: center;
}
.book-list>.container>.product-grid>.product-card>.product-image-container>.product-info>.product-price {
font-size: 28rpx;
font-weight: bold;
color: #ff6b00;
display: block;
margin-bottom: 4rpx;
text-align: center;
}
.book-list>.container>.product-grid>.product-card>.product-image-container>.price-details {
font-size: 22rpx;
line-height: 1.2;
overflow: hidden;
text-overflow: ellipsis;
display: flex;
flex-direction: row;
justify-content: center;
gap: 8rpx;
color: #ffffff;
background-color: rgba(0, 0, 0, 0.5);
padding: 4rpx 0;
border-radius: 0 0 8rpx 8rpx;
position: absolute;
bottom: 0;
left: 0;
right: 0;
z-index: 1;
}
.button-group {
display: flex;
align-items: center;
gap: 20rpx;
margin: 10rpx 0;
}
.filter-section {
margin-bottom: 30rpx;
}
.section-title {
font-size: 28rpx;
color: #333;
}
.tag-group {
display: flex;
flex-wrap: wrap;
gap: 10rpx;
margin-top: 10rpx;
}
.filter-popup {
padding: 30rpx;
background-color: #fff;
}
.filter-buttons {
display: flex;
justify-content: space-between;
margin-top: 40rpx;
}
</style>