1051 lines
22 KiB
Plaintext
1051 lines
22 KiB
Plaintext
<!-- 订单列表页面 -->
|
||
<template>
|
||
<view class="orders-page">
|
||
<!-- 顶部栏 -->
|
||
<!-- <view class="orders-header" @click="goBackToHome">
|
||
<view class="header-left">
|
||
<text class="header-title">我的订单</text>
|
||
</view>
|
||
<view class="header-right">
|
||
<text class="search-icon" @click.stop="navigateToSearch">🔍</text>
|
||
</view>
|
||
</view> -->
|
||
|
||
<!-- 订单状态标签页 -->
|
||
<view class="order-tabs">
|
||
<view :class="['order-tab', { active: activeTab === 'all' }]" @click="changeTab('all')">
|
||
<text class="tab-text">全部</text>
|
||
</view>
|
||
<view :class="['order-tab', { active: activeTab === 'pending' }]" @click="changeTab('pending')">
|
||
<text class="tab-text">待支付</text>
|
||
<text v-if="tabBadges.pending > 0" class="tab-badge">{{ tabBadges.pending }}</text>
|
||
</view>
|
||
<view :class="['order-tab', { active: activeTab === 'shipping' }]" @click="changeTab('shipping')">
|
||
<text class="tab-text">待发货</text>
|
||
<text v-if="tabBadges.shipping > 0" class="tab-badge">{{ tabBadges.shipping }}</text>
|
||
</view>
|
||
<view :class="['order-tab', { active: activeTab === 'receiving' }]" @click="changeTab('receiving')">
|
||
<text class="tab-text">待收货</text>
|
||
<text v-if="tabBadges.receiving > 0" class="tab-badge">{{ tabBadges.receiving }}</text>
|
||
</view>
|
||
<view :class="['order-tab', { active: activeTab === 'review' }]" @click="changeTab('review')">
|
||
<text class="tab-text">待评价</text>
|
||
<text v-if="tabBadges.review > 0" class="tab-badge">{{ tabBadges.review }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 订单列表 -->
|
||
<scroll-view class="orders-list" scroll-y @scrolltolower="loadMore">
|
||
<!-- 订单为空 -->
|
||
<view v-if="orders.length === 0 && !isLoading" class="empty-orders">
|
||
<text class="empty-icon">📦</text>
|
||
<text class="empty-text">暂无订单</text>
|
||
<text class="empty-subtext">去逛逛吧,有惊喜在等你</text>
|
||
<button class="go-shopping-btn" @click="goShopping">去逛逛</button>
|
||
</view>
|
||
|
||
<!-- 订单项 -->
|
||
<view v-for="order in orders" :key="order.id" class="order-item">
|
||
<!-- 订单头部 -->
|
||
<view class="order-header">
|
||
<text class="order-no">订单号: {{ order.order_no }}</text>
|
||
<text :class="['order-status', getStatusClass(order.status)]">
|
||
{{ getStatusText(order.status) }}
|
||
</text>
|
||
</view>
|
||
|
||
<!-- 订单商品 -->
|
||
<view class="order-products" @click="viewOrderDetail(order)">
|
||
<view v-for="(item, index) in order.items" :key="index" class="product-item">
|
||
<image class="product-image" :src="item.product_image || '/static/default-product.png'" />
|
||
<view class="product-info">
|
||
<text class="product-name">{{ item.product_name }}</text>
|
||
<text v-if="item.sku_specifications" class="product-spec">
|
||
{{ getSpecText(item.sku_specifications) }}
|
||
</text>
|
||
<view class="product-price-row">
|
||
<text class="product-price">¥{{ item.price }}</text>
|
||
<text class="product-quantity">×{{ item.quantity }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 订单信息 -->
|
||
<view class="order-info">
|
||
<text class="order-time">{{ formatTime(order.created_at) }}</text>
|
||
<view class="order-total">
|
||
共{{ getTotalQuantity(order.items) }}件商品 合计:
|
||
<text class="total-amount">¥{{ order.actual_amount }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 订单操作 -->
|
||
<view class="order-actions">
|
||
<button v-if="order.status === 1"
|
||
class="action-btn pay"
|
||
@click="payOrder(order)">
|
||
立即支付
|
||
</button>
|
||
<button v-if="order.status === 1"
|
||
class="action-btn cancel"
|
||
@click="cancelOrder(order)">
|
||
取消订单
|
||
</button>
|
||
<button v-if="order.status === 2"
|
||
class="action-btn remind"
|
||
@click="remindShipment(order)">
|
||
提醒发货
|
||
</button>
|
||
<button v-if="order.status === 3"
|
||
class="action-btn confirm"
|
||
@click="confirmReceipt(order)">
|
||
确认收货
|
||
</button>
|
||
<button v-if="order.status === 4"
|
||
class="action-btn review"
|
||
@click="goToReview(order)">
|
||
评价
|
||
</button>
|
||
<button v-if="order.status === 4 || order.status === 5"
|
||
class="action-btn delete"
|
||
@click="deleteOrder(order)">
|
||
删除订单
|
||
</button>
|
||
<button v-if="order.status === 4"
|
||
class="action-btn rebuy"
|
||
@click="reBuy(order)">
|
||
再次购买
|
||
</button>
|
||
<button class="action-btn service" @click="contactService(order)">
|
||
联系客服
|
||
</button>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 加载更多 -->
|
||
<view v-if="isLoading" class="loading-more">
|
||
<text class="loading-text">加载中...</text>
|
||
</view>
|
||
<view v-if="!hasMore && orders.length > 0" class="no-more">
|
||
<text class="no-more-text">没有更多订单了</text>
|
||
</view>
|
||
</scroll-view>
|
||
|
||
<!-- 底部导航 -->
|
||
<view class="bottom-navigation">
|
||
<view class="nav-item" @click="goToHome">
|
||
<text class="nav-icon">🏠</text>
|
||
<text class="nav-text">首页</text>
|
||
</view>
|
||
<view class="nav-item" @click="goToCategory">
|
||
<text class="nav-icon">📂</text>
|
||
<text class="nav-text">分类</text>
|
||
</view>
|
||
<view class="nav-item active">
|
||
<text class="nav-icon">📦</text>
|
||
<text class="nav-text">订单</text>
|
||
</view>
|
||
<view class="nav-item" @click="goToProfile">
|
||
<text class="nav-icon">👤</text>
|
||
<text class="nav-text">我的</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup lang="uts">
|
||
import { ref, onMounted, watch } from 'vue'
|
||
import { onShow, onBackPress } from '@dcloudio/uni-app'
|
||
import type { OrderType } from '@/types/mall-types.uts'
|
||
// import supa from '@/components/supadb/aksupainstance.uts'
|
||
|
||
type OrderItemType = {
|
||
id: string
|
||
product_id: string
|
||
product_name: string
|
||
product_image: string
|
||
sku_specifications: any
|
||
price: number
|
||
quantity: number
|
||
}
|
||
|
||
type FullOrderType = OrderType & {
|
||
items: Array<OrderItemType>
|
||
}
|
||
|
||
type TabBadgesType = {
|
||
pending: number
|
||
shipping: number
|
||
receiving: number
|
||
review: number
|
||
}
|
||
|
||
const activeTab = ref<string>('all')
|
||
const orders = ref<Array<FullOrderType>>([])
|
||
const tabBadges = ref<TabBadgesType>({
|
||
pending: 0,
|
||
shipping: 0,
|
||
receiving: 0,
|
||
review: 0
|
||
})
|
||
const isLoading = ref<boolean>(false)
|
||
const currentPage = ref<number>(1)
|
||
const pageSize = ref<number>(10)
|
||
const hasMore = ref<boolean>(true)
|
||
|
||
// 监听标签页变化
|
||
watch(activeTab, () => {
|
||
loadOrders()
|
||
})
|
||
|
||
// 生命周期
|
||
onMounted(() => {
|
||
loadOrderCounts()
|
||
loadOrders()
|
||
})
|
||
|
||
// 加载订单数量统计
|
||
const loadOrderCounts = async () => {
|
||
const userId = getCurrentUserId() || 'user_001'
|
||
if (!userId) return
|
||
|
||
try {
|
||
// 从本地存储获取订单
|
||
const ordersStr = uni.getStorageSync('orders')
|
||
let localOrders: any[] = []
|
||
if (ordersStr) {
|
||
localOrders = JSON.parse(ordersStr as string) as any[]
|
||
}
|
||
|
||
// 过滤当前用户的订单
|
||
const userOrders = localOrders.filter((o: any) => o.user_id === userId)
|
||
|
||
// 待支付
|
||
const pendingCount = userOrders.filter((o: any) => o.status === 1).length
|
||
tabBadges.value.pending = pendingCount
|
||
|
||
// 待发货
|
||
const shippingCount = userOrders.filter((o: any) => o.status === 2).length
|
||
tabBadges.value.shipping = shippingCount
|
||
|
||
// 待收货
|
||
const receivingCount = userOrders.filter((o: any) => o.status === 3).length
|
||
tabBadges.value.receiving = receivingCount
|
||
|
||
// 待评价
|
||
const reviewCount = userOrders.filter((o: any) => o.status === 4).length
|
||
tabBadges.value.review = reviewCount
|
||
|
||
} catch (err) {
|
||
console.error('加载订单统计异常:', err)
|
||
}
|
||
}
|
||
|
||
// 加载订单列表
|
||
const loadOrders = async (loadMore: boolean = false) => {
|
||
const userId = getCurrentUserId() || 'user_001' // 默认用户ID
|
||
if (!userId) {
|
||
// uni.showToast({
|
||
// title: '请先登录',
|
||
// icon: 'none'
|
||
// })
|
||
// uni.navigateTo({
|
||
// url: '/pages/user/login'
|
||
// })
|
||
// 模拟已登录,用于测试
|
||
// return
|
||
}
|
||
|
||
if (isLoading.value || (!hasMore.value && loadMore)) {
|
||
return
|
||
}
|
||
|
||
isLoading.value = true
|
||
|
||
try {
|
||
const page = loadMore ? currentPage.value + 1 : 1
|
||
// 从本地存储获取订单
|
||
const ordersStr = uni.getStorageSync('orders')
|
||
let localOrders: any[] = []
|
||
if (ordersStr) {
|
||
localOrders = JSON.parse(ordersStr as string) as any[]
|
||
}
|
||
|
||
// 过滤当前用户的订单
|
||
const userOrders = localOrders.filter((o: any) => o.user_id === userId)
|
||
|
||
// 根据标签页过滤
|
||
let filteredOrders = userOrders
|
||
switch (activeTab.value) {
|
||
case 'pending':
|
||
filteredOrders = userOrders.filter((o: any) => o.status === 1)
|
||
break
|
||
case 'shipping':
|
||
filteredOrders = userOrders.filter((o: any) => o.status === 2)
|
||
break
|
||
case 'receiving':
|
||
filteredOrders = userOrders.filter((o: any) => o.status === 3)
|
||
break
|
||
case 'review':
|
||
filteredOrders = userOrders.filter((o: any) => o.status === 4)
|
||
break
|
||
}
|
||
|
||
// 按时间倒序
|
||
filteredOrders.sort((a: any, b: any) => {
|
||
return new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
|
||
})
|
||
|
||
// 分页 (模拟)
|
||
const total = filteredOrders.length
|
||
const start = (page - 1) * pageSize.value
|
||
const end = start + pageSize.value
|
||
const pagedOrders = filteredOrders.slice(start, end)
|
||
|
||
// 处理订单数据,补充商品图片等信息
|
||
const processedOrders = await processOrderData(pagedOrders)
|
||
|
||
if (loadMore) {
|
||
for (let i = 0; i < processedOrders.length; i++) {
|
||
orders.value.push(processedOrders[i])
|
||
}
|
||
currentPage.value = page
|
||
} else {
|
||
orders.value = processedOrders
|
||
currentPage.value = 1
|
||
}
|
||
|
||
hasMore.value = end < total
|
||
} catch (err) {
|
||
console.error('加载订单异常:', err)
|
||
} finally {
|
||
isLoading.value = false
|
||
}
|
||
}
|
||
|
||
// 处理订单数据
|
||
const processOrderData = async (orders: any[]): Promise<FullOrderType[]> => {
|
||
const processed: FullOrderType[] = []
|
||
|
||
for (let i = 0; i < orders.length; i++) {
|
||
const order = orders[i]
|
||
const orderItems = order.items || [] // 这里的 items 已经在 checkout 存入时有了
|
||
|
||
// 为每个商品项加载图片
|
||
// const itemsWithImages = await Promise.all(
|
||
// orderItems.map(async (item: any) => {
|
||
// const productImage = await getProductImage(item.product_id)
|
||
// return {
|
||
// ...item,
|
||
// product_image: productImage
|
||
// }
|
||
// })
|
||
// )
|
||
// 本地存储的 items 应该已经有 image 字段了,如果没有,再尝试获取
|
||
const itemsWithImages = orderItems.map((item: any) => {
|
||
return {
|
||
...item,
|
||
product_image: item.product_image || item.image || '/static/default-product.png',
|
||
product_name: item.product_name || item.name // 兼容不同字段名
|
||
}
|
||
})
|
||
|
||
processed.push({
|
||
...order,
|
||
items: itemsWithImages
|
||
})
|
||
}
|
||
|
||
return processed
|
||
}
|
||
|
||
// 获取商品图片
|
||
const getProductImage = async (productId: string): Promise<string> => {
|
||
try {
|
||
const { data, error } = await supa
|
||
.from('products')
|
||
.select('images')
|
||
.eq('id', productId)
|
||
.single()
|
||
|
||
if (error !== null) {
|
||
console.error('获取商品图片失败:', error)
|
||
return '/static/default-product.png'
|
||
}
|
||
|
||
return data?.images?.[0] || '/static/default-product.png'
|
||
} catch (err) {
|
||
console.error('获取商品图片异常:', err)
|
||
return '/static/default-product.png'
|
||
}
|
||
}
|
||
|
||
// 获取当前用户ID
|
||
const getCurrentUserId = (): string | null => {
|
||
const userStore = uni.getStorageSync('userInfo')
|
||
return userStore?.id || null
|
||
}
|
||
|
||
// 获取状态文本
|
||
const getStatusText = (status: number): string => {
|
||
const statusMap: Record<number, string> = {
|
||
1: '待支付',
|
||
2: '待发货',
|
||
3: '待收货',
|
||
4: '已完成',
|
||
5: '已取消'
|
||
}
|
||
return statusMap[status] || '未知状态'
|
||
}
|
||
|
||
// 获取状态样式类
|
||
const getStatusClass = (status: number): string => {
|
||
const classMap: Record<number, string> = {
|
||
1: 'status-pending',
|
||
2: 'status-shipping',
|
||
3: 'status-receiving',
|
||
4: 'status-completed',
|
||
5: 'status-cancelled'
|
||
}
|
||
return classMap[status] || 'status-unknown'
|
||
}
|
||
|
||
// 获取规格文本
|
||
const getSpecText = (specs: any): string => {
|
||
if (!specs) return ''
|
||
if (typeof specs === 'object') {
|
||
return Object.keys(specs)
|
||
.map(key => `${key}: ${specs[key]}`)
|
||
.join('; ')
|
||
}
|
||
return String(specs)
|
||
}
|
||
|
||
// 格式化时间
|
||
const formatTime = (timeStr: string): string => {
|
||
const date = new Date(timeStr)
|
||
const year = date.getFullYear()
|
||
const month = (date.getMonth() + 1).toString().padStart(2, '0')
|
||
const day = date.getDate().toString().padStart(2, '0')
|
||
const hour = date.getHours().toString().padStart(2, '0')
|
||
const minute = date.getMinutes().toString().padStart(2, '0')
|
||
return `${year}-${month}-${day} ${hour}:${minute}`
|
||
}
|
||
|
||
// 计算商品总数
|
||
const getTotalQuantity = (items: OrderItemType[]): number => {
|
||
return items.reduce((total, item) => total + item.quantity, 0)
|
||
}
|
||
|
||
// 返回主页
|
||
const goBackToHome = () => {
|
||
uni.switchTab({
|
||
url: '/pages/mall/consumer/index'
|
||
})
|
||
}
|
||
|
||
// 导航到搜索页面
|
||
const navigateToSearch = () => {
|
||
uni.navigateTo({
|
||
url: '/pages/mall/consumer/search'
|
||
})
|
||
}
|
||
|
||
// 监听手机返回键
|
||
onBackPress(() => {
|
||
goBackToHome()
|
||
return true // 阻止默认返回行为
|
||
})
|
||
|
||
// 标签页切换
|
||
const changeTab = (tab: string) => {
|
||
activeTab.value = tab
|
||
}
|
||
|
||
// 加载更多
|
||
const loadMore = () => {
|
||
if (hasMore.value && !isLoading.value) {
|
||
loadOrders(true)
|
||
}
|
||
}
|
||
|
||
// 查看订单详情
|
||
const viewOrderDetail = (order: FullOrderType) => {
|
||
uni.navigateTo({
|
||
url: `/pages/mall/consumer/order-detail?id=${order.id}`
|
||
})
|
||
}
|
||
|
||
// 支付订单
|
||
const payOrder = (order: FullOrderType) => {
|
||
uni.navigateTo({
|
||
url: `/pages/mall/consumer/payment?orderId=${order.id}&amount=${order.actual_amount}`
|
||
})
|
||
}
|
||
|
||
// 取消订单
|
||
const cancelOrder = async (order: FullOrderType) => {
|
||
uni.showModal({
|
||
title: '取消订单',
|
||
content: '确定要取消这个订单吗?',
|
||
success: async (res) => {
|
||
if (res.confirm) {
|
||
try {
|
||
const { error } = await supa
|
||
.from('orders')
|
||
.update({ status: 5 })
|
||
.eq('id', order.id)
|
||
|
||
if (error !== null) {
|
||
console.error('取消订单失败:', error)
|
||
uni.showToast({
|
||
title: '取消失败',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
order.status = 5
|
||
loadOrderCounts() // 重新加载统计
|
||
|
||
uni.showToast({
|
||
title: '订单已取消',
|
||
icon: 'success'
|
||
})
|
||
} catch (err) {
|
||
console.error('取消订单异常:', err)
|
||
}
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
// 提醒发货
|
||
const remindShipment = (order: FullOrderType) => {
|
||
uni.showToast({
|
||
title: '已提醒商家发货',
|
||
icon: 'success'
|
||
})
|
||
}
|
||
|
||
// 确认收货
|
||
const confirmReceipt = async (order: FullOrderType) => {
|
||
uni.showModal({
|
||
title: '确认收货',
|
||
content: '确认已收到商品吗?',
|
||
success: async (res) => {
|
||
if (res.confirm) {
|
||
try {
|
||
const { error } = await supa
|
||
.from('orders')
|
||
.update({ status: 4 })
|
||
.eq('id', order.id)
|
||
|
||
if (error !== null) {
|
||
console.error('确认收货失败:', error)
|
||
uni.showToast({
|
||
title: '确认失败',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
order.status = 4
|
||
loadOrderCounts() // 重新加载统计
|
||
|
||
uni.showToast({
|
||
title: '确认收货成功',
|
||
icon: 'success'
|
||
})
|
||
} catch (err) {
|
||
console.error('确认收货异常:', err)
|
||
}
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
// 去评价
|
||
const goToReview = (order: FullOrderType) => {
|
||
uni.navigateTo({
|
||
url: `/pages/mall/consumer/review?orderId=${order.id}`
|
||
})
|
||
}
|
||
|
||
// 删除订单
|
||
const deleteOrder = async (order: FullOrderType) => {
|
||
uni.showModal({
|
||
title: '删除订单',
|
||
content: '确定要删除这个订单吗?删除后将无法恢复',
|
||
success: async (res) => {
|
||
if (res.confirm) {
|
||
try {
|
||
const { error } = await supa
|
||
.from('orders')
|
||
.delete()
|
||
.eq('id', order.id)
|
||
|
||
if (error !== null) {
|
||
console.error('删除订单失败:', error)
|
||
uni.showToast({
|
||
title: '删除失败',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
const index = orders.value.findIndex(o => o.id === order.id)
|
||
if (index !== -1) {
|
||
orders.value.splice(index, 1)
|
||
orders.value = [...orders.value]
|
||
}
|
||
|
||
uni.showToast({
|
||
title: '删除成功',
|
||
icon: 'success'
|
||
})
|
||
} catch (err) {
|
||
console.error('删除订单异常:', err)
|
||
}
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
// 再次购买
|
||
const reBuy = async (order: FullOrderType) => {
|
||
// 将订单商品加入购物车
|
||
const userId = getCurrentUserId()
|
||
if (!userId) return
|
||
|
||
try {
|
||
const addPromises = order.items.map(item =>
|
||
supa
|
||
.from('shopping_cart')
|
||
.upsert({
|
||
user_id: userId,
|
||
product_id: item.product_id,
|
||
sku_id: null, // 这里需要获取SKU ID
|
||
quantity: item.quantity
|
||
})
|
||
)
|
||
|
||
await Promise.all(addPromises)
|
||
|
||
uni.showToast({
|
||
title: '已加入购物车',
|
||
icon: 'success'
|
||
})
|
||
} catch (err) {
|
||
console.error('再次购买异常:', err)
|
||
uni.showToast({
|
||
title: '操作失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
}
|
||
|
||
// 联系客服
|
||
const contactService = (order: FullOrderType) => {
|
||
uni.navigateTo({
|
||
url: `/pages/mall/service/chat?orderId=${order.id}`
|
||
})
|
||
}
|
||
|
||
// 去逛逛
|
||
const goShopping = () => {
|
||
uni.switchTab({
|
||
url: '/pages/mall/consumer/index'
|
||
})
|
||
}
|
||
|
||
// 导航方法
|
||
const goToHome = () => {
|
||
uni.switchTab({
|
||
url: '/pages/mall/consumer/index'
|
||
})
|
||
}
|
||
|
||
const goToCategory = () => {
|
||
uni.switchTab({
|
||
url: '/pages/mall/consumer/category'
|
||
})
|
||
}
|
||
|
||
const goToProfile = () => {
|
||
uni.switchTab({
|
||
url: '/pages/mall/consumer/profile'
|
||
})
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.orders-page {
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100vh;
|
||
background-color: #f5f5f5;
|
||
}
|
||
|
||
.orders-header {
|
||
background-color: #ffffff;
|
||
padding: 15px;
|
||
border-bottom: 1px solid #e5e5e5;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.header-left {
|
||
flex: 1;
|
||
}
|
||
|
||
.header-title {
|
||
font-size: 18px;
|
||
font-weight: bold;
|
||
color: #333333;
|
||
}
|
||
|
||
.header-right {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.search-icon {
|
||
font-size: 20px;
|
||
color: #333333;
|
||
padding: 5px;
|
||
}
|
||
|
||
.order-tabs {
|
||
background-color: #ffffff;
|
||
display: flex;
|
||
flex-direction: row;
|
||
border-bottom: 1px solid #e5e5e5;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.order-tab {
|
||
flex: 1;
|
||
padding: 15px 0;
|
||
text-align: center;
|
||
position: relative;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
|
||
.order-tab.active {
|
||
color: #007aff;
|
||
border-bottom: 2px solid #007aff;
|
||
}
|
||
|
||
.tab-text {
|
||
font-size: 14px;
|
||
color: #666666;
|
||
}
|
||
|
||
.order-tab.active .tab-text {
|
||
color: #007aff;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.tab-badge {
|
||
position: absolute;
|
||
top: 8px;
|
||
right: 5px;
|
||
background-color: #ff4757;
|
||
color: #ffffff;
|
||
font-size: 10px;
|
||
padding: 2px 5px;
|
||
border-radius: 8px;
|
||
min-width: 16px;
|
||
text-align: center;
|
||
}
|
||
|
||
.orders-list {
|
||
flex: 1;
|
||
}
|
||
|
||
.empty-orders {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 80px 20px;
|
||
background-color: #ffffff;
|
||
}
|
||
|
||
.empty-icon {
|
||
font-size: 80px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.empty-text {
|
||
font-size: 16px;
|
||
color: #666666;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.empty-subtext {
|
||
font-size: 14px;
|
||
color: #999999;
|
||
margin-bottom: 30px;
|
||
}
|
||
|
||
.go-shopping-btn {
|
||
background-color: #007aff;
|
||
color: #ffffff;
|
||
padding: 10px 40px;
|
||
border-radius: 25px;
|
||
font-size: 14px;
|
||
border: none;
|
||
}
|
||
|
||
.order-item {
|
||
background-color: #ffffff;
|
||
margin-bottom: 10px;
|
||
padding: 15px;
|
||
}
|
||
|
||
.order-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 15px;
|
||
padding-bottom: 10px;
|
||
border-bottom: 1px solid #f5f5f5;
|
||
}
|
||
|
||
.order-no {
|
||
font-size: 14px;
|
||
color: #333333;
|
||
}
|
||
|
||
.order-status {
|
||
font-size: 14px;
|
||
padding: 4px 10px;
|
||
border-radius: 12px;
|
||
}
|
||
|
||
.status-pending {
|
||
background-color: #ffa726;
|
||
color: #ffffff;
|
||
}
|
||
|
||
.status-shipping {
|
||
background-color: #2196f3;
|
||
color: #ffffff;
|
||
}
|
||
|
||
.status-receiving {
|
||
background-color: #9c27b0;
|
||
color: #ffffff;
|
||
}
|
||
|
||
.status-completed {
|
||
background-color: #4caf50;
|
||
color: #ffffff;
|
||
}
|
||
|
||
.status-cancelled {
|
||
background-color: #9e9e9e;
|
||
color: #ffffff;
|
||
}
|
||
|
||
.order-products {
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.product-item {
|
||
display: flex;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.product-item:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.product-image {
|
||
width: 60px;
|
||
height: 60px;
|
||
border-radius: 5px;
|
||
margin-right: 10px;
|
||
}
|
||
|
||
.product-info {
|
||
flex: 1;
|
||
}
|
||
|
||
.product-name {
|
||
font-size: 13px;
|
||
color: #333333;
|
||
line-height: 1.4;
|
||
margin-bottom: 5px;
|
||
display: -webkit-box;
|
||
-webkit-box-orient: vertical;
|
||
-webkit-line-clamp: 2;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.product-spec {
|
||
font-size: 12px;
|
||
color: #999999;
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.product-price-row {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.product-price {
|
||
font-size: 14px;
|
||
color: #ff4757;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.product-quantity {
|
||
font-size: 12px;
|
||
color: #666666;
|
||
}
|
||
|
||
.order-info {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 15px;
|
||
padding-top: 10px;
|
||
border-top: 1px solid #f5f5f5;
|
||
}
|
||
|
||
.order-time {
|
||
font-size: 12px;
|
||
color: #999999;
|
||
}
|
||
|
||
.order-total {
|
||
font-size: 14px;
|
||
color: #333333;
|
||
}
|
||
|
||
.total-amount {
|
||
font-size: 16px;
|
||
color: #ff4757;
|
||
font-weight: bold;
|
||
margin-left: 5px;
|
||
}
|
||
|
||
.order-actions {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
gap: 10px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.action-btn {
|
||
padding: 8px 15px;
|
||
border-radius: 15px;
|
||
font-size: 12px;
|
||
border: 1px solid;
|
||
background-color: #ffffff;
|
||
}
|
||
|
||
.action-btn.pay {
|
||
border-color: #ff4757;
|
||
color: #ff4757;
|
||
}
|
||
|
||
.action-btn.cancel {
|
||
border-color: #666666;
|
||
color: #666666;
|
||
}
|
||
|
||
.action-btn.remind {
|
||
border-color: #2196f3;
|
||
color: #2196f3;
|
||
}
|
||
|
||
.action-btn.confirm {
|
||
border-color: #4caf50;
|
||
color: #4caf50;
|
||
}
|
||
|
||
.action-btn.review {
|
||
border-color: #ffa726;
|
||
color: #ffa726;
|
||
}
|
||
|
||
.action-btn.delete {
|
||
border-color: #9e9e9e;
|
||
color: #9e9e9e;
|
||
}
|
||
|
||
.action-btn.rebuy {
|
||
border-color: #007aff;
|
||
color: #007aff;
|
||
}
|
||
|
||
.action-btn.service {
|
||
border-color: #9c27b0;
|
||
color: #9c27b0;
|
||
}
|
||
|
||
.loading-more,
|
||
.no-more {
|
||
padding: 20px;
|
||
text-align: center;
|
||
background-color: #ffffff;
|
||
}
|
||
|
||
.loading-text,
|
||
.no-more-text {
|
||
color: #999999;
|
||
font-size: 14px;
|
||
}
|
||
|
||
/* 底部导航栏 */
|
||
.bottom-navigation {
|
||
position: fixed;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: 50px;
|
||
background: #ffffff;
|
||
display: flex;
|
||
justify-content: space-around;
|
||
align-items: center;
|
||
border-top: 1px solid #f0f0f0;
|
||
padding-bottom: constant(safe-area-inset-bottom);
|
||
padding-bottom: env(safe-area-inset-bottom);
|
||
z-index: 100;
|
||
}
|
||
|
||
.nav-item {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 100%;
|
||
}
|
||
|
||
.nav-icon {
|
||
font-size: 24px;
|
||
margin-bottom: 2px;
|
||
}
|
||
|
||
.nav-text {
|
||
font-size: 10px;
|
||
color: #999;
|
||
}
|
||
|
||
.nav-item.active .nav-text {
|
||
color: #4CAF50;
|
||
font-weight: 500;
|
||
}
|
||
</style>
|