daShangDao_miniProgram/components/_deprecated/PriceComparison.vue
2026-06-15 16:37:57 +08:00

716 lines
18 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="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="handleSwitchCompareType">
{{ compareType === 'isbn' ? '书名比价' : 'ISBN比价' }}
</view>
<view class="btn" @click="popupShow = true">更多筛序</view>
</view>
<!-- 在售商品展示区域 -->
<view class="container" v-if="showProducts.length > 0">
<view class="product-grid">
<view class="product-card" v-for="(product, index) in showProducts" :key="index">
<view class="product-image-container">
<image class="product-image" :src="product.imageUrl" mode="aspectFit"
@click="previewImage(product.imageUrl, showProducts)">
</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 class="empty-products" v-else>
<text>暂无在售商品信息</text>
</view>
</view>
</template>
<script>
export default {
name: 'price-comparison',
props: {
// 当前比价类型
compareType: {
type: String,
default: 'isbn'
},
// 书籍标识符(ISBN或书名)
keyword: {
type: String,
default: ''
},
// 品相值
conditionValue: {
type: String,
default: ''
},
// 排序类型
sortType: {
type: String,
default: 'price' // 默认按价格排序
},
// 阻止自动加载
preventAutoLoad: {
type: Boolean,
default: false
},
},
data() {
return {
popupShow: false,
isFiltered: false,
publisherOptions: [],
authorOptions: [],
allProducts: [], // 存储所有在售商品
displayProducts: [], // 展示的商品
filteredProducts: [], // 筛选后的商品
publisherAuthorMap: {}, // 出版社-作者关系映射
authorPublisherMap: {}, // 作者-出版社关系映射
loading: false,
loadError: null
};
},
computed: {
// 根据筛选状态决定展示哪些商品
showProducts() {
return this.isFiltered ? this.filteredProducts : this.displayProducts;
}
},
watch: {
keyword: {
handler(newVal) {
if (newVal && !this.preventAutoLoad) {
this.loadProducts();
}
},
immediate: true
},
compareType: {
handler(newVal) {
if (this.keyword && !this.preventAutoLoad) {
this.loadProducts();
}
}
}
},
methods: {
// 加载在售商品数据
async loadProducts() {
if (!this.keyword) return;
this.loading = true;
this.loadError = null;
try {
// 获取cookies可以从缓存中读取
const cookies = uni.getStorageSync('cookies');
// 调用API获取在售商品数据
const response = await this.fetchProductData(this.keyword, this.sortType, this.conditionValue, cookies);
// 处理数据
this.processProductData(response);
// 发出加载完成事件
this.$emit('loaded', {
products: this.allProducts,
displayProducts: this.displayProducts
});
} catch (error) {
console.error('获取在售商品信息失败:', error);
this.loadError = error.message || '加载失败';
this.$emit('error', error);
} finally {
this.loading = false;
}
},
// 调用API获取数据
async fetchProductData(keyword, sortType, conditionValue, cookies) {
return new Promise((resolve, reject) => {
uni.request({
url: 'https://api.buzhiyushu.cn/zhishu/baseInfo/getBookList',
method: 'POST',
data: {
keyword,
sortType,
conditionValue,
compareType: this.compareType
},
header: {
'Cookie': cookies || ''
},
success: (res) => {
if (res.statusCode === 200 && res.data) {
resolve(res.data);
} else {
reject(new Error('请求失败: ' + res.statusCode));
}
},
fail: (err) => {
reject(err);
}
});
});
},
// 处理获取到的数据
processProductData(data) {
// 获取屏蔽店铺列表
const blockedShopsStr = uni.getStorageSync('blockedShops') || '';
const blockedShops = blockedShopsStr.split(';').filter(shop => shop.trim() !== '');
// 过滤掉屏蔽的店铺
const filteredData = Array.isArray(data) ? data.filter(product => {
return !blockedShops.some(shop => product.shopName && product.shopName.includes(shop.trim()));
}) : [];
// 保存所有数据用于筛选
this.allProducts = [...filteredData];
// 对商品数据按照总价从低到高排序
const sortedData = [...filteredData].sort((a, b) => {
const priceA = parseFloat(a.totalPrice) || 0;
const priceB = parseFloat(b.totalPrice) || 0;
return priceA - priceB; // 从低到高排序
});
// 只保留前12条数据用于展示
this.displayProducts = sortedData.slice(0, 12);
// 提取出版社和作者信息,用于筛选选项
this.extractPublishersAndAuthors();
// 计算参考价格
this.calculateReferencePrice();
},
// 提取出版社和作者信息
extractPublishersAndAuthors() {
// 创建映射对象
const publisherAuthorMap = {};
const authorPublisherMap = {};
// 遍历商品数据,建立关联关系
this.allProducts.forEach(product => {
if (product.publisher && product.author) {
// 添加出版社-作者关联
if (!publisherAuthorMap[product.publisher]) {
publisherAuthorMap[product.publisher] = [];
}
if (!publisherAuthorMap[product.publisher].includes(product.author)) {
publisherAuthorMap[product.publisher].push(product.author);
}
// 添加作者-出版社关联
if (!authorPublisherMap[product.author]) {
authorPublisherMap[product.author] = [];
}
if (!authorPublisherMap[product.author].includes(product.publisher)) {
authorPublisherMap[product.author].push(product.publisher);
}
}
});
// 保存关联映射
this.publisherAuthorMap = publisherAuthorMap;
this.authorPublisherMap = authorPublisherMap;
// 提取出版社
const publishers = new Set();
this.allProducts.forEach(product => {
if (product.publisher) {
publishers.add(product.publisher);
}
});
// 提取作者
const authors = new Set();
this.allProducts.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
}));
},
// 计算参考价格
calculateReferencePrice() {
if (!this.displayProducts || this.displayProducts.length === 0) return;
// 获取最低价格
const lowestBookPrice = Math.min(...this.displayProducts.map(p => parseFloat(p.bookPrice) || 0));
const lowestTotalPrice = Math.min(...this.displayProducts.map(p => parseFloat(p.totalPrice) || 0));
// 发出价格计算事件
this.$emit('price-calculated', {
lowestBookPrice,
lowestTotalPrice,
products: this.displayProducts
});
},
// 打开和关闭筛选弹窗
open() {
this.popupShow = true;
this.$emit('popup-open');
},
close() {
this.popupShow = false;
this.$emit('popup-close');
},
// 切换比价类型
handleSwitchCompareType() {
const newType = this.compareType === 'isbn' ? 'title' : 'isbn';
this.$emit('compare-type-change', newType);
},
// 图片预览
previewImage(currentUrl, productList) {
// 检查productList是否存在且是数组
let urls = [];
if (productList && Array.isArray(productList)) {
// 提取所有图片 URL
urls = productList.map(item => item.imageUrl);
} else {
urls = [currentUrl];
}
// 确保urls中至少有一个有效的URL
if (!urls.length || !urls[0]) {
console.error('没有有效的图片URL可预览');
return;
}
// 调用预览接口
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);
}
});
},
// 筛选相关方法
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[publisher]) {
const relatedAuthors = this.publisherAuthorMap[publisher];
this.authorOptions.forEach(item => {
if (relatedAuthors.includes(item.author)) {
item.visible = true;
}
});
}
});
} else {
// 如果是新选中,只显示与该出版社相关的作者
this.authorOptions.forEach(item => {
// 检查该作者是否与当前选中的出版社相关
if (this.publisherAuthorMap[currentPublisher]) {
const relatedAuthors = this.publisherAuthorMap[currentPublisher];
item.visible = relatedAuthors.includes(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[author]) {
const relatedPublishers = this.authorPublisherMap[author];
this.publisherOptions.forEach(item => {
if (relatedPublishers.includes(item.publisher)) {
item.visible = true;
}
});
}
});
} else {
// 如果是新选中,只显示与该作者相关的出版社
this.publisherOptions.forEach(item => {
// 检查该出版社是否与当前选中的作者相关
if (this.authorPublisherMap[currentAuthor]) {
const relatedPublishers = this.authorPublisherMap[currentAuthor];
item.visible = relatedPublishers.includes(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.filteredProducts = [];
// 关闭弹窗
this.popupShow = false;
// 触发事件
this.$emit('filters-reset');
},
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.filteredProducts = [];
this.isFiltered = false;
} else {
// 筛选在售商品
let filteredProducts = this.allProducts.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.filteredProducts = filteredProducts.slice(0, 10);
this.isFiltered = true;
}
// 关闭弹窗
this.popupShow = false;
// 触发事件
this.$emit('filters-applied', {
filteredProducts: this.filteredProducts,
selectedPublishers,
selectedAuthors
});
},
// 手动刷新数据
refresh() {
this.loadProducts();
}
}
}
</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;
}
.empty-products {
padding: 30rpx;
text-align: center;
color: #999;
font-size: 28rpx;
}
.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>