Compare commits
2 Commits
1258138ba9
...
30d3241536
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30d3241536 | ||
|
|
84c228f5e6 |
@ -84,6 +84,12 @@
|
|||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "积分流水"
|
"navigationBarTitleText": "积分流水"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/inviteUsers/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "我邀请的用户"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"globalStyle": {
|
"globalStyle": {
|
||||||
|
|||||||
293
pages/inviteUsers/index.vue
Normal file
293
pages/inviteUsers/index.vue
Normal 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>
|
||||||
|
|
||||||
@ -54,14 +54,14 @@ export default {
|
|||||||
if (!loginRes.code) {
|
if (!loginRes.code) {
|
||||||
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`,
|
||||||
|
|||||||
@ -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({
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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;
|
||||||
},
|
},
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user