556 lines
15 KiB
JavaScript
556 lines
15 KiB
JavaScript
import Dialog from 'tdesign-miniprogram/dialog/index';
|
||
import Toast from 'tdesign-miniprogram/toast/index';
|
||
import {
|
||
fetchCartGroupData,
|
||
updateCartItem,
|
||
removeFromCart,
|
||
addToCart,
|
||
selectCartItem,
|
||
selectAllCartItems
|
||
} from '../../services/cart/cart';
|
||
|
||
Page({
|
||
data: {
|
||
cartGroupData: null,
|
||
refresherTriggered: false, // 下拉刷新状态
|
||
},
|
||
|
||
// 调用自定义tabbar的init函数,使页面与tabbar激活状态保持一致
|
||
onShow() {
|
||
this.getTabBar().init();
|
||
// 每次显示页面时刷新购物车数据,确保数据是最新的
|
||
this.refreshData();
|
||
},
|
||
|
||
onLoad() {
|
||
this.refreshData();
|
||
},
|
||
|
||
refreshData() {
|
||
this.getCartGroupData().then((res) => {
|
||
let isEmpty = true;
|
||
const cartGroupData = res.data;
|
||
// 一些组件中需要的字段可能接口并没有返回,或者返回的数据结构与预期不一致,需要在此先对数据做一些处理
|
||
// 统计门店下加购的商品是否全选、是否存在缺货/无货
|
||
if (cartGroupData && cartGroupData.storeGoods) {
|
||
for (const store of cartGroupData.storeGoods) {
|
||
store.isSelected = true; // 该门店已加购商品是否全选
|
||
store.storeStockShortage = false; // 该门店已加购商品是否存在库存不足
|
||
if (!store.shortageGoodsList) {
|
||
store.shortageGoodsList = []; // 该门店已加购商品如果库存为0需单独分组
|
||
}
|
||
for (const activity of store.promotionGoodsList) {
|
||
activity.goodsPromotionList = activity.goodsPromotionList.filter((goods) => {
|
||
goods.originPrice = undefined;
|
||
|
||
// 统计是否有加购数大于库存数的商品
|
||
if (goods.quantity > goods.stockQuantity) {
|
||
store.storeStockShortage = true;
|
||
}
|
||
// 统计是否全选
|
||
if (!goods.isSelected) {
|
||
store.isSelected = false;
|
||
}
|
||
// 库存为0(无货)的商品单独分组
|
||
if (goods.stockQuantity > 0) {
|
||
return true;
|
||
}
|
||
store.shortageGoodsList.push(goods);
|
||
return false;
|
||
});
|
||
|
||
if (activity.goodsPromotionList.length > 0) {
|
||
isEmpty = false;
|
||
}
|
||
}
|
||
if (store.shortageGoodsList.length > 0) {
|
||
isEmpty = false;
|
||
}
|
||
}
|
||
}
|
||
if (cartGroupData && cartGroupData.invalidGoodItems) {
|
||
cartGroupData.invalidGoodItems = cartGroupData.invalidGoodItems.map((goods) => {
|
||
goods.originPrice = undefined;
|
||
return goods;
|
||
});
|
||
}
|
||
if (cartGroupData) {
|
||
cartGroupData.isNotEmpty = !isEmpty;
|
||
}
|
||
this.setData({ cartGroupData });
|
||
});
|
||
},
|
||
|
||
findGoods(spuId, skuId) {
|
||
let currentStore;
|
||
let currentActivity;
|
||
let currentGoods;
|
||
if (!this.data.cartGroupData || !this.data.cartGroupData.storeGoods) {
|
||
return {
|
||
currentStore: null,
|
||
currentActivity: null,
|
||
currentGoods: null,
|
||
};
|
||
}
|
||
const { storeGoods } = this.data.cartGroupData;
|
||
for (const store of storeGoods) {
|
||
for (const activity of store.promotionGoodsList) {
|
||
for (const goods of activity.goodsPromotionList) {
|
||
if (goods.spuId === spuId && goods.skuId === skuId) {
|
||
currentStore = store;
|
||
currentActivity = activity;
|
||
currentGoods = goods;
|
||
return {
|
||
currentStore,
|
||
currentActivity,
|
||
currentGoods,
|
||
};
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return {
|
||
currentStore,
|
||
currentActivity,
|
||
currentGoods,
|
||
};
|
||
},
|
||
|
||
// 获取购物车数据 - 每次都从后端获取最新数据
|
||
getCartGroupData() {
|
||
return fetchCartGroupData();
|
||
},
|
||
|
||
// 选择单个商品
|
||
selectGoodsService({ spuId, skuId, isSelected }) {
|
||
// 先更新本地状态
|
||
const { currentGoods } = this.findGoods(spuId, skuId);
|
||
if (currentGoods) {
|
||
currentGoods.isSelected = isSelected ? 1 : 0;
|
||
}
|
||
|
||
// 调用API更新后端状态
|
||
const cartId = currentGoods ? currentGoods.uid : spuId;
|
||
return selectCartItem(cartId, isSelected).catch(err => {
|
||
console.error('选择商品失败:', err);
|
||
// 如果API调用失败,恢复本地状态
|
||
if (currentGoods) {
|
||
currentGoods.isSelected = isSelected ? 0 : 1;
|
||
}
|
||
throw err;
|
||
});
|
||
},
|
||
|
||
// 全选门店
|
||
// 注:实际场景时应该调用接口更改选中状态
|
||
selectStoreService({ storeId, isSelected }) {
|
||
if (!this.data.cartGroupData || !this.data.cartGroupData.storeGoods) {
|
||
return;
|
||
}
|
||
const currentStore = this.data.cartGroupData.storeGoods.find((s) => s.storeId === storeId);
|
||
if (currentStore) {
|
||
currentStore.isSelected = isSelected;
|
||
// 添加数据验证,确保数组存在
|
||
if (Array.isArray(currentStore.promotionGoodsList)) {
|
||
currentStore.promotionGoodsList.forEach((activity) => {
|
||
if (Array.isArray(activity.goodsPromotionList)) {
|
||
activity.goodsPromotionList.forEach((goods) => {
|
||
goods.isSelected = isSelected;
|
||
});
|
||
}
|
||
});
|
||
}
|
||
}
|
||
return Promise.resolve();
|
||
},
|
||
|
||
// 加购数量变更
|
||
async changeQuantityService(spuId, skuId, quantity) {
|
||
try {
|
||
const goods = this.findGoods(spuId, skuId);
|
||
if (!goods) {
|
||
Toast({
|
||
context: this,
|
||
selector: '#t-toast',
|
||
message: '商品不存在',
|
||
theme: 'error',
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 调用后端API,传递skuId
|
||
await updateCartItem(spuId, quantity, skuId);
|
||
|
||
// 更新本地数据
|
||
goods.quantity = quantity;
|
||
this.setData({
|
||
cartGroupData: this.data.cartGroupData,
|
||
});
|
||
|
||
Toast({
|
||
context: this,
|
||
selector: '#t-toast',
|
||
message: '修改成功',
|
||
theme: 'success',
|
||
});
|
||
} catch (error) {
|
||
console.error('修改数量失败:', error);
|
||
Toast({
|
||
context: this,
|
||
selector: '#t-toast',
|
||
message: error.message || '修改失败',
|
||
theme: 'error',
|
||
});
|
||
}
|
||
},
|
||
|
||
// 删除商品
|
||
async deleteGoodsService(spuId, skuId) {
|
||
try {
|
||
const goods = this.findGoods(spuId, skuId);
|
||
if (!goods.currentGoods) {
|
||
Toast({
|
||
context: this,
|
||
selector: '#t-toast',
|
||
message: '商品不存在',
|
||
theme: 'error',
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 调用后端API,传递skuId
|
||
await removeFromCart(spuId, skuId);
|
||
|
||
// 重新获取购物车数据
|
||
this.refreshData();
|
||
|
||
Toast({
|
||
context: this,
|
||
selector: '#t-toast',
|
||
message: '删除成功',
|
||
theme: 'success',
|
||
});
|
||
} catch (error) {
|
||
console.error('删除商品失败:', error);
|
||
Toast({
|
||
context: this,
|
||
selector: '#t-toast',
|
||
message: error.message || '删除失败',
|
||
theme: 'error',
|
||
});
|
||
}
|
||
},
|
||
|
||
// 清空失效商品
|
||
// 注:实际场景时应该调用接口
|
||
clearInvalidGoodsService() {
|
||
this.data.cartGroupData.invalidGoodItems = [];
|
||
return Promise.resolve();
|
||
},
|
||
|
||
onGoodsSelect(e) {
|
||
const {
|
||
goods: { spuId, skuId },
|
||
isSelected,
|
||
} = e.detail;
|
||
const { currentGoods } = this.findGoods(spuId, skuId);
|
||
Toast({
|
||
context: this,
|
||
selector: '#t-toast',
|
||
message: `${isSelected ? '选择' : '取消'}"${
|
||
currentGoods.title.length > 5 ? `${currentGoods.title.slice(0, 5)}...` : currentGoods.title
|
||
}"`,
|
||
icon: '',
|
||
});
|
||
this.selectGoodsService({ spuId, skuId, isSelected }).then(() => this.refreshData());
|
||
},
|
||
|
||
onStoreSelect(e) {
|
||
const {
|
||
store: { storeId },
|
||
isSelected,
|
||
} = e.detail;
|
||
this.selectStoreService({ storeId, isSelected }).then(() => this.refreshData());
|
||
},
|
||
|
||
onQuantityChange(e) {
|
||
const {
|
||
goods: { spuId, skuId },
|
||
quantity,
|
||
} = e.detail;
|
||
|
||
const { currentGoods } = this.findGoods(spuId, skuId);
|
||
const stockQuantity = currentGoods.stockQuantity > 0 ? currentGoods.stockQuantity : 0; // 避免后端返回的是-1
|
||
// 加购数量超过库存数量
|
||
if (quantity > stockQuantity) {
|
||
// 加购数量等于库存数量的情况下继续加购
|
||
if (currentGoods.quantity === stockQuantity && quantity - stockQuantity === 1) {
|
||
Toast({
|
||
context: this,
|
||
selector: '#t-toast',
|
||
message: '当前商品库存不足',
|
||
});
|
||
return;
|
||
}
|
||
Dialog.confirm({
|
||
title: '商品库存不足',
|
||
content: `当前商品库存不足,最大可购买数量为${stockQuantity}件`,
|
||
confirmBtn: '修改为最大可购买数量',
|
||
cancelBtn: '取消',
|
||
})
|
||
.then(() => {
|
||
this.changeQuantityService(spuId, skuId, stockQuantity).then(() => this.refreshData());
|
||
})
|
||
.catch(() => {});
|
||
return;
|
||
}
|
||
this.changeQuantityService(spuId, skuId, quantity).then(() => this.refreshData());
|
||
},
|
||
|
||
// SKU变更
|
||
async onSkuChange(e) {
|
||
const { oldSpuId, oldSkuId, newSpuId, newSkuId, quantity } = e.detail;
|
||
|
||
try {
|
||
// 先删除旧SKU
|
||
await removeFromCart(oldSpuId, oldSkuId);
|
||
|
||
// 再添加新SKU,使用用户选择的数量
|
||
await addToCart(newSpuId, newSkuId, quantity || 1);
|
||
|
||
// 刷新购物车数据
|
||
this.refreshData();
|
||
|
||
Toast({
|
||
context: this,
|
||
selector: '#t-toast',
|
||
message: '规格修改成功',
|
||
theme: 'success',
|
||
});
|
||
} catch (error) {
|
||
console.error('SKU变更失败:', error);
|
||
Toast({
|
||
context: this,
|
||
selector: '#t-toast',
|
||
message: error.message || '修改规格失败',
|
||
theme: 'error',
|
||
});
|
||
}
|
||
},
|
||
|
||
goCollect() {
|
||
/** 活动肯定有一个活动ID,用来获取活动banner,活动商品列表等 */
|
||
const promotionID = '123';
|
||
wx.navigateTo({
|
||
url: `/pages/promotion/promotion-detail/index?promotion_id=${promotionID}`,
|
||
});
|
||
},
|
||
|
||
goGoodsDetail(e) {
|
||
const { spuId, storeId } = e.detail.goods;
|
||
wx.navigateTo({
|
||
url: `/pages/goods/details/index?spuId=${spuId}&storeId=${storeId}`,
|
||
});
|
||
},
|
||
|
||
clearInvalidGoods() {
|
||
// 实际场景时应该调用接口清空失效商品
|
||
this.clearInvalidGoodsService().then(() => this.refreshData());
|
||
},
|
||
|
||
onGoodsDelete(e) {
|
||
const {
|
||
goods: { spuId, skuId },
|
||
} = e.detail;
|
||
Dialog.confirm({
|
||
content: '确认删除该商品吗?',
|
||
confirmBtn: '确定',
|
||
cancelBtn: '取消',
|
||
}).then(() => {
|
||
// deleteGoodsService 内部已经包含了Toast提示和数据刷新,无需重复操作
|
||
this.deleteGoodsService(spuId, skuId);
|
||
});
|
||
},
|
||
|
||
onSelectAll(event) {
|
||
const { isAllSelected } = event?.detail ?? {};
|
||
Toast({
|
||
context: this,
|
||
selector: '#t-toast',
|
||
message: `${isAllSelected ? '取消' : '点击'}了全选按钮`,
|
||
});
|
||
|
||
// 调用接口改变全选
|
||
selectAllCartItems(!isAllSelected).then(() => {
|
||
this.refreshData();
|
||
}).catch(err => {
|
||
console.error('全选操作失败:', err);
|
||
Toast({
|
||
context: this,
|
||
selector: '#t-toast',
|
||
message: '操作失败,请重试',
|
||
});
|
||
});
|
||
},
|
||
|
||
onToSettle() {
|
||
const goodsRequestList = [];
|
||
let totalAmount = 0;
|
||
let selectedCount = 0;
|
||
|
||
// 添加数据验证,确保数据结构存在
|
||
if (this.data.cartGroupData && Array.isArray(this.data.cartGroupData.storeGoods)) {
|
||
this.data.cartGroupData.storeGoods.forEach((store) => {
|
||
if (Array.isArray(store.promotionGoodsList)) {
|
||
store.promotionGoodsList.forEach((promotion) => {
|
||
if (Array.isArray(promotion.goodsPromotionList)) {
|
||
promotion.goodsPromotionList.forEach((m) => {
|
||
if (m.isSelected == 1) {
|
||
// 检查库存
|
||
if (m.quantity > m.stockQuantity) {
|
||
Toast({
|
||
context: this,
|
||
selector: '#t-toast',
|
||
message: `${m.title}库存不足,请调整数量`,
|
||
});
|
||
return;
|
||
}
|
||
|
||
goodsRequestList.push({
|
||
...m,
|
||
// 确保价格格式正确
|
||
price: parseInt(m.price) || 0,
|
||
originPrice: parseInt(m.originPrice) || parseInt(m.price) || 0,
|
||
});
|
||
selectedCount += m.quantity;
|
||
totalAmount += (parseInt(m.price) || 0) * m.quantity;
|
||
}
|
||
});
|
||
}
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
// 验证是否有选中的商品
|
||
if (goodsRequestList.length === 0) {
|
||
Toast({
|
||
context: this,
|
||
selector: '#t-toast',
|
||
message: '请选择要结算的商品',
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 验证用户是否登录
|
||
const token = wx.getStorageSync('token');
|
||
if (!token) {
|
||
Dialog.confirm({
|
||
title: '提示',
|
||
content: '请先登录后再进行结算',
|
||
confirmBtn: '去登录',
|
||
cancelBtn: '取消',
|
||
}).then(() => {
|
||
wx.navigateTo({ url: '/pages/login/index' });
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 保存结算数据到本地存储
|
||
const orderData = {
|
||
goodsRequestList,
|
||
totalAmount,
|
||
selectedCount,
|
||
timestamp: Date.now()
|
||
};
|
||
|
||
try {
|
||
wx.setStorageSync('order.goodsRequestList', JSON.stringify(goodsRequestList));
|
||
wx.setStorageSync('order.settlementData', JSON.stringify(orderData));
|
||
|
||
// 跳转到订单确认页面
|
||
wx.navigateTo({
|
||
url: '/pages/order/order-confirm/index?type=cart',
|
||
success: () => {
|
||
console.log('跳转到订单确认页面成功');
|
||
},
|
||
fail: (err) => {
|
||
console.error('跳转失败:', err);
|
||
Toast({
|
||
context: this,
|
||
selector: '#t-toast',
|
||
message: '跳转失败,请重试',
|
||
});
|
||
}
|
||
});
|
||
} catch (error) {
|
||
console.error('保存订单数据失败:', error);
|
||
Toast({
|
||
context: this,
|
||
selector: '#t-toast',
|
||
message: '数据保存失败,请重试',
|
||
});
|
||
}
|
||
},
|
||
onGotoHome() {
|
||
wx.switchTab({ url: '/pages/home/home' });
|
||
},
|
||
|
||
// 下拉刷新相关方法
|
||
onRefresh() {
|
||
console.log('开始下拉刷新');
|
||
this.setData({
|
||
refresherTriggered: true,
|
||
});
|
||
|
||
// 重新获取购物车数据
|
||
this.refreshData();
|
||
|
||
// 模拟网络请求延迟,确保用户能看到刷新动画
|
||
setTimeout(() => {
|
||
this.setData({
|
||
refresherTriggered: false,
|
||
});
|
||
|
||
// 显示刷新成功提示
|
||
Toast({
|
||
context: this,
|
||
selector: '#t-toast',
|
||
message: '刷新成功',
|
||
theme: 'success',
|
||
duration: 1500,
|
||
});
|
||
}, 1000);
|
||
},
|
||
|
||
onRefresherPulling(e) {
|
||
console.log('下拉中', e.detail);
|
||
},
|
||
|
||
onRefresherRestore(e) {
|
||
console.log('刷新恢复', e.detail);
|
||
},
|
||
|
||
onRefresherAbort(e) {
|
||
console.log('刷新中止', e.detail);
|
||
this.setData({
|
||
refresherTriggered: false,
|
||
});
|
||
},
|
||
|
||
// 分享功能
|
||
onShareAppMessage() {
|
||
return {
|
||
title: '购物车 - 查看我的心仪好物',
|
||
path: '/pages/cart/index'
|
||
};
|
||
},
|
||
|
||
// 分享到朋友圈
|
||
onShareTimeline() {
|
||
return {
|
||
title: '购物车 - 查看我的心仪好物'
|
||
};
|
||
}
|
||
});
|