- 修改 ArticleController.java - 更新 application.yml 配置 - 更新 frontend/.env.production 环境配置 - 添加 single_uniapp22miao 小程序模块 - 添加 logs 目录
1014 lines
25 KiB
Vue
1014 lines
25 KiB
Vue
<template>
|
||
<view class="orders-page">
|
||
<!-- 橙色头部 -->
|
||
<view class="header-section">
|
||
<view class="header-content">
|
||
<view class="header-icon" @click="goBack">
|
||
<text class="iconfont icon-fanhui"></text>
|
||
</view>
|
||
<text class="header-title">我的订单</text>
|
||
<text class="header-menu"></text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 状态标签栏 -->
|
||
<view class="stats-bar">
|
||
<view
|
||
v-for="(tab, index) in tabs"
|
||
:key="index"
|
||
class="stat-item"
|
||
:class="{ 'active': currentTab === index }"
|
||
@click="switchTab(index)"
|
||
>
|
||
<view class="stat-number-wrapper">
|
||
<text class="stat-number" :class="{ 'active': currentTab === index }">{{ tab.count || 0 }}</text>
|
||
<view v-if="currentTab === index" class="stat-underline"></view>
|
||
</view>
|
||
<text class="stat-text" :class="{ 'active': currentTab === index }">{{ tab.name }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 订单列表 -->
|
||
<scroll-view
|
||
class="orders-list"
|
||
scroll-y
|
||
@scrolltolower="loadMore"
|
||
:refresher-enabled="true"
|
||
:refresher-triggered="refreshing"
|
||
@refresherrefresh="onRefresh"
|
||
>
|
||
<view v-if="orderList.length > 0" class="list-container">
|
||
<view
|
||
v-for="(order, index) in orderList"
|
||
:key="order.id"
|
||
class="order-item"
|
||
@click="goToDetail(order.orderId)"
|
||
>
|
||
<!-- 订单头部:日期和状态 -->
|
||
<view class="order-header">
|
||
<text class="order-time">{{ order.createTime }}</text>
|
||
<text class="order-status" :style="{ color: getStatusColor(order.status, order.paid) }">
|
||
{{ order.status_text }}
|
||
</text>
|
||
</view>
|
||
|
||
<!-- 商品信息列表 -->
|
||
<view class="order-content">
|
||
<view
|
||
v-for="(goods, gIndex) in order.orderInfoList"
|
||
:key="gIndex"
|
||
class="goods-row"
|
||
>
|
||
<image v-if="goods.image" class="goods-image" :src="goods.image" mode="aspectFill"></image>
|
||
<view class="goods-info">
|
||
<text class="goods-name">{{ goods.storeName || goods.productName }}</text>
|
||
<view class="goods-price-row">
|
||
<text class="goods-points">{{ formatPoints(goods.integral || goods.vipPrice || goods.price) }}积分</text>
|
||
<text class="goods-quantity">x{{ goods.cartNum }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 订单汇总 -->
|
||
<view class="order-summary">
|
||
<text class="summary-text">共{{ order.quantity }}件商品,总金额</text>
|
||
<text class="summary-points">{{ formatPoints(order.points) }}积分</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 空状态 -->
|
||
<view v-else-if="!loading && isShow" class="empty-state">
|
||
<image class="empty-image" src="/static/images/empty.png" mode="aspectFit"></image>
|
||
<text class="empty-text">暂无订单</text>
|
||
<button class="empty-btn" @click="goToShop">去逛逛</button>
|
||
</view>
|
||
|
||
<!-- 加载更多 -->
|
||
<view v-if="orderList.length > 0" class="load-more">
|
||
<text v-if="loading" class="load-text">加载中...</text>
|
||
<text v-else-if="noMore" class="load-text">我也是有底线的</text>
|
||
</view>
|
||
</scroll-view>
|
||
|
||
<!-- 底部导航栏 -->
|
||
<view class="bottom-tabbar safe-area-inset-bottom">
|
||
<view class="tab-item" @click="goToShop">
|
||
<image class="tab-icon" src="/static/tabBar/home.png" mode="aspectFit"></image>
|
||
<text class="tab-text">积分兑换</text>
|
||
</view>
|
||
<view class="tab-item" @click="goToCart">
|
||
<view class="tab-icon-wrap">
|
||
<image class="tab-icon" src="/static/tabBar/cart.png" mode="aspectFit"></image>
|
||
<view class="cart-badge" v-if="cartCount > 0">
|
||
<text>{{ cartCount > 99 ? '99+' : cartCount }}</text>
|
||
</view>
|
||
</view>
|
||
<text class="tab-text">购物车</text>
|
||
</view>
|
||
<view class="tab-item active">
|
||
<image class="tab-icon" src="/static/tabBar/order-active.png" mode="aspectFit"></image>
|
||
<text class="tab-text active">订单</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import { getOrderList, orderData, orderCancel, orderTake, orderDel, getCartCounts } from '@/api/order.js';
|
||
import { mapGetters } from 'vuex';
|
||
import { toLogin } from '@/libs/login.js';
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
// 状态标签: type对应后端参数
|
||
// -99-全部 0-待兑换(待付款) 1-待发货 2-待收货 3-已完成
|
||
tabs: [
|
||
{ name: '全部', type: -99, count: 0 },
|
||
{ name: '待兑换', type: 0, count: 0 },
|
||
{ name: '待发货', type: 1, count: 0 },
|
||
{ name: '待收货', type: 2, count: 0 },
|
||
{ name: '已完成', type: 4, count: 0 }
|
||
],
|
||
currentTab: 0, // 默认显示"全部"
|
||
orderList: [],
|
||
orderData: {}, // 订单统计数据
|
||
cartCount: 0, // 购物车数量
|
||
page: 1,
|
||
limit: 10,
|
||
loading: false,
|
||
refreshing: false,
|
||
noMore: false,
|
||
isShow: false
|
||
}
|
||
},
|
||
|
||
computed: {
|
||
...mapGetters(['isLogin'])
|
||
},
|
||
|
||
onLoad(options) {
|
||
if (options.status !== undefined) {
|
||
const status = parseInt(options.status);
|
||
// 根据状态找到对应的标签索引
|
||
const tabIndex = this.tabs.findIndex(tab => tab.type === status);
|
||
if (tabIndex >= 0) {
|
||
this.currentTab = tabIndex;
|
||
}
|
||
} else {
|
||
// 默认显示"全部"标签(索引0)
|
||
this.currentTab = 0;
|
||
}
|
||
},
|
||
|
||
onShow() {
|
||
// 页面显示时刷新订单统计和列表
|
||
if (this.isLogin) {
|
||
this.noMore = false;
|
||
this.page = 1;
|
||
this.orderList = [];
|
||
this.getOrderData();
|
||
this.loadOrderList();
|
||
this.getCartNum();
|
||
} else {
|
||
toLogin();
|
||
}
|
||
},
|
||
|
||
onReachBottom() {
|
||
this.loadMore();
|
||
},
|
||
|
||
methods: {
|
||
// 初始化页面
|
||
async initPage() {
|
||
// 检查登录状态
|
||
if (!this.isLogin) {
|
||
toLogin();
|
||
return;
|
||
}
|
||
|
||
// 加载订单统计
|
||
await this.getOrderData();
|
||
|
||
// 加载订单列表
|
||
this.loadOrderList();
|
||
},
|
||
|
||
// 获取订单统计数据
|
||
async getOrderData() {
|
||
try {
|
||
const res = await orderData();
|
||
if (res.data) {
|
||
this.orderData = res.data;
|
||
// 更新各个状态的订单数量
|
||
// 当前标签: 全部(-99), 待兑换(0), 待发货(1), 待收货(2), 已完成(4)
|
||
const unPaidCount = res.data.unPaidCount || 0; // 待兑换(待付款)
|
||
const unShippedCount = res.data.unShippedCount || 0;
|
||
const receivedCount = res.data.receivedCount || 0;
|
||
const evaluateCount = res.data.evaluateCount || 0; // 待评价
|
||
const completeCount = res.data.completeCount || 0; // 已完成
|
||
|
||
// "已完成"标签:包含待评价(type:3) + 已完成(type:4)
|
||
const finishedCount = evaluateCount + completeCount;
|
||
|
||
// 计算全部订单数量
|
||
const totalCount = res.data.orderCount || (unPaidCount + unShippedCount + receivedCount + finishedCount);
|
||
|
||
this.tabs[0].count = totalCount; // 全部
|
||
this.tabs[1].count = unPaidCount; // 待兑换
|
||
this.tabs[2].count = unShippedCount; // 待发货
|
||
this.tabs[3].count = receivedCount; // 待收货
|
||
this.tabs[4].count = finishedCount; // 已完成(包含待评价)
|
||
}
|
||
} catch (error) {
|
||
console.error('加载订单统计失败:', error);
|
||
}
|
||
},
|
||
|
||
// 获取购物车数量
|
||
async getCartNum() {
|
||
try {
|
||
const res = await getCartCounts(true, 'total');
|
||
if (res.data) {
|
||
this.cartCount = res.data.count || 0;
|
||
}
|
||
} catch (error) {
|
||
console.error('获取购物车数量失败:', error);
|
||
}
|
||
},
|
||
|
||
// 返回上一页
|
||
goBack() {
|
||
uni.navigateBack()
|
||
},
|
||
|
||
// 切换标签
|
||
switchTab(index) {
|
||
if (this.currentTab === index) return
|
||
this.currentTab = index
|
||
this.resetList()
|
||
this.loadOrderList()
|
||
},
|
||
|
||
// 重置列表
|
||
resetList() {
|
||
this.orderList = []
|
||
this.page = 1
|
||
this.noMore = false
|
||
},
|
||
|
||
// 加载订单列表
|
||
async loadOrderList() {
|
||
if (this.noMore) return
|
||
if (this.loading) return
|
||
|
||
// 检查登录状态
|
||
if (!this.isLogin) {
|
||
toLogin();
|
||
return;
|
||
}
|
||
|
||
this.loading = true
|
||
|
||
try {
|
||
const tab = this.tabs[this.currentTab];
|
||
const params = {
|
||
page: this.page,
|
||
limit: this.limit
|
||
};
|
||
|
||
let res;
|
||
|
||
// "全部"时传空字符串,其他传具体type值
|
||
if (tab.type === -99) {
|
||
params.type = '-99'; // 空字符串表示查询所有状态
|
||
res = await getOrderList(params);
|
||
} else if (tab.type === 4) {
|
||
// "已完成"标签:同时获取 type=3(待评价) 和 type=4(已完成) 的订单
|
||
const [res3, res4] = await Promise.all([
|
||
getOrderList({ ...params, type: 3 }),
|
||
getOrderList({ ...params, type: 4 })
|
||
]);
|
||
|
||
// 合并两个结果
|
||
const list3 = (res3.data && res3.data.list) || [];
|
||
const list4 = (res4.data && res4.data.list) || [];
|
||
const mergedList = [...list3, ...list4];
|
||
|
||
// 按创建时间倒序排序
|
||
mergedList.sort((a, b) => {
|
||
const timeA = new Date(a.createTime || 0).getTime();
|
||
const timeB = new Date(b.createTime || 0).getTime();
|
||
return timeB - timeA;
|
||
});
|
||
|
||
// 构造合并后的响应
|
||
res = {
|
||
data: {
|
||
list: mergedList
|
||
}
|
||
};
|
||
} else {
|
||
params.type = tab.type;
|
||
res = await getOrderList(params);
|
||
}
|
||
|
||
if (res.data) {
|
||
const list = res.data.list || [];
|
||
|
||
// 格式化订单数据
|
||
const formattedList = list.map(order => this.formatOrderData(order));
|
||
|
||
if (this.page === 1) {
|
||
this.orderList = formattedList;
|
||
} else {
|
||
this.orderList = [...this.orderList, ...formattedList];
|
||
}
|
||
|
||
if (list.length < this.limit) {
|
||
this.noMore = true;
|
||
}
|
||
|
||
this.page++;
|
||
this.isShow = true;
|
||
} else {
|
||
uni.showToast({
|
||
title: res.msg || '加载失败',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
} catch (error) {
|
||
console.error('加载订单失败:', error)
|
||
uni.showToast({
|
||
title: error.msg || '加载失败,请重试',
|
||
icon: 'none'
|
||
})
|
||
} finally {
|
||
this.loading = false
|
||
this.refreshing = false
|
||
}
|
||
},
|
||
|
||
// 格式化订单数据
|
||
formatOrderData(order) {
|
||
// 获取商品列表
|
||
const orderInfoList = order.orderInfoList || [];
|
||
|
||
// 计算总商品数量
|
||
let totalNum = order.totalNum || 1;
|
||
|
||
// 计算总积分:优先使用payIntegral/useIntegral,否则从商品列表计算
|
||
let totalPoints = 0;
|
||
|
||
// 优先使用订单级别的积分字段
|
||
if (order.payIntegral !== undefined && order.payIntegral !== null) {
|
||
totalPoints = parseFloat(order.payIntegral) || 0;
|
||
} else if (order.useIntegral !== undefined && order.useIntegral !== null) {
|
||
totalPoints = parseFloat(order.useIntegral) || 0;
|
||
} else if (order.integral !== undefined && order.integral !== null) {
|
||
totalPoints = parseFloat(order.integral) || 0;
|
||
} else {
|
||
// 从商品列表计算总积分
|
||
totalPoints = orderInfoList.reduce((sum, item) => {
|
||
// 优先使用integral字段,否则使用vipPrice或price
|
||
const itemPoints = parseFloat(item.integral) || parseFloat(item.vipPrice) || parseFloat(item.price) || 0;
|
||
const quantity = parseInt(item.cartNum) || 1;
|
||
return sum + (itemPoints * quantity);
|
||
}, 0);
|
||
|
||
// 如果计算结果为0,尝试使用payPrice或totalPrice
|
||
if (totalPoints === 0) {
|
||
totalPoints = parseFloat(order.payPrice) || parseFloat(order.totalPrice) || 0;
|
||
}
|
||
}
|
||
|
||
// 获取第一个商品的信息用于列表显示
|
||
let goodsName = '商品名称';
|
||
let goodsImage = '/static/images/default-goods.png';
|
||
let goodsPrice = 0;
|
||
let goodsNum = 1;
|
||
|
||
if (orderInfoList.length > 0) {
|
||
const firstGoods = orderInfoList[0];
|
||
goodsName = firstGoods.storeName || firstGoods.productName || goodsName;
|
||
goodsImage = firstGoods.image || goodsImage;
|
||
// 商品积分:优先使用integral,否则使用vipPrice或price
|
||
goodsPrice = parseFloat(firstGoods.integral) || parseFloat(firstGoods.vipPrice) || parseFloat(firstGoods.price) || 0;
|
||
goodsNum = firstGoods.cartNum || 1;
|
||
}
|
||
|
||
console.log('订单积分计算:', {
|
||
orderId: order.orderId,
|
||
payIntegral: order.payIntegral,
|
||
useIntegral: order.useIntegral,
|
||
integral: order.integral,
|
||
payPrice: order.payPrice,
|
||
totalPrice: order.totalPrice,
|
||
calculatedPoints: totalPoints,
|
||
orderInfoList: orderInfoList.map(item => ({
|
||
name: item.storeName,
|
||
integral: item.integral,
|
||
vipPrice: item.vipPrice,
|
||
price: item.price,
|
||
cartNum: item.cartNum
|
||
}))
|
||
});
|
||
|
||
return {
|
||
id: order.id,
|
||
orderId: order.orderId || order.orderNo || '',
|
||
order_no: order.orderId || order.orderNo || '',
|
||
goods_name: goodsName,
|
||
goods_image: goodsImage,
|
||
quantity: totalNum,
|
||
points: totalPoints,
|
||
goods_points: goodsPrice,
|
||
goods_quantity: goodsNum,
|
||
status: order.status,
|
||
paid: order.paid,
|
||
status_text: order.orderStatus || this.getStatusText(order.status, order.paid),
|
||
orderInfoList: orderInfoList,
|
||
createTime: order.createTime || '',
|
||
created_at: order.createTime || '',
|
||
activityType: order.activityType || '普通'
|
||
};
|
||
},
|
||
|
||
// 获取状态文本
|
||
getStatusText(status, paid) {
|
||
if (!paid) return '待兑换';
|
||
|
||
// status: 0-待发货 1-待收货 2-待评价 3-已完成
|
||
const statusMap = {
|
||
0: '待发货',
|
||
1: '待收货',
|
||
2: '待评价',
|
||
3: '已完成'
|
||
};
|
||
return statusMap[status] || '未知状态';
|
||
},
|
||
|
||
// 下拉刷新
|
||
onRefresh() {
|
||
this.refreshing = true
|
||
this.resetList()
|
||
this.getOrderData()
|
||
this.loadOrderList()
|
||
},
|
||
|
||
// 加载更多
|
||
loadMore() {
|
||
if (!this.noMore && !this.loading) {
|
||
this.loadOrderList()
|
||
}
|
||
},
|
||
|
||
// 取消订单
|
||
cancelOrder(orderId, index) {
|
||
uni.showModal({
|
||
title: '提示',
|
||
content: '确定要取消这个订单吗?',
|
||
confirmColor: '#f55850',
|
||
success: async (res) => {
|
||
if (res.confirm) {
|
||
if (!this.isLogin) {
|
||
toLogin();
|
||
return;
|
||
}
|
||
|
||
uni.showLoading({ title: '取消中...' })
|
||
|
||
try {
|
||
const result = await orderCancel(orderId);
|
||
|
||
uni.hideLoading()
|
||
uni.showToast({
|
||
title: '取消成功',
|
||
icon: 'success'
|
||
})
|
||
|
||
// 从列表中移除该订单
|
||
if (index !== undefined) {
|
||
this.orderList.splice(index, 1);
|
||
}
|
||
|
||
// 刷新统计
|
||
this.getOrderData();
|
||
} catch (error) {
|
||
uni.hideLoading()
|
||
uni.showToast({
|
||
title: error.msg || error.message || '取消失败,请重试',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
}
|
||
}
|
||
})
|
||
},
|
||
|
||
// 确认收货
|
||
confirmReceipt(orderId, index) {
|
||
uni.showModal({
|
||
title: '确认收货',
|
||
content: '确认已收到商品?',
|
||
confirmColor: '#f55850',
|
||
success: async (res) => {
|
||
if (res.confirm) {
|
||
if (!this.isLogin) {
|
||
toLogin();
|
||
return;
|
||
}
|
||
|
||
uni.showLoading({ title: '确认中...' })
|
||
|
||
try {
|
||
const result = await orderTake(orderId);
|
||
|
||
uni.hideLoading()
|
||
uni.showToast({
|
||
title: '确认收货成功',
|
||
icon: 'success'
|
||
})
|
||
|
||
// 刷新统计和列表
|
||
this.getOrderData();
|
||
this.resetList();
|
||
this.loadOrderList();
|
||
} catch (error) {
|
||
uni.hideLoading()
|
||
uni.showToast({
|
||
title: error.msg || error.message || '操作失败,请重试',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
}
|
||
}
|
||
})
|
||
},
|
||
|
||
// 删除订单
|
||
delOrder(orderId, index) {
|
||
uni.showModal({
|
||
title: '提示',
|
||
content: '确定要删除这个订单吗?',
|
||
confirmColor: '#f55850',
|
||
success: async (res) => {
|
||
if (res.confirm) {
|
||
try {
|
||
await orderDel(orderId);
|
||
|
||
uni.showToast({
|
||
title: '删除成功',
|
||
icon: 'success'
|
||
})
|
||
|
||
// 从列表中移除该订单
|
||
if (index !== undefined) {
|
||
this.orderList.splice(index, 1);
|
||
}
|
||
|
||
// 刷新统计
|
||
this.getOrderData();
|
||
} catch (error) {
|
||
uni.showToast({
|
||
title: error.msg || '删除失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
}
|
||
}
|
||
})
|
||
},
|
||
|
||
// 查看物流
|
||
viewLogistics(order) {
|
||
if (!order.express_no) {
|
||
uni.showToast({
|
||
title: '暂无物流信息',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
// 跳转到积分订单详情页面查看物流
|
||
uni.navigateTo({
|
||
url: `/pages/integral/order-detail?id=${order.orderId}`
|
||
})
|
||
},
|
||
|
||
// 跳转订单详情
|
||
goToDetail(orderId) {
|
||
if (!orderId) return;
|
||
uni.navigateTo({
|
||
url: `/pages/integral/order-detail?id=${orderId}`
|
||
})
|
||
},
|
||
|
||
// 去评价
|
||
goComment(order) {
|
||
if (!order.orderInfoList || order.orderInfoList.length === 0) {
|
||
uni.showToast({
|
||
title: '商品信息不存在',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
const firstGoods = order.orderInfoList[0]
|
||
uni.navigateTo({
|
||
url: `/pages/goods/goods_comment_con/index?unique=${firstGoods.attrId}&orderId=${order.orderId}&id=${order.id}`
|
||
})
|
||
},
|
||
|
||
// 去商城
|
||
goToShop() {
|
||
uni.navigateTo({
|
||
url: '/pages/integral/index'
|
||
})
|
||
},
|
||
|
||
// 去购物车
|
||
goToCart() {
|
||
uni.navigateTo({
|
||
url: '/pages/integral/cart'
|
||
})
|
||
},
|
||
|
||
// 去支付
|
||
goPay(order) {
|
||
uni.navigateTo({
|
||
url: `/pages/order/order_payment/index?orderNo=${order.orderId}&payPrice=${order.points}`
|
||
})
|
||
},
|
||
|
||
// 格式化积分
|
||
formatPoints(price) {
|
||
if (!price && price !== 0) return '0'
|
||
// 积分显示为整数,添加千分位
|
||
return Number(price).toFixed(0).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
||
},
|
||
|
||
// 获取状态颜色
|
||
getStatusColor(status, paid) {
|
||
if (!paid) return '#F54900'; // 待付款 - 橙色
|
||
|
||
// status: 0-待发货 1-待收货 2-待评价 3-已完成
|
||
const colors = {
|
||
0: '#F54900', // 待发货 - 橙色
|
||
1: '#F54900', // 待收货 - 橙色
|
||
2: '#F54900', // 待评价 - 橙色
|
||
3: '#52c41a', // 已完成 - 绿色
|
||
}
|
||
return colors[status] || '#F54900'
|
||
},
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.orders-page {
|
||
min-height: 100vh;
|
||
background-color: #F9FAFB;
|
||
display: flex;
|
||
flex-direction: column;
|
||
padding-bottom: 120rpx;
|
||
}
|
||
|
||
// 橙色头部
|
||
.header-section {
|
||
background-color: #F54900;
|
||
padding: 0;
|
||
}
|
||
|
||
.header-content {
|
||
height: 112rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 0 32rpx;
|
||
}
|
||
|
||
.header-icon {
|
||
width: 72rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
.iconfont {
|
||
font-size: 36rpx;
|
||
color: #FFFFFF;
|
||
}
|
||
}
|
||
|
||
.header-title {
|
||
flex: 1;
|
||
font-size: 36rpx;
|
||
color: #FFFFFF;
|
||
font-weight: normal;
|
||
text-align: center;
|
||
line-height: 56rpx;
|
||
}
|
||
|
||
.header-menu {
|
||
font-size: 32rpx;
|
||
color: #FFFFFF;
|
||
font-weight: bold;
|
||
letter-spacing: 2rpx;
|
||
width: 72rpx;
|
||
text-align: right;
|
||
}
|
||
|
||
// 状态统计栏
|
||
.stats-bar {
|
||
background-color: #FFFFFF;
|
||
display: flex;
|
||
padding: 32rpx 0;
|
||
align-items: center;
|
||
justify-content: space-around;
|
||
}
|
||
|
||
.stat-item {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.stat-number-wrapper {
|
||
position: relative;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
|
||
.stat-number {
|
||
font-size: 40rpx;
|
||
color: #333333;
|
||
font-weight: 500;
|
||
line-height: 1.2;
|
||
|
||
&.active {
|
||
color: #F54900;
|
||
}
|
||
}
|
||
|
||
.stat-underline {
|
||
position: absolute;
|
||
bottom: -4rpx;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: 24rpx;
|
||
height: 4rpx;
|
||
background-color: #F54900;
|
||
}
|
||
|
||
.stat-text {
|
||
font-size: 26rpx;
|
||
color: #666666;
|
||
font-weight: normal;
|
||
line-height: 1.2;
|
||
|
||
&.active {
|
||
color: #F54900;
|
||
}
|
||
}
|
||
|
||
.orders-list {
|
||
flex: 1;
|
||
padding: 24rpx 32rpx;
|
||
background-color: #F9FAFB;
|
||
}
|
||
|
||
.list-container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 24rpx;
|
||
}
|
||
|
||
.order-item {
|
||
background-color: #FFFFFF;
|
||
border-radius: 20rpx;
|
||
overflow: hidden;
|
||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
||
}
|
||
|
||
.order-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 24rpx 32rpx;
|
||
border-bottom: 1rpx solid #F5F5F5;
|
||
}
|
||
|
||
.order-time {
|
||
font-size: 28rpx;
|
||
color: #333333;
|
||
line-height: 40rpx;
|
||
}
|
||
|
||
.order-status {
|
||
font-size: 28rpx;
|
||
font-weight: normal;
|
||
color: #F54900;
|
||
line-height: 40rpx;
|
||
}
|
||
|
||
.order-content {
|
||
padding: 0 32rpx;
|
||
}
|
||
|
||
.goods-row {
|
||
display: flex;
|
||
padding: 24rpx 0;
|
||
gap: 20rpx;
|
||
border-bottom: 1rpx solid #F5F5F5;
|
||
|
||
&:last-child {
|
||
border-bottom: none;
|
||
}
|
||
}
|
||
|
||
.goods-image {
|
||
width: 100rpx;
|
||
height: 100rpx;
|
||
border-radius: 12rpx;
|
||
background-color: #F5F5F5;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.goods-info {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
gap: 12rpx;
|
||
}
|
||
|
||
.goods-name {
|
||
font-size: 28rpx;
|
||
color: #333333;
|
||
line-height: 40rpx;
|
||
font-weight: normal;
|
||
display: -webkit-box;
|
||
-webkit-box-orient: vertical;
|
||
-webkit-line-clamp: 1;
|
||
line-clamp: 1;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.goods-price-row {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.goods-points {
|
||
font-size: 28rpx;
|
||
color: #F54900;
|
||
font-weight: normal;
|
||
line-height: 40rpx;
|
||
}
|
||
|
||
.goods-quantity {
|
||
font-size: 26rpx;
|
||
color: #999999;
|
||
line-height: 40rpx;
|
||
}
|
||
|
||
.order-summary {
|
||
padding: 24rpx 32rpx;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
align-items: center;
|
||
gap: 8rpx;
|
||
}
|
||
|
||
.summary-text {
|
||
font-size: 26rpx;
|
||
color: #333333;
|
||
line-height: 40rpx;
|
||
}
|
||
|
||
.summary-points {
|
||
font-size: 28rpx;
|
||
color: #F54900;
|
||
font-weight: 500;
|
||
line-height: 40rpx;
|
||
}
|
||
|
||
.empty-state {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 200rpx 0;
|
||
}
|
||
|
||
.empty-image {
|
||
width: 300rpx;
|
||
height: 300rpx;
|
||
margin-bottom: 40rpx;
|
||
}
|
||
|
||
.empty-text {
|
||
font-size: 28rpx;
|
||
color: #999999;
|
||
margin-bottom: 40rpx;
|
||
}
|
||
|
||
.empty-btn {
|
||
width: 200rpx;
|
||
height: 80rpx;
|
||
line-height: 80rpx;
|
||
background-color: #F54900;
|
||
color: #FFFFFF;
|
||
border-radius: 40rpx;
|
||
font-size: 28rpx;
|
||
border: none;
|
||
|
||
&::after {
|
||
border: none;
|
||
}
|
||
}
|
||
|
||
.load-more {
|
||
padding: 40rpx 0;
|
||
text-align: center;
|
||
}
|
||
|
||
.load-text {
|
||
font-size: 28rpx;
|
||
color: #999999;
|
||
line-height: 40rpx;
|
||
}
|
||
|
||
// 底部导航栏
|
||
.bottom-tabbar {
|
||
position: fixed;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: 100rpx;
|
||
background-color: #FFFFFF;
|
||
display: flex;
|
||
border-top: 1rpx solid #EEEEEE;
|
||
z-index: 100;
|
||
padding-bottom: constant(safe-area-inset-bottom);
|
||
padding-bottom: env(safe-area-inset-bottom);
|
||
}
|
||
|
||
.tab-item {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 4rpx;
|
||
}
|
||
|
||
.tab-icon-wrap {
|
||
position: relative;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.tab-icon {
|
||
width: 44rpx;
|
||
height: 44rpx;
|
||
}
|
||
|
||
.cart-badge {
|
||
position: absolute;
|
||
top: -8rpx;
|
||
right: -16rpx;
|
||
min-width: 32rpx;
|
||
height: 32rpx;
|
||
background-color: #F54900;
|
||
border-radius: 16rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 0 8rpx;
|
||
|
||
text {
|
||
font-size: 20rpx;
|
||
color: #FFFFFF;
|
||
font-weight: 500;
|
||
}
|
||
}
|
||
|
||
.tab-text {
|
||
font-size: 22rpx;
|
||
color: #999999;
|
||
|
||
&.active {
|
||
color: #F54900;
|
||
}
|
||
}
|
||
</style>
|
||
|