Browse Source

实现对比价格弹窗的图片和视频显示功能

pull/11/head
徐飞洋 2 months ago
parent
commit
4e6974cab9
  1. 249
      pages/goods-detail/goods-detail.js
  2. 123
      pages/goods-detail/goods-detail.wxml
  3. 218
      pages/goods-detail/goods-detail.wxss
  4. 2
      utils/api.js

249
pages/goods-detail/goods-detail.js

@ -462,6 +462,13 @@ Page({
offsetX: 0, // X轴偏移量 offsetX: 0, // X轴偏移量
offsetY: 0, // Y轴偏移量 offsetY: 0, // Y轴偏移量
initialTouch: null, // 初始触摸点 initialTouch: null, // 初始触摸点
// 对比价格相关状态
showCompareModal: false, // 是否显示对比价格弹窗
activeTab: 'home', // 当前激活的选项卡,'home'表示首页数据,'favorite'表示收藏数据
homeGoods: [], // 首页商品数据
favoriteGoods: [], // 收藏商品数据
loadingHome: false, // 首页数据加载状态
loadingFavorite: false, // 收藏数据加载状态
}, },
onLoad: function (options) { onLoad: function (options) {
@ -2028,6 +2035,248 @@ Page({
}); });
}, },
// 对比价格功能:处理按钮点击事件
onCompareClick: function () {
console.log('用户点击了对比价格按钮,准备显示弹窗');
// 立即显示弹窗,不等待数据加载
this.setData({
showCompareModal: true,
activeTab: 'home' // 默认显示首页数据选项卡
});
// 打印弹窗状态,用于调试
console.log('弹窗状态设置为:', this.data.showCompareModal);
// 加载首页数据
this.loadHomeGoods();
// 加载收藏数据
this.loadFavoriteGoods();
},
// 关闭对比价格弹窗
closeCompareModal: function () {
this.setData({
showCompareModal: false
});
},
// 阻止事件冒泡
stopPropagation: function () {
// 空函数,用于阻止事件冒泡
},
// 切换选项卡
switchTab: function (e) {
const tab = e.currentTarget.dataset.tab;
this.setData({
activeTab: tab
});
// 如果切换到收藏选项卡且收藏数据为空,则加载收藏数据
if (tab === 'favorite' && this.data.favoriteGoods.length === 0) {
this.loadFavoriteGoods();
}
},
// 加载首页商品数据
loadHomeGoods: function () {
this.setData({ loadingHome: true });
// 调用API获取首页商品列表
API.getProducts()
.then(res => {
console.log('获取首页商品数据成功:', res);
// API.getProducts()直接返回商品数组,而不是包含data字段的对象
if (Array.isArray(res)) {
// 为每个商品添加mediaItems字段
const processedGoods = res.map(goods => {
return {
...goods,
mediaItems: processMediaUrls(goods.imageUrls)
};
});
this.setData({
homeGoods: processedGoods,
loadingHome: false
});
} else {
this.setData({ loadingHome: false });
wx.showToast({
title: '获取首页数据失败',
icon: 'none',
duration: 2000
});
}
})
.catch(err => {
console.error('获取首页商品数据失败:', err);
this.setData({ loadingHome: false });
wx.showToast({
title: '获取首页数据失败',
icon: 'none',
duration: 2000
});
});
},
// 加载已收藏商品数据
loadFavoriteGoods: function () {
this.setData({ loadingFavorite: true });
// 获取用户手机号
let userPhone = '';
try {
// 打印所有可能的存储位置内容,用于调试
console.log('调试信息 - 获取收藏数据前的存储状态:');
console.log('userId:', wx.getStorageSync('userId'));
console.log('users:', wx.getStorageSync('users'));
console.log('userInfo:', wx.getStorageSync('userInfo'));
console.log('phoneNumber:', wx.getStorageSync('phoneNumber'));
// 先尝试从最新的存储位置获取
const userInfo = wx.getStorageSync('userInfo');
if (userInfo && userInfo.phoneNumber) {
userPhone = userInfo.phoneNumber;
console.log('从userInfo获取到手机号:', userPhone);
} else {
// 然后尝试从users对象获取
const users = wx.getStorageSync('users') || {};
const userId = wx.getStorageSync('userId');
if (userId && users[userId] && users[userId].phoneNumber) {
userPhone = users[userId].phoneNumber;
console.log('从users[' + userId + ']获取到手机号:', userPhone);
} else {
// 最后尝试从单独的phoneNumber字段获取
userPhone = wx.getStorageSync('phoneNumber');
console.log('从phoneNumber字段获取到手机号:', userPhone);
}
}
} catch (e) {
console.error('获取用户手机号失败:', e);
}
// 验证手机号是否有效
if (!userPhone) {
this.setData({ loadingFavorite: false });
console.log('用户未登录或未获取手机号,无法加载收藏数据');
wx.showToast({
title: '请先登录获取手机号',
icon: 'none',
duration: 2000
});
return;
}
// 确保手机号格式正确
if (typeof userPhone !== 'string' || userPhone.length < 11) {
this.setData({ loadingFavorite: false });
console.error('手机号格式不正确:', userPhone);
return;
}
console.log('准备调用API获取收藏数据,手机号:', userPhone);
// 调用API获取收藏商品列表
API.getFavorites(userPhone)
.then(res => {
console.log('获取收藏商品数据成功:', res);
// 处理API返回的数据结构
let favoritesList = [];
if (res) {
if (Array.isArray(res.data)) {
favoritesList = res.data;
} else if (res.data && Array.isArray(res.data.favorites)) {
favoritesList = res.data.favorites;
} else if (res.data && Array.isArray(res.data.data)) {
favoritesList = res.data.data;
} else if (Array.isArray(res)) {
// 直接返回数组的情况
favoritesList = res;
}
console.log('解析后的收藏商品列表:', favoritesList);
}
// 检查收藏列表是否只包含productId
const hasOnlyProductId = favoritesList.length > 0 &&
favoritesList.every(item =>
(typeof item === 'string' || typeof item === 'number') ||
(typeof item === 'object' && item.productId && !item.name)
);
if (hasOnlyProductId) {
console.log('收藏列表只包含productId,需要获取商品详情');
// 转换为productId数组
const productIds = favoritesList.map(item =>
typeof item === 'object' ? item.productId : item
);
console.log('提取的productId列表:', productIds);
// 并行获取所有商品详情
const productPromises = productIds.map(productId =>
API.getProductDetail({ productId: productId })
.then(detailRes => {
console.log('获取商品详情成功:', productId, detailRes);
return detailRes && detailRes.data ? detailRes.data : null;
})
.catch(err => {
console.error('获取商品详情失败:', productId, err);
return null;
})
);
// 等待所有商品详情获取完成
Promise.all(productPromises)
.then(products => {
// 过滤掉获取失败的商品,并为每个商品添加mediaItems字段
const validProducts = products
.filter(product => product !== null)
.map(product => ({
...product,
mediaItems: processMediaUrls(product.imageUrls)
}));
console.log('所有商品详情获取完成,有效商品数量:', validProducts.length);
this.setData({
favoriteGoods: validProducts,
loadingFavorite: false
});
})
.catch(err => {
console.error('获取商品详情列表失败:', err);
this.setData({
favoriteGoods: [],
loadingFavorite: false
});
});
} else {
// 收藏列表已经包含完整商品信息,为每个商品添加mediaItems字段
const processedFavorites = favoritesList.map(product => ({
...product,
mediaItems: processMediaUrls(product.imageUrls)
}));
this.setData({
favoriteGoods: processedFavorites,
loadingFavorite: false
});
}
})
.catch(err => {
console.error('获取收藏商品数据失败:', err);
this.setData({ loadingFavorite: false });
wx.showToast({
title: '获取收藏数据失败: ' + (err && err.message ? err.message : '未知错误'),
icon: 'none',
duration: 3000
});
});
},
// 返回上一页 // 返回上一页
goBack() { goBack() {
wx.navigateBack(); wx.navigateBack();

123
pages/goods-detail/goods-detail.wxml

@ -71,6 +71,14 @@
<text class="price-value">{{goodsDetail.price}}</text> <text class="price-value">{{goodsDetail.price}}</text>
<text style="margin-left: 10rpx; color: #333; font-size: 32rpx;">(可议价)</text> <text style="margin-left: 10rpx; color: #333; font-size: 32rpx;">(可议价)</text>
</view> </view>
<view
class="compare-button"
bindtap="onCompareClick"
style="display: flex; align-items: center; margin-right: 20rpx; padding: 8rpx 16rpx; border: 2rpx solid #4a90e2; border-radius: 20rpx;"
>
<text style="font-size: 32rpx; color: #4a90e2; margin-right: 8rpx;">对比价格</text>
<text style="font-size: 28rpx; color: #4a90e2;">></text>
</view>
<view <view
class="favorite-button" class="favorite-button"
bindtap="onFavoriteClick" bindtap="onFavoriteClick"
@ -153,7 +161,8 @@
</view> </view>
</view> </view>
</view> </view>
</view>
<!-- 登录弹窗 --> <!-- 登录弹窗 -->
<view wx:if="{{showOneKeyLoginModal}}" class="auth-modal-overlay"> <view wx:if="{{showOneKeyLoginModal}}" class="auth-modal-overlay">
<view class="auth-modal-container"> <view class="auth-modal-container">
@ -176,7 +185,117 @@
</view> </view>
</view> </view>
</view> </view>
</view>
<!-- 底部弹出层 - 对比价格 -->
<view wx:if="{{showCompareModal}}" class="compare-modal-overlay" bindtap="closeCompareModal">
<view class="compare-modal-container" catchtap="stopPropagation">
<view class="compare-modal-header">
<text class="compare-modal-title">对比价格</text>
<text class="compare-modal-close" bindtap="closeCompareModal">×</text>
</view>
<!-- 选项卡 -->
<view class="compare-tabs">
<view
class="compare-tab {{activeTab === 'home' ? 'active' : ''}}"
bindtap="switchTab"
data-tab="home"
>
首页数据
</view>
<view
class="compare-tab {{activeTab === 'favorite' ? 'active' : ''}}"
bindtap="switchTab"
data-tab="favorite"
>
已收藏数据
</view>
</view>
<!-- 商品列表 -->
<view class="compare-goods-list">
<block wx:if="{{activeTab === 'home' && homeGoods.length > 0}}">
<view wx:for="{{homeGoods}}" wx:key="id" class="compare-goods-item">
<view class="product-image-wrapper">
<!-- 视频处理:根据mediaItems中的类型字段判断 -->
<video
wx:if="{{item.mediaItems && item.mediaItems.length > 0 && item.mediaItems[0].type === 'video'}}"
class="product-media"
src="{{item.mediaItems[0].url}}"
mode="aspectFill"
show-center-play-btn="{{true}}"
show-play-btn="{{false}}"
controls="{{true}}"
autoplay="{{true}}"
loop="{{true}}"
muted="{{true}}"
object-fit="fill"
poster=""
></video>
<!-- 图片处理 -->
<image
wx:else
class="product-media"
src="{{item.mediaItems && item.mediaItems.length > 0 ? item.mediaItems[0].url : (item.imageUrls[0] || '')}}"
mode="aspectFill"
lazy-load="true"
></image>
</view>
<view class="compare-goods-info">
<text class="compare-goods-name">{{item.name}}</text>
<text class="compare-goods-spec">{{item.specification || item.spec || item.specs || '暂无规格'}}</text>
<text class="compare-goods-quantity">{{item.quantity || '暂无件数'}}件</text>
<text class="compare-goods-price">价格: {{item.price}}</text>
<text class="compare-goods-region">{{item.region || '暂无地区'}}</text>
</view>
</view>
</block>
<block wx:elif="{{activeTab === 'home' && homeGoods.length === 0}}">
<view class="compare-empty">暂无首页数据</view>
</block>
<block wx:if="{{activeTab === 'favorite' && favoriteGoods.length > 0}}">
<view wx:for="{{favoriteGoods}}" wx:key="id" class="compare-goods-item">
<view class="product-image-wrapper">
<!-- 视频处理:根据mediaItems中的类型字段判断 -->
<video
wx:if="{{item.mediaItems && item.mediaItems.length > 0 && item.mediaItems[0].type === 'video'}}"
class="product-media"
src="{{item.mediaItems[0].url}}"
mode="aspectFill"
show-center-play-btn="{{true}}"
show-play-btn="{{false}}"
controls="{{true}}"
autoplay="{{true}}"
loop="{{true}}"
muted="{{true}}"
object-fit="fill"
poster=""
></video>
<!-- 图片处理 -->
<image
wx:else
class="product-media"
src="{{item.mediaItems && item.mediaItems.length > 0 ? item.mediaItems[0].url : (item.imageUrls[0] || '')}}"
mode="aspectFill"
lazy-load="true"
></image>
</view>
<view class="compare-goods-info">
<text class="compare-goods-name">{{item.name}}</text>
<text class="compare-goods-spec">{{item.specification || item.spec || item.specs || '暂无规格'}}</text>
<text class="compare-goods-quantity">{{item.quantity || '暂无件数'}}件</text>
<text class="compare-goods-price">价格: {{item.price}}</text>
<text class="compare-goods-region">{{item.region || '暂无地区'}}</text>
</view>
</view>
</block>
<block wx:elif="{{activeTab === 'favorite' && favoriteGoods.length === 0}}">
<view class="compare-empty">暂无收藏商品</view>
</block>
</view>
</view>
</view>
<!-- 操作按钮区域 --> <!-- 操作按钮区域 -->
<view class="action-buttons" wx:if="{{!fromSeller}}"> <view class="action-buttons" wx:if="{{!fromSeller}}">

218
pages/goods-detail/goods-detail.wxss

@ -748,4 +748,222 @@ video.slider-media .wx-video-volume-icon {
color: #595959; color: #595959;
line-height: 1.5; line-height: 1.5;
font-weight: 500; font-weight: 500;
}
/* 对比价格弹窗样式 */
.compare-modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: flex-end;
z-index: 9999;
animation: fadeIn 0.3s ease-out;
}
.compare-modal-container {
width: 100%;
background-color: #fff;
border-top-left-radius: 32rpx;
border-top-right-radius: 32rpx;
padding-bottom: 20rpx;
max-height: 70vh;
animation: slideUp 0.3s ease-out;
display: flex;
flex-direction: column;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes slideUp {
from {
transform: translateY(100%);
}
to {
transform: translateY(0);
}
}
.compare-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24rpx 32rpx;
border-bottom: 1rpx solid #f0f0f0;
position: relative;
}
.compare-modal-title {
font-size: 36rpx;
font-weight: bold;
color: #222;
text-align: center;
flex: 1;
}
.compare-modal-close {
font-size: 48rpx;
color: #999;
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
transition: all 0.3s ease;
}
.compare-modal-close:active {
background-color: #f0f0f0;
transform: scale(0.9);
}
.compare-tabs {
display: flex;
background-color: #f8f9fa;
padding: 12rpx;
border-radius: 0;
}
.compare-tab {
flex: 1;
text-align: center;
padding: 16rpx 0;
font-size: 32rpx;
color: #666;
border-radius: 12rpx;
transition: all 0.3s ease;
font-weight: 500;
}
.compare-tab.active {
background-color: #fff;
color: #4a90e2;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
font-weight: bold;
}
.compare-goods-list {
flex: 1;
overflow-y: auto;
padding: 16rpx;
}
.compare-goods-item {
display: flex;
background-color: #fff;
border-radius: 16rpx;
padding: 16rpx;
margin-bottom: 16rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
transition: all 0.3s ease;
border: 1rpx solid #f0f0f0;
}
.compare-goods-item:active {
transform: translateY(2rpx);
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.12);
}
.compare-goods-image {
width: 120rpx;
height: 120rpx;
border-radius: 12rpx;
margin-right: 16rpx;
object-fit: cover;
background: linear-gradient(135deg, #f0f4ff 0%, #d9e4ff 100%);
}
/* 视频和图片容器样式 */
.product-image-wrapper {
width: 120rpx;
height: 120rpx;
border-radius: 12rpx;
margin-right: 16rpx;
overflow: hidden;
position: relative;
background: linear-gradient(135deg, #f0f4ff 0%, #d9e4ff 100%);
}
/* 视频和图片样式 */
.product-media {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
object-fit: cover;
}
.compare-goods-info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.compare-goods-name {
font-size: 32rpx;
color: #222;
font-weight: 600;
line-height: 1.4;
margin-bottom: 8rpx;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.compare-goods-spec {
font-size: 28rpx;
color: #666;
margin-bottom: 4rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.compare-goods-quantity {
font-size: 28rpx;
color: #666;
margin-bottom: 4rpx;
}
.compare-goods-price {
font-size: 36rpx;
color: #ff4d4f;
font-weight: bold;
margin-bottom: 4rpx;
}
.compare-goods-region {
font-size: 26rpx;
color: #999;
}
.compare-empty {
text-align: center;
padding: 80rpx 0;
color: #999;
font-size: 32rpx;
}
/* 修复样式冲突 */
.goods-detail-page {
position: relative;
z-index: 1;
} }

2
utils/api.js

@ -754,7 +754,7 @@ module.exports = {
request('/api/product/list', 'POST', { request('/api/product/list', 'POST', {
openid: openid, openid: openid,
status: 'all', // 请求所有状态的商品(除了hidden) status: 'all', // 请求所有状态的商品(除了hidden)
viewMode: 'seller', // 添加viewMode参数,限制只能查看当前用户的商品 viewMode: 'buyer', // 使用buyer模式获取所有商品,而非仅当前用户的商品
page: 1, page: 1,
pageSize: 100 // 获取足够多的商品 pageSize: 100 // 获取足够多的商品
}).then(res => { }).then(res => {

Loading…
Cancel
Save