Compare commits

...

2 Commits

Author SHA1 Message Date
左哥
30d3241536 sdwer 2025-11-24 22:03:57 +08:00
左哥
84c228f5e6 sdwer 2025-11-24 22:03:19 +08:00
7 changed files with 518 additions and 76 deletions

View File

@ -84,6 +84,12 @@
"style": { "style": {
"navigationBarTitleText": "积分流水" "navigationBarTitleText": "积分流水"
} }
},
{
"path": "pages/inviteUsers/index",
"style": {
"navigationBarTitleText": "我邀请的用户"
}
} }
], ],
"globalStyle": { "globalStyle": {

293
pages/inviteUsers/index.vue Normal file
View File

@ -0,0 +1,293 @@
<template>
<view class="invite-page">
<view class="summary-card">
<view class="summary-item">
<text class="summary-value">{{ total }}</text>
<text class="summary-label">已邀请用户</text>
</view>
<view class="summary-divider"></view>
<view class="summary-item">
<text class="summary-value">{{ totalPoints }}</text>
<text class="summary-label">累计积分</text>
</view>
</view>
<scroll-view
class="invite-scroll"
scroll-y
@scrolltolower="loadMore"
:refresher-enabled="true"
:refresher-triggered="refreshing"
@refresherrefresh="refresh"
>
<view class="invite-list">
<view
class="invite-item"
v-for="user in inviteList"
:key="`${user.username}-${user.created_at}`"
>
<image class="avatar" :src="user.avatar_url || defaultAvatar" mode="aspectFill" />
<view class="invite-info">
<view class="invite-header">
<text class="invite-name">
{{ user.username || '未命名用户' }}
</text>
<text class="sex-tag" :class="getSexClass(user.sex)">
{{ getSexText(user.sex) }}
</text>
</view>
<text class="invite-time">邀请时间{{ formatDate(user.created_at) }}</text>
</view>
</view>
<view v-if="!loading && inviteList.length === 0" class="empty-state">
<text class="empty-icon">🤝</text>
<text class="empty-text">暂时还没有邀请记录</text>
</view>
<view v-if="loading && inviteList.length > 0" class="loading-more">
<text class="loading-text">加载中...</text>
</view>
<view v-if="!hasMore && inviteList.length > 0" class="no-more">
<text class="no-more-text">没有更多了</text>
</view>
</view>
</scroll-view>
</view>
</template>
<script>
import request from '@/api/request.js';
const INVITE_API_PATH = 'xcx/invite_users';
export default {
data() {
return {
inviteList: [],
page: 1,
pageSize: 10,
loading: false,
refreshing: false,
hasMore: true,
total: 0,
totalPoints: 0,
defaultAvatar: '/static/images/home/icon-1.png'
};
},
onLoad() {
this.loadInvitedUsers();
},
methods: {
formatDate(value) {
if (!value) return '--';
const date = new Date(value);
if (Number.isNaN(date.getTime())) return value;
const year = date.getFullYear();
const month = `${date.getMonth() + 1}`.padStart(2, '0');
const day = `${date.getDate()}`.padStart(2, '0');
const hour = `${date.getHours()}`.padStart(2, '0');
const minute = `${date.getMinutes()}`.padStart(2, '0');
return `${year}-${month}-${day} ${hour}:${minute}`;
},
getSexText(sex) {
const map = {
1: '男',
2: '女',
0: '保密'
};
return map.hasOwnProperty(sex) ? map[sex] : '保密';
},
getSexClass(sex) {
if (sex === 1) return 'tag-male';
if (sex === 2) return 'tag-female';
return 'tag-unknown';
},
async loadInvitedUsers() {
if (this.loading || !this.hasMore) return;
this.loading = true;
try {
const params = {
page: this.page,
page_size: this.pageSize
};
const response = await request(INVITE_API_PATH, 'GET', params);
const list = Array.isArray(response)
? response
: response?.list || response?.data || [];
this.total = response?.total ?? this.total ?? 0;
this.totalPoints = response?.total_points ?? response?.totalPoints ?? this.totalPoints;
if (this.page === 1) {
this.inviteList = list;
} else {
this.inviteList = [...this.inviteList, ...list];
}
const received = list.length;
if (received < this.pageSize) {
this.hasMore = false;
} else {
this.page += 1;
}
} catch (error) {
console.error('加载邀请列表失败', error);
if (this.page === 1) {
this.inviteList = [];
}
} finally {
this.loading = false;
this.refreshing = false;
}
},
refresh() {
this.refreshing = true;
this.page = 1;
this.hasMore = true;
this.inviteList = [];
this.loadInvitedUsers();
},
loadMore() {
if (!this.loading && this.hasMore) {
this.loadInvitedUsers();
}
}
}
};
</script>
<style scoped lang="scss">
.invite-page {
min-height: 100vh;
background-color: #f5f5f5;
padding: 24rpx;
display: flex;
flex-direction: column;
gap: 24rpx;
}
.summary-card {
background: linear-gradient(120deg, #f6f1ff 0%, #ffeef5 100%);
border-radius: 32rpx;
padding: 32rpx;
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0 16rpx 32rpx rgba(139, 64, 255, 0.12);
}
.summary-item {
display: flex;
flex-direction: column;
gap: 8rpx;
text-align: center;
flex: 1;
}
.summary-value {
font-size: 44rpx;
font-weight: 700;
color: #33195d;
}
.summary-label {
font-size: 26rpx;
color: #7b43ff;
}
.summary-divider {
width: 2rpx;
height: 80rpx;
background-color: rgba(255, 255, 255, 0.4);
}
.invite-scroll {
flex: 1;
height: calc(100vh - 240rpx);
}
.invite-list {
display: flex;
flex-direction: column;
gap: 16rpx;
}
.invite-item {
background-color: #fff;
border-radius: 24rpx;
padding: 24rpx;
display: flex;
align-items: center;
gap: 24rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
}
.avatar {
width: 96rpx;
height: 96rpx;
border-radius: 50%;
background-color: #f3f3f3;
}
.invite-info {
flex: 1;
display: flex;
flex-direction: column;
gap: 12rpx;
}
.invite-header {
display: flex;
align-items: center;
gap: 16rpx;
}
.invite-name {
font-size: 32rpx;
font-weight: 600;
color: #333;
}
.sex-tag {
font-size: 24rpx;
padding: 6rpx 20rpx;
border-radius: 999rpx;
}
.tag-male {
background-color: #e3f2fd;
color: #1a73e8;
}
.tag-female {
background-color: #fde2ef;
color: #d81b60;
}
.tag-unknown {
background-color: #f1f3f4;
color: #5f6368;
}
.invite-time {
font-size: 26rpx;
color: #999;
}
.empty-state,
.loading-more,
.no-more {
text-align: center;
padding: 80rpx 0;
display: flex;
flex-direction: column;
gap: 16rpx;
color: #999;
}
.empty-icon {
font-size: 80rpx;
}
</style>

View File

@ -55,13 +55,13 @@ export default {
throw new Error('获取微信登录code失败'); throw new Error('获取微信登录code失败');
} }
const open_id = (await request('xcx/basic_login', 'post', {code: loginRes.code})).openid const open_id = (await request('xcx/basic_login', 'post', { code: loginRes.code })).openid
// code // code
const loginData = { const loginData = {
code: e.detail.code, code: e.detail.code,
invitation_code: '', invitation_code: '',
openid: open_id openid: open_id
// iv: e.detail.iv // iv: e.detail.iv
}; };
@ -69,7 +69,7 @@ export default {
await wx.setStorageSync('access_token', result.token); await wx.setStorageSync('access_token', result.token);
await wx.setStorageSync('is_personal_information_complete', result.is_personal_information_complete); await wx.setStorageSync('is_personal_information_complete', result.is_personal_information_complete);
// if (result.is_personal_information_complete) { // if (result.is_personal_information_complete) {
wx.navigateBack(); wx.navigateBack();
// } else { // } else {
// wx.navigateTo({ // wx.navigateTo({
// url: `/pages/my/editInfo/index`, // url: `/pages/my/editInfo/index`,

View File

@ -262,6 +262,7 @@ export default {
quickActions: [ quickActions: [
{ icon: '💳', label: '我的钱包' }, { icon: '💳', label: '我的钱包' },
{ icon: '📍', label: '地址管理', path: '/pages/address/index' }, { icon: '📍', label: '地址管理', path: '/pages/address/index' },
{ icon: '🤝', label: '邀请用户', path: '/pages/inviteUsers/index' },
{ icon: '🔔', label: '消息通知' }, { icon: '🔔', label: '消息通知' },
{ icon: '❓', label: '帮助中心' } { icon: '❓', label: '帮助中心' }
], ],
@ -701,6 +702,9 @@ export default {
if (item.label === '当前积分') { if (item.label === '当前积分') {
this.navigateTo('/pages/pointsLog/index'); this.navigateTo('/pages/pointsLog/index');
} }
if (item.label === '总订单数') {
this.navigateTo('/pages/order/index');
}
}, },
toEditInfoPage() { toEditInfoPage() {
uni.navigateTo({ uni.navigateTo({

View File

@ -44,7 +44,7 @@
<text class="picker-address">{{ formatAddress(item) }}</text> <text class="picker-address">{{ formatAddress(item) }}</text>
</view> </view>
<view class="picker-item-check" v-if="selectedAddress && selectedAddress.id === item.id"> <view class="picker-item-check" v-if="selectedAddress && selectedAddress.id === item.id">
<text class="iconfont icon-gou"></text> <text class="iconfont icon-gou"></text>
</view> </view>
</view> </view>
<view v-if="addressList.length === 0" class="picker-empty"> <view v-if="addressList.length === 0" class="picker-empty">
@ -266,29 +266,29 @@ export default {
this.submitting = true; this.submitting = true;
// appid // appid
if (!this.app_id) { // if (!this.app_id) {
const accountInfo = wx.getAccountInfoSync && wx.getAccountInfoSync(); // const accountInfo = wx.getAccountInfoSync && wx.getAccountInfoSync();
this.app_id = accountInfo && accountInfo.miniProgram && accountInfo.miniProgram.appId // this.app_id = accountInfo && accountInfo.miniProgram && accountInfo.miniProgram.appId
? accountInfo.miniProgram.appId // ? accountInfo.miniProgram.appId
: ''; // : '';
} // }
try { try {
// //
const orderData = { const orderData = {
app_id: this.app_id, // app_id: this.app_id,
address_id: this.selectedAddress.id, address_id: this.selectedAddress.id,
items: this.orderItems.map(item => ({ // items: this.orderItems.map(item => ({
cart_id: item.cart_id, // cart_id: item.cart_id,
product_id: item.product_id, // product_id: item.product_id,
sku_id: item.sku_id, // sku_id: item.sku_id,
quantity: item.quantity, // quantity: item.quantity,
price: item.price // price: item.price
})), // })),
remark: this.orderRemark, // remark: this.orderRemark,
total_price: this.totalPrice, // total_price: this.totalPrice,
shipping_fee: this.shippingFee, // shipping_fee: this.shippingFee,
discount_amount: this.discountAmount, // discount_amount: this.discountAmount,
final_price: this.finalPrice // final_price: this.finalPrice
}; };
// //
@ -299,14 +299,26 @@ export default {
icon: 'success', icon: 'success',
duration: 2000 duration: 2000
}); });
//
wx.requestPayment({
timeStamp: result.timeStamp,
nonceStr: result.nonceStr,
package: result.package,
signType: result.signType,
paySign: result.paySign,
success: () => {
console.log('支付成功');
//
setTimeout(() => {
//
uni.redirectTo({
url: `/pages/order/detail?id=${result.order_id || result.id}`
});
}, 2000);
}
});
//
setTimeout(() => {
//
uni.redirectTo({
url: `/pages/order/detail?id=${result.order_id || result.id}`
});
}, 2000);
} catch (error) { } catch (error) {
console.error('提交订单失败:', error); console.error('提交订单失败:', error);

View File

@ -26,14 +26,14 @@
<view <view
class="order-item" class="order-item"
v-for="order in orderList" v-for="order in orderList"
:key="order.id || order.order_no" :key="order.order_id"
@click="goToDetail(order)" @click="goToDetail(order)"
> >
<!-- 订单头部 --> <!-- 订单头部 -->
<view class="order-header"> <view class="order-header">
<view class="order-info"> <view class="order-info">
<text class="order-no">订单号{{ order.order_no || order.no }}</text> <text class="order-no">订单号{{ order.order_id }}</text>
<text class="order-date">{{ formatDate(order.created_at || order.date) }}</text> <text class="order-date">{{ formatDate(order.created_at || order.createdAt || order.date) }}</text>
</view> </view>
<view class="order-status-tag" :class="getStatusClass(order.status)"> <view class="order-status-tag" :class="getStatusClass(order.status)">
{{ getStatusText(order.status) }} {{ getStatusText(order.status) }}
@ -44,12 +44,12 @@
<view class="order-goods"> <view class="order-goods">
<view <view
class="goods-item" class="goods-item"
v-for="(item, index) in order.items || [order]" v-for="(item, index) in (order.items || order.product_list || [order])"
:key="index" :key="index"
> >
<view class="goods-image"> <view class="goods-image">
<image <image
:src="item.product_image || item.main_image_url || item.image" :src="item.product_image || item.main_image_url || item.product_main_image_url || item.image"
mode="aspectFill" mode="aspectFill"
@error="handleImageError" @error="handleImageError"
></image> ></image>
@ -62,7 +62,7 @@
<view class="goods-price-row"> <view class="goods-price-row">
<view class="goods-price"> <view class="goods-price">
<text class="price-symbol"></text> <text class="price-symbol"></text>
<text class="price-value">{{ formatPrice(item.price || order.price) }}</text> <text class="price-value">{{ formatPrice(item.price || order.price || item.sku_price) }}</text>
</view> </view>
<view class="goods-quantity">x{{ item.quantity || order.quantity || 1 }}</view> <view class="goods-quantity">x{{ item.quantity || order.quantity || 1 }}</view>
</view> </view>
@ -74,7 +74,7 @@
<view class="order-footer"> <view class="order-footer">
<view class="order-total"> <view class="order-total">
<text class="total-label">{{ getTotalQuantity(order) }}件商品 合计</text> <text class="total-label">{{ getTotalQuantity(order) }}件商品 合计</text>
<text class="total-price">{{ formatPrice(order.final_price || order.total_price || order.amount) }}</text> <text class="total-price">{{ formatPrice(order.final_price || order.payable_amount || order.total_price || order.amount || order.total_amount) }}</text>
</view> </view>
<view class="order-actions"> <view class="order-actions">
<view <view
@ -119,23 +119,36 @@ export default {
currentStatus: 'all', // currentStatus: 'all', //
statusTabs: [ statusTabs: [
{ label: '全部', value: 'all' }, { label: '全部', value: 'all' },
{ label: '待付款', value: 'pending' }, { label: '待支付', value: 1 },
{ label: '待发货', value: 'paid' }, // { label: '', value: 2 },
{ label: '待收货', value: 'shipped' }, { label: '待发货', value: 3 },
{ label: '已完成', value: 'completed' } { label: '待收货', value: 4 },
{ label: '已完成', value: 5 },
// { label: '', value: 6 },
// { label: '退', value: 7 }
], ],
orderList: [], orderList: [],
loading: false, loading: false,
refreshing: false, refreshing: false,
page: 1, page: 1,
pageSize: 10, pageSize: 10,
hasMore: true hasMore: true,
statusConfig: {
1: { label: '待支付', class: 'pending' },
2: { label: '支付失败', class: 'cancelled' },
3: { label: '待发货', class: 'warning' },
4: { label: '待收货', class: 'warning' },
5: { label: '已完成', class: 'success' },
6: { label: '已取消', class: 'cancelled' },
7: { label: '已退款', class: 'cancelled' }
}
}; };
}, },
onLoad(options) { onLoad(options) {
// //
if (options.status) { if (options.status) {
this.currentStatus = options.status; const statusValue = Number(options.status);
this.currentStatus = Number.isNaN(statusValue) ? options.status : statusValue;
} }
this.loadOrderList(); this.loadOrderList();
}, },
@ -168,9 +181,33 @@ export default {
return `${year}-${month}-${day}`; return `${year}-${month}-${day}`;
}, },
//
normalizeStatus(status) {
if (status === null || status === undefined) return null;
const numericStatus = Number(status);
if (!Number.isNaN(numericStatus)) {
return numericStatus;
}
const legacyMap = {
'pending': 1,
'paid': 3,
'shipped': 4,
'completed': 5,
'cancelled': 6,
'refunded': 7,
'failed': 2,
'pay_failed': 2
};
return legacyMap[status] !== undefined ? legacyMap[status] : status;
},
// //
getStatusText(status) { getStatusText(status) {
const statusMap = { const normalized = this.normalizeStatus(status);
if (typeof normalized === 'number' && this.statusConfig[normalized]) {
return this.statusConfig[normalized].label;
}
const legacyTextMap = {
'pending': '待付款', 'pending': '待付款',
'paid': '待发货', 'paid': '待发货',
'shipped': '待收货', 'shipped': '待收货',
@ -178,11 +215,15 @@ export default {
'cancelled': '已取消', 'cancelled': '已取消',
'refunded': '已退款' 'refunded': '已退款'
}; };
return statusMap[status] || status || '未知'; return legacyTextMap[normalized] || legacyTextMap[status] || status || '未知';
}, },
// //
getStatusClass(status) { getStatusClass(status) {
const normalized = this.normalizeStatus(status);
if (typeof normalized === 'number' && this.statusConfig[normalized]) {
return this.statusConfig[normalized].class;
}
const classMap = { const classMap = {
'pending': 'pending', 'pending': 'pending',
'paid': 'warning', 'paid': 'warning',
@ -191,14 +232,41 @@ export default {
'cancelled': 'cancelled', 'cancelled': 'cancelled',
'refunded': 'cancelled' 'refunded': 'cancelled'
}; };
return classMap[status] || ''; return classMap[normalized] || classMap[status] || '';
}, },
// //
getOrderActions(order) { getOrderActions(order) {
const status = order.status; const status = order.status;
const actions = []; const actions = [];
const normalized = this.normalizeStatus(status);
if (typeof normalized === 'number') {
switch (normalized) {
case 1: //
case 2: //
actions.push({ label: '取消订单', action: 'cancel', class: 'cancel-btn' });
actions.push({ label: '立即付款', action: 'pay', class: 'primary-btn' });
break;
case 3: //
actions.push({ label: '查看详情', action: 'detail', class: 'default-btn' });
break;
case 4: //
actions.push({ label: '查看物流', action: 'logistics', class: 'default-btn' });
actions.push({ label: '确认收货', action: 'confirm', class: 'primary-btn' });
break;
case 5: //
actions.push({ label: '查看详情', action: 'detail', class: 'default-btn' });
actions.push({ label: '再次购买', action: 'rebuy', class: 'primary-btn' });
break;
default:
actions.push({ label: '查看详情', action: 'detail', class: 'default-btn' });
break;
}
return actions;
}
//
if (status === 'pending') { if (status === 'pending') {
actions.push({ label: '取消订单', action: 'cancel', class: 'cancel-btn' }); actions.push({ label: '取消订单', action: 'cancel', class: 'cancel-btn' });
actions.push({ label: '立即付款', action: 'pay', class: 'primary-btn' }); actions.push({ label: '立即付款', action: 'pay', class: 'primary-btn' });
@ -219,8 +287,9 @@ export default {
// //
getTotalQuantity(order) { getTotalQuantity(order) {
if (order.items && Array.isArray(order.items)) { const items = order.items || order.product_list;
return order.items.reduce((sum, item) => sum + (parseInt(item.quantity) || 1), 0); if (items && Array.isArray(items)) {
return items.reduce((sum, item) => sum + (parseInt(item.quantity) || 1), 0);
} }
return parseInt(order.quantity) || 1; return parseInt(order.quantity) || 1;
}, },

View File

@ -42,7 +42,7 @@
<view class="product-price"> <view class="product-price">
<text class="current-price">¥{{ formatPrice(currentPrice) }}</text> <text class="current-price">¥{{ formatPrice(currentPrice) }}</text>
<text class="original-price" v-if="originalPrice > currentPrice">¥{{ formatPrice(originalPrice) <text class="original-price" v-if="originalPrice > currentPrice">¥{{ formatPrice(originalPrice)
}}</text> }}</text>
</view> </view>
<view class="sku-hint" v-if="skuList.length > 1 && !selectedSku"> <view class="sku-hint" v-if="skuList.length > 1 && !selectedSku">
请选择规格 请选择规格
@ -143,17 +143,17 @@
<view class="note-item"> <view class="note-item">
<text class="note-label">前调</text> <text class="note-label">前调</text>
<text class="note-content">{{ productInfo.scent_level.top_note || '柠檬、佛手柑、粉红胡椒' <text class="note-content">{{ productInfo.scent_level.top_note || '柠檬、佛手柑、粉红胡椒'
}}</text> }}</text>
</view> </view>
<view class="note-item"> <view class="note-item">
<text class="note-label">中调</text> <text class="note-label">中调</text>
<text class="note-content">{{ productInfo.scent_level.middle_note || '玫瑰、茉莉、牡丹' <text class="note-content">{{ productInfo.scent_level.middle_note || '玫瑰、茉莉、牡丹'
}}</text> }}</text>
</view> </view>
<view class="note-item"> <view class="note-item">
<text class="note-label">后调</text> <text class="note-label">后调</text>
<text class="note-content">{{ productInfo.scent_level.base_note || '白麝香、雪松、香草' <text class="note-content">{{ productInfo.scent_level.base_note || '白麝香、雪松、香草'
}}</text> }}</text>
</view> </view>
</view> </view>
</view> </view>
@ -254,9 +254,10 @@
<view class="bar-btn" @click="goToCart"> <view class="bar-btn" @click="goToCart">
<text class="iconfont icon-gouwuche"></text> <text class="iconfont icon-gouwuche"></text>
<text>购物车</text> <text>购物车</text>
<view v-if="cartSelectedCount > 0" class="cart-count">{{ cartSelectedCount }}</view>
</view> </view>
<view class="bar-btn cart-btn" @click="addToCart">加入购物车</view> <view class="bar-btn cart-btn" @click="addToCart">加入购物车</view>
<view class="bar-btn primary" @click="buyNow">立即购买</view> <!-- <view class="bar-btn primary" @click="buyNow">立即购买</view> -->
</view> </view>
</view> </view>
</template> </template>
@ -307,6 +308,7 @@ export default {
activeTab: 'detail', activeTab: 'detail',
showPurchaseModal: false, showPurchaseModal: false,
purchaseAction: 'cart', // 'cart' 'buy' purchaseAction: 'cart', // 'cart' 'buy'
cartSelectedCount: 0,
fragranceNotes: { fragranceNotes: {
top: '柠檬、佛手柑、粉红胡椒', top: '柠檬、佛手柑、粉红胡椒',
middle: '玫瑰、茉莉、牡丹', middle: '玫瑰、茉莉、牡丹',
@ -357,6 +359,10 @@ export default {
onLoad(options) { onLoad(options) {
// this.productInfo = uni.getStorageSync('product_info'); // this.productInfo = uni.getStorageSync('product_info');
this.loadProductDetail(uni.getStorageSync('product_info')); this.loadProductDetail(uni.getStorageSync('product_info'));
this.fetchCartSelectedCount();
},
onShow() {
this.fetchCartSelectedCount();
}, },
methods: { methods: {
@ -483,33 +489,53 @@ export default {
switchTab(tab) { switchTab(tab) {
this.activeTab = tab; this.activeTab = tab;
}, },
async userIsLogin() {
// - const token = await uni.getStorageSync('access_token')
addToCart() { if (token) {
this.purchaseAction = 'cart'; return
// SKU } else {
if (!this.selectedSku && this.skuList.length > 0) { uni.navigateTo({
const availableSku = this.skuList.find(sku => sku && (sku.quantity > 0 || sku.quantity === undefined)) || this.skuList[0]; url: '/pages/login/index'
if (availableSku) { })
const skuIndex = this.skuList.indexOf(availableSku);
this.selectSku(availableSku, skuIndex >= 0 ? skuIndex : 0);
}
} }
this.showPurchaseModal = true; },
// -
async addToCart() {
await this.userIsLogin().then(async (res) => {
this.purchaseAction = 'cart';
// SKU
if (!this.selectedSku && this.skuList.length > 0) {
const availableSku = this.skuList.find(sku => sku && (sku.quantity > 0 || sku.quantity === undefined)) || this.skuList[0];
if (availableSku) {
const skuIndex = this.skuList.indexOf(availableSku);
this.selectSku(availableSku, skuIndex >= 0 ? skuIndex : 0);
}
}
this.showPurchaseModal = true;
}).catch((err) => {
console.log(err);
});
}, },
// - // -
buyNow() { async buyNow() {
this.purchaseAction = 'buy'; await this.userIsLogin().then((res) => {
// SKU this.purchaseAction = 'buy';
if (!this.selectedSku && this.skuList.length > 0) { // SKU
const availableSku = this.skuList.find(sku => sku && (sku.quantity > 0 || sku.quantity === undefined)) || this.skuList[0]; if (!this.selectedSku && this.skuList.length > 0) {
if (availableSku) { const availableSku = this.skuList.find(sku => sku && (sku.quantity > 0 || sku.quantity === undefined)) || this.skuList[0];
const skuIndex = this.skuList.indexOf(availableSku); if (availableSku) {
this.selectSku(availableSku, skuIndex >= 0 ? skuIndex : 0); const skuIndex = this.skuList.indexOf(availableSku);
this.selectSku(availableSku, skuIndex >= 0 ? skuIndex : 0);
}
} }
} this.showPurchaseModal = true;
this.showPurchaseModal = true; }).catch((err) => {
console.log(err);
});
}, },
// //
@ -540,6 +566,7 @@ export default {
title: '已添加到购物车', title: '已添加到购物车',
icon: 'success' icon: 'success'
}); });
this.fetchCartSelectedCount();
} catch (error) { } catch (error) {
console.error('添加到购物车失败:', error); console.error('添加到购物车失败:', error);
uni.showToast({ uni.showToast({
@ -574,6 +601,20 @@ export default {
uni.navigateTo({ uni.navigateTo({
url: '/pages/shoppingCart/index' url: '/pages/shoppingCart/index'
}); });
},
async fetchCartSelectedCount() {
try {
const res = await request('xcx/carts', 'GET', { page: 1, page_size: 99 });
const list = res.list || res.data || res || [];
this.cartSelectedCount = list
.filter(item => item && item.selected === 1)
.reduce((sum, item) => {
const quantity = parseInt(item.quantity || item.count || 0, 10);
return sum + (isNaN(quantity) ? 0 : quantity);
}, 0);
} catch (error) {
console.error('获取购物车数量失败:', error);
}
} }
} }
}; };
@ -1223,6 +1264,7 @@ export default {
color: #666; color: #666;
padding: 12rpx 0; padding: 12rpx 0;
box-sizing: border-box; box-sizing: border-box;
position: relative;
} }
.bar-btn .iconfont { .bar-btn .iconfont {
@ -1254,4 +1296,20 @@ export default {
height: 72rpx; height: 72rpx;
line-height: 72rpx; line-height: 72rpx;
} }
.cart-count {
position: absolute;
top: 6rpx;
right: 36rpx;
min-width: 32rpx;
padding: 0 8rpx;
height: 32rpx;
border-radius: 16rpx;
background-color: #ff4d4f;
color: #fff;
font-size: 20rpx;
line-height: 32rpx;
text-align: center;
box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.15);
}
</style> </style>