Files
consumer-front/pages/order/order.vue
T
2026-04-30 15:07:56 +08:00

641 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="order-page">
<!-- 顶部Tab切换 -->
<view class="tab-header">
<view
class="tab-item"
:class="{ active: currentTab === 'all' }"
@click="switchTab('all')"
>
<text class="tab-text">全部订单</text>
<view class="tab-line" v-if="currentTab === 'all'"></view>
</view>
<view
class="tab-item"
:class="{ active: currentTab === 'paid' }"
@click="switchTab('paid')"
>
<text class="tab-text">已支付</text>
<view class="tab-line" v-if="currentTab === 'paid'"></view>
</view>
<view
class="tab-item"
:class="{ active: currentTab === 'unpaid' }"
@click="switchTab('unpaid')"
>
<text class="tab-text">未支付</text>
<view class="tab-line" v-if="currentTab === 'unpaid'"></view>
</view>
</view>
<!-- 数量统计和筛选 -->
<view class="filter-bar">
<text class="total-count">总数量: {{ filteredOrders.length }}</text>
<view class="search-btn" @click="showFilterSidebar = true">
<text class="search-icon">🔍</text>
</view>
</view>
<!-- 筛选条件显示 -->
<view class="filter-condition" v-if="filterStartTime || filterEndTime">
<text class="filter-text">{{ filterStartTime }} - {{ filterEndTime }}</text>
<text class="filter-clear" @click="clearFilter"></text>
</view>
<!-- 订单列表 -->
<scroll-view class="order-scroll" scroll-y>
<view class="order-list">
<view
class="order-card"
v-for="(order, index) in filteredOrders"
:key="index"
>
<!-- 第一行: 日期 + 状态 -->
<view class="order-header">
<text class="order-date">{{ order.create_time }}</text>
<text class="order-status" :class="{ paid: order.status === 'paid', unpaid: order.status === 'unpaid' }">
{{ order.status === 'paid' ? '已支付' : '未支付' }}
</text>
</view>
<view class="divider"></view>
<!-- 商品列表整体可点击跳转 -->
<view class="product-section" @click="goToDetail(order)">
<view class="product-list">
<view
class="product-item"
v-for="(product, pIndex) in order.products"
:key="pIndex"
>
<image class="product-img" :src="product.image" mode="aspectFill" />
<view class="product-info">
<text class="product-name">{{ product.name }}</text>
<text class="product-price-qty">{{ product.price }} x {{ product.quantity }}</text>
</view>
</view>
</view>
<view class="product-arrow">
<text class="arrow-icon"></text>
</view>
</view>
<!-- 总计 -->
<view class="order-total">
<text class="total-qty">{{ order.totalQuantity }}</text>
<view class="total-amount">
<text class="total-label">总计:</text>
<text class="total-price">{{ order.totalAmount }}</text>
</view>
</view>
<!-- 操作按钮 -->
<view class="order-action">
<view
class="action-btn"
:class="{ 'pay-btn': order.status === 'unpaid', 'refund-btn': order.status === 'paid' }"
@click="handleAction(order)"
>
{{ order.status === 'unpaid' ? '立即支付' : '申请退款' }}
</view>
</view>
</view>
<!-- 空状态 -->
<view class="empty-state" v-if="filteredOrders.length === 0">
<text class="empty-text">暂无订单</text>
</view>
</view>
<view class="bottom-spacer"></view>
</scroll-view>
<!-- 筛选侧边栏 -->
<view class="filter-sidebar-mask" v-if="showFilterSidebar" @click="showFilterSidebar = false">
<view class="filter-sidebar" @click.stop>
<view class="sidebar-header">
<text class="sidebar-title">筛选条件</text>
<text class="sidebar-close" @click="showFilterSidebar = false"></text>
</view>
<view class="sidebar-content">
<view class="date-row">
<text class="date-label">开始时间</text>
<picker
mode="date"
:value="tempStartTime"
@change="onStartTimeChange"
>
<view class="date-picker">
<text class="date-value">{{ tempStartTime || '请选择' }}</text>
</view>
</picker>
</view>
<view class="date-row">
<text class="date-label">结束时间</text>
<picker
mode="date"
:value="tempEndTime"
@change="onEndTimeChange"
>
<view class="date-picker">
<text class="date-value">{{ tempEndTime || '请选择' }}</text>
</view>
</picker>
</view>
</view>
<view class="sidebar-footer">
<view class="sidebar-btn reset-btn" @click="resetFilter">
<text class="btn-text">重置</text>
</view>
<view class="sidebar-btn confirm-btn" @click="confirmFilter">
<text class="btn-text">确定</text>
</view>
</view>
</view>
</view>
<!-- 底部导航条 -->
<page-nav-bar
:hasPrev="true"
:hasNext="false"
@prev="handleNavPrev"
@next="handleNavNext"
/>
</view>
</template>
<script>
import PageNavBar from '@/components/page-nav-bar/page-nav-bar.vue';
export default {
components: { PageNavBar },
data() {
return {
currentTab: 'all',
showFilterSidebar: false,
tempStartTime: '',
tempEndTime: '',
filterStartTime: '',
filterEndTime: '',
// 模拟订单数据
orderList: [
{
id: 1,
create_time: '2026-04-30 10:25:30',
status: 'paid',
products: [
{ name: '君乐宝450ml悦鲜活', price: 0.01, quantity: 2, image: '/static/c1.png' },
{ name: '可口可乐330ml', price: 3.00, quantity: 1, image: '/static/c4.png' }
],
totalQuantity: 3,
totalAmount: '0.04'
},
{
id: 2,
create_time: '2026-04-29 15:12:45',
status: 'unpaid',
products: [
{ name: '农夫山泉550ml', price: 2.00, quantity: 3, image: '/static/c5.png' }
],
totalQuantity: 3,
totalAmount: '6.00'
},
{
id: 3,
create_time: '2026-04-28 09:30:00',
status: 'paid',
products: [
{ name: '乐事薯片原味75g', price: 7.50, quantity: 1, image: '/static/c6.png' },
{ name: '白桔(0.0.0.0-5.5.5', price: 0.05, quantity: 5, image: '/static/c3.png' }
],
totalQuantity: 6,
totalAmount: '1.00'
},
{
id: 4,
create_time: '2026-04-27 18:45:20',
status: 'unpaid',
products: [
{ name: '白红(0.0.0.0-9.9.9', price: 0.06, quantity: 10, image: '/static/c2.png' }
],
totalQuantity: 10,
totalAmount: '0.60'
},
{
id: 5,
create_time: '2026-04-25 12:00:00',
status: 'paid',
products: [
{ name: '君乐宝450ml悦鲜活', price: 0.01, quantity: 1, image: '/static/c1.png' }
],
totalQuantity: 1,
totalAmount: '0.01'
}
]
};
},
computed: {
filteredOrders() {
let list = this.orderList;
// Tab筛选
if (this.currentTab === 'paid') {
list = list.filter(o => o.status === 'paid');
} else if (this.currentTab === 'unpaid') {
list = list.filter(o => o.status === 'unpaid');
}
// 日期筛选
if (this.filterStartTime) {
list = list.filter(o => o.create_time >= this.filterStartTime);
}
if (this.filterEndTime) {
list = list.filter(o => o.create_time.split(' ')[0] <= this.filterEndTime);
}
return list;
}
},
methods: {
switchTab(tab) {
this.currentTab = tab;
},
onStartTimeChange(e) {
this.tempStartTime = e.detail.value;
},
onEndTimeChange(e) {
this.tempEndTime = e.detail.value;
},
resetFilter() {
this.tempStartTime = '';
this.tempEndTime = '';
},
confirmFilter() {
this.filterStartTime = this.tempStartTime;
this.filterEndTime = this.tempEndTime;
this.showFilterSidebar = false;
},
clearFilter() {
this.filterStartTime = '';
this.filterEndTime = '';
},
goToDetail(order) {
uni.showToast({ title: '订单详情开发中', icon: 'none' });
},
handleAction(order) {
if (order.status === 'unpaid') {
uni.showModal({
title: '立即支付',
content: `确认支付¥${order.totalAmount}`,
success: (res) => {
if (res.confirm) {
uni.showToast({ title: '支付成功', icon: 'success' });
}
}
});
} else {
uni.showModal({
title: '申请退款',
content: '确认申请退款?',
success: (res) => {
if (res.confirm) {
uni.showToast({ title: '退款申请已提交', icon: 'success' });
}
}
});
}
},
handleNavPrev() {
uni.navigateBack({ fail: () => { uni.switchTab({ url: '/pages/index/index' }); } });
},
handleNavNext() {
uni.showToast({ title: '暂无下一页', icon: 'none' });
}
}
};
</script>
<style scoped>
page { height: 100%; background-color: #f5f5f5; }
.order-page {
display: flex;
flex-direction: column;
height: 100vh;
background-color: #f5f5f5;
}
/* 顶部Tab */
.tab-header {
display: flex;
background: #fff;
padding: 0 24rpx;
}
.tab-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
padding: 28rpx 0 20rpx;
position: relative;
}
.tab-text {
font-size: 30rpx;
color: #666;
}
.tab-item.active .tab-text {
color: #2979ff;
font-weight: bold;
}
.tab-line {
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 48rpx;
height: 6rpx;
background: #2979ff;
border-radius: 3rpx;
}
/* 筛选栏 */
.filter-bar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 28rpx;
background: #fff;
border-top: 1rpx solid #f0f0f0;
}
.total-count {
font-size: 28rpx;
color: #333;
}
.search-btn {
padding: 8rpx 16rpx;
}
.search-icon {
font-size: 36rpx;
}
/* 筛选条件显示 */
.filter-condition {
display: flex;
align-items: center;
padding: 16rpx 28rpx;
background: #e8f4ff;
}
.filter-text {
font-size: 26rpx;
color: #2979ff;
flex: 1;
}
.filter-clear {
font-size: 28rpx;
color: #999;
padding: 8rpx;
}
/* 订单列表 */
.order-scroll {
flex: 1;
height: 0;
}
.order-list {
padding: 20rpx;
}
.order-card {
background: #fff;
border-radius: 16rpx;
margin-bottom: 20rpx;
padding: 24rpx;
}
/* 订单头部 */
.order-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.order-date {
font-size: 26rpx;
color: #666;
}
.order-status {
font-size: 26rpx;
font-weight: bold;
}
.order-status.paid {
color: #19be6b;
}
.order-status.unpaid {
color: #e4393c;
}
.divider {
height: 1rpx;
background: #f0f0f0;
margin: 20rpx 0;
}
/* 商品列表 */
.product-section {
display: flex;
align-items: stretch;
margin-bottom: 20rpx;
}
.product-list {
flex: 1;
min-width: 0;
}
.product-item {
display: flex;
align-items: center;
padding: 16rpx 0;
}
.product-img {
width: 100rpx;
height: 100rpx;
border-radius: 8rpx;
background: #f0f0f0;
flex-shrink: 0;
}
.product-info {
flex: 1;
margin-left: 20rpx;
min-width: 0;
}
.product-name {
font-size: 28rpx;
font-weight: bold;
color: #333;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.product-price-qty {
font-size: 24rpx;
color: #999;
margin-top: 8rpx;
display: block;
}
.product-arrow {
display: flex;
align-items: center;
padding: 0 16rpx 0 20rpx;
}
.arrow-icon {
font-size: 52rpx;
color: #bbb;
}
/* 总计 */
.order-total {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 16rpx;
border-top: 1rpx solid #f0f0f0;
}
.total-qty {
font-size: 26rpx;
color: #666;
}
.total-amount {
display: flex;
align-items: center;
}
.total-label {
font-size: 26rpx;
color: #666;
}
.total-price {
font-size: 32rpx;
font-weight: bold;
color: #e4393c;
margin-left: 4rpx;
}
/* 操作按钮 */
.order-action {
display: flex;
justify-content: flex-end;
margin-top: 20rpx;
}
.action-btn {
padding: 16rpx 40rpx;
border-radius: 40rpx;
font-size: 26rpx;
}
.pay-btn {
background: linear-gradient(135deg, #2979ff, #1e60e0);
color: #fff;
}
.refund-btn {
background: #fff;
border: 2rpx solid #2979ff;
color: #2979ff;
}
/* 空状态 */
.empty-state {
display: flex;
justify-content: center;
align-items: center;
padding: 100rpx 0;
}
.empty-text {
font-size: 28rpx;
color: #999;
}
/* 筛选侧边栏 */
.filter-sidebar-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
}
.filter-sidebar {
position: absolute;
top: 0;
right: 0;
width: 600rpx;
height: 100%;
background: #fff;
display: flex;
flex-direction: column;
}
.sidebar-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 32rpx 28rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.sidebar-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.sidebar-close {
font-size: 36rpx;
color: #999;
padding: 8rpx;
}
.sidebar-content {
flex: 1;
padding: 28rpx;
}
.date-row {
margin-bottom: 32rpx;
}
.date-label {
font-size: 28rpx;
color: #333;
margin-bottom: 16rpx;
display: block;
}
.date-picker {
background: #f5f5f5;
border-radius: 8rpx;
padding: 24rpx;
}
.date-value {
font-size: 28rpx;
color: #333;
}
.sidebar-footer {
display: flex;
padding: 28rpx;
border-top: 1rpx solid #f0f0f0;
}
.sidebar-btn {
flex: 1;
padding: 24rpx 0;
text-align: center;
border-radius: 8rpx;
margin: 0 8rpx;
}
.reset-btn {
background: #f5f5f5;
}
.confirm-btn {
background: #2979ff;
}
.reset-btn .btn-text {
color: #666;
}
.confirm-btn .btn-text {
color: #fff;
}
.btn-text {
font-size: 28rpx;
}
/* 底部占位 */
.bottom-spacer {
height: 120rpx;
}
</style>