Files
medical-mall/pages/mall/consumer/profile.uvue

1203 lines
31 KiB
Plaintext
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="consumer-profile">
<!-- 智能顶部导航栏 - 与消息页保持一致 -->
<view class="smart-navbar" :style="{ paddingTop: statusBarHeight + 'px' }">
<view class="nav-container">
<!-- 头像 -->
<image
:src="userInfo.avatar_url || '/static/default-avatar.png'"
class="nav-avatar"
@click="editProfile"
/>
<!-- 用户信息横向排列 (名字、积分、余额、优惠券) -->
<view class="nav-user-stats">
<text class="nav-user-name">{{ userInfo.nickname || userInfo.phone }}</text>
<view class="nav-stat-item" @click="goToPoints">
<text class="nav-stat-label">积分</text>
<text class="nav-stat-value">{{ userStats.points }}</text>
</view>
<view class="nav-stat-item" @click="goToWallet">
<text class="nav-stat-label">余额</text>
<text class="nav-stat-value">¥{{ userStats.balance }}</text>
</view>
<view class="nav-stat-item" @click="goToCoupons">
<text class="nav-stat-label">券</text>
<text class="nav-stat-value">{{ serviceCounts.coupons }}</text>
</view>
</view>
<!-- 设置按钮 (右侧) -->
<view class="nav-actions">
<view class="action-btn" @click="goToSettings">
<text class="action-icon">⚙️</text>
</view>
</view>
</view>
</view>
<!-- 导航栏占位符 - 恢复 -->
<view :style="{ height: (statusBarHeight + 10) + 'px' }"></view>
<!-- 我的服务 (移到订单上方) -->
<view class="my-services" style="margin-top: 10px;">
<view class="section-title">我的服务</view>
<view class="service-grid">
<view class="service-item" @click="goToCoupons">
<text class="service-icon">🎫</text>
<text class="service-text">优惠券</text>
<text v-if="serviceCounts.coupons > 0" class="service-badge">{{ serviceCounts.coupons }}</text>
</view>
<view class="service-item" @click="goToAddress">
<text class="service-icon">📍</text>
<text class="service-text">收货地址</text>
</view>
<view class="service-item" @click="goToFavorites">
<text class="service-icon">❤️</text>
<text class="service-text">我的收藏</text>
<text v-if="serviceCounts.favorites > 0" class="service-badge">{{ serviceCounts.favorites }}</text>
</view>
<view class="service-item" @click="goToFootprint">
<text class="service-icon">👣</text>
<text class="service-text">浏览足迹</text>
</view>
<view class="service-item" @click="goToRefund">
<text class="service-icon">🔄</text>
<text class="service-text">退款/售后</text>
</view>
<view class="service-item" @click="goToOrderReviews">
<text class="service-icon">📝</text>
<text class="service-text">评价</text>
</view>
<view class="service-item" @click="goToMySubscriptions">
<text class="service-icon">🧩</text>
<text class="service-text">我的订阅</text>
</view>
<view class="service-item" @click="goToSubscriptions">
<text class="service-icon">📱</text>
<text class="service-text">软件订阅</text>
</view>
</view>
</view>
<!-- 订单状态快捷入口 -->
<view class="order-shortcuts">
<view class="section-title">我的订单</view>
<view class="order-tabs">
<view class="order-tab" :class="{ active: currentOrderTab === 'all' }" @click="switchOrderTab('all')">
<text class="tab-icon">📋</text>
<text class="tab-text">全部</text>
<text v-if="orderCounts.total > 0" class="tab-badge">{{ orderCounts.total }}</text>
</view>
<view class="order-tab" :class="{ active: currentOrderTab === 'pending' }" @click="switchOrderTab('pending')">
<text class="tab-icon">💰</text>
<text class="tab-text">待支付</text>
<text v-if="orderCounts.pending > 0" class="tab-badge">{{ orderCounts.pending }}</text>
</view>
<view class="order-tab" :class="{ active: currentOrderTab === 'toship' }" @click="switchOrderTab('toship')">
<text class="tab-icon">🚚</text>
<text class="tab-text">待发货</text>
<text v-if="orderCounts.toship > 0" class="tab-badge">{{ orderCounts.toship }}</text>
</view>
<view class="order-tab" :class="{ active: currentOrderTab === 'shipped' }" @click="switchOrderTab('shipped')">
<text class="tab-icon">📦</text>
<text class="tab-text">待收货</text>
<text v-if="orderCounts.shipped > 0" class="tab-badge">{{ orderCounts.shipped }}</text>
</view>
</view>
</view>
<!-- 最近订单列表 (根据Tab切换显示) -->
<view class="recent-orders">
<view class="section-header">
<text class="section-title">{{ getOrderSectionTitle() }}</text>
<text class="view-all" @click="goToOrders(currentOrderTab)">查看更多 ></text>
</view>
<view v-if="filteredOrders.length === 0" class="empty-orders">
<text class="empty-text">暂无相关订单记录</text>
<button class="start-shopping" @click="goShopping">去逛逛</button>
</view>
<view v-for="order in filteredOrders" :key="order.id" class="order-item" @click="viewOrderDetail(order)">
<view class="order-header">
<text class="order-no">订单号: {{ order.order_no }}</text>
<text class="order-status" :class="getOrderStatusClass(order.status)">{{ getOrderStatusText(order.status) }}</text>
</view>
<view class="order-content">
<image :src="getOrderMainImage(order)" class="order-image" mode="aspectFill" />
<view class="order-info">
<text class="order-title">{{ getOrderTitle(order) }}</text>
<text class="order-amount">¥{{ order.actual_amount }}</text>
<text class="order-time">{{ formatTime(order.created_at) }}</text>
</view>
</view>
<view class="order-actions">
<button v-if="order.status === 1" class="action-btn pay" @click.stop="payOrder(order)">立即支付</button>
<button v-if="order.status === 3" class="action-btn confirm" @click.stop="confirmReceive(order)">确认收货</button>
<button v-if="order.status === 4" class="action-btn review" @click.stop="reviewOrder(order)">评价</button>
</view>
</view>
</view>
<!-- 我的服务 -->
<!-- <view class="my-services">
<view class="section-title">我的服务</view>
<view class="service-grid">
<view class="service-item" @click="goToCoupons">
<text class="service-icon">🎫</text>
<text class="service-text">优惠券</text>
<text v-if="serviceCounts.coupons > 0" class="service-badge">{{ serviceCounts.coupons }}</text>
</view>
<view class="service-item" @click="goToAddress">
<text class="service-icon">📍</text>
<text class="service-text">收货地址</text>
</view>
<view class="service-item" @click="goToFavorites">
<text class="service-icon">❤️</text>
<text class="service-text">我的收藏</text>
<text v-if="serviceCounts.favorites > 0" class="service-badge">{{ serviceCounts.favorites }}</text>
</view>
<view class="service-item" @click="goToFootprint">
<text class="service-icon">👣</text>
<text class="service-text">浏览足迹</text>
</view>
<view class="service-item" @click="goToRefund">
<text class="service-icon">🔄</text>
<text class="service-text">退款/售后</text>
</view>
<view class="service-item" @click="contactService">
<text class="service-icon">💬</text>
<text class="service-text">在线客服</text>
</view>
<view class="service-item" @click="goToMySubscriptions">
<text class="service-icon">🧩</text>
<text class="service-text">我的订阅</text>
</view>
<view class="service-item" @click="goToSubscriptions">
<text class="service-icon">🧩</text>
<text class="service-text">软件订阅</text>
</view>
</view>
</view> -->
<!-- 消费统计 -->
<view class="consumption-stats">
<view class="section-title">消费统计</view>
<view class="stats-period">
<text v-for="period in statsPeriods" :key="period.key"
class="period-tab"
:class="{ active: activeStatsPeriod === period.key }"
@click="switchStatsPeriod(period.key)">{{ period.label }}</text>
</view>
<view class="stats-content">
<view class="stat-card">
<text class="stat-value">¥{{ currentStats.total_amount }}</text>
<text class="stat-label">总消费</text>
</view>
<view class="stat-card">
<text class="stat-value">{{ currentStats.order_count }}</text>
<text class="stat-label">订单数</text>
</view>
<view class="stat-card">
<text class="stat-value">¥{{ currentStats.avg_amount }}</text>
<text class="stat-label">平均消费</text>
</view>
<view class="stat-card">
<text class="stat-value">{{ currentStats.save_amount }}</text>
<text class="stat-label">节省金额</text>
</view>
</view>
</view>
<!-- 账户安全 -->
<!-- <view class="account-security">
<view class="section-title">账户安全</view>
<view class="security-items">
<view class="security-item" @click="changePassword">
<text class="security-icon">🔒</text>
<text class="security-text">修改密码</text>
<text class="security-arrow">></text>
</view>
<view class="security-item" @click="bindPhone">
<text class="security-icon">📱</text>
<text class="security-text">手机绑定</text>
<view class="security-status">
<text class="status-text" :class="{ bound: userInfo.phone }">{{ userInfo.phone ? '已绑定' : '未绑定' }}</text>
<text class="security-arrow">></text>
</view>
</view>
<view class="security-item" @click="bindEmail">
<text class="security-icon">📧</text>
<text class="security-text">邮箱绑定</text>
<view class="security-status">
<text class="status-text" :class="{ bound: userInfo.email }">{{ userInfo.email ? '已绑定' : '未绑定' }}</text>
<text class="security-arrow">></text>
</view>
</view>
</view>
</view> -->
</view>
</template>
<script>
import { UserType, OrderType } from '@/types/mall-types.uts'
import supabaseService from '@/utils/supabaseService.uts'
import { getCurrentUser } from '@/utils/store.uts'
type UserStatsType = {
points: number
balance: number
level: number
}
type OrderCountsType = {
total: number
pending: number
toship: number
shipped: number
}
type ServiceCountsType = {
coupons: number
favorites: number
}
type ConsumptionStatsType = {
total_amount: number
order_count: number
avg_amount: number
save_amount: number
}
type StatsPeriodType = {
key: string
label: string
}
export default {
data() {
return {
userInfo: {
id: '',
phone: '',
email: '',
nickname: '',
avatar_url: '',
gender: 0,
user_type: 0,
status: 0,
created_at: ''
} as UserType,
userStats: {
points: 0,
balance: 0,
level: 1
} as UserStatsType,
orderCounts: {
total: 0,
pending: 0,
toship: 0,
shipped: 0,
} as any,
serviceCounts: {
coupons: 0,
favorites: 0
} as ServiceCountsType,
recentOrders: [] as Array<OrderType>,
statsPeriods: [
{ key: 'month', label: '本月' },
{ key: 'quarter', label: '本季度' },
{ key: 'year', label: '本年' },
{ key: 'all', label: '全部' }
] as Array<StatsPeriodType>,
activeStatsPeriod: 'month',
currentStats: {
total_amount: 0,
order_count: 0,
avg_amount: 0,
save_amount: 0
} as ConsumptionStatsType,
statusBarHeight: 0,
currentOrderTab: 'all' as string, // 当前选中的订单Tab
allOrders: [] as Array<OrderType> // 存储所有订单数据
}
},
onLoad() {
this.initPage()
this.loadUserProfile()
this.loadOrders()
// 监听订单更新事件
uni.$on('orderUpdated', this.handleOrderUpdated)
},
onShow() {
this.refreshData()
},
onUnload() {
// 移除事件监听
uni.$off('orderUpdated', this.handleOrderUpdated)
},
computed: {
// 根据当前Tab筛选订单
filteredOrders(): Array<OrderType> {
if (this.currentOrderTab === 'all') {
return this.allOrders
} else if (this.currentOrderTab === 'pending') {
return this.allOrders.filter((order: OrderType): boolean => order.status === 1)
} else if (this.currentOrderTab === 'toship') {
return this.allOrders.filter((order: OrderType): boolean => order.status === 2)
} else if (this.currentOrderTab === 'shipped') {
return this.allOrders.filter((order: OrderType): boolean => order.status === 3)
} else if (this.currentOrderTab === 'review') {
return this.allOrders.filter((order: OrderType): boolean => order.status === 4)
}
return []
}
},
methods: {
// 加载订单数据
async loadOrders() {
try {
const orders = await supabaseService.getOrders()
// 映射数据库字段到前端类型
this.allOrders = orders.map((o: any): OrderType => {
// 确保 status 字段存在
if (o['status'] == null && o['order_status'] != null) {
o['status'] = o['order_status']
}
// 确保 actual_amount 存在
if (o['actual_amount'] == null && o['total_amount'] != null) {
o['actual_amount'] = o['total_amount']
}
return o as OrderType
})
// 按时间倒序 (created_at)
this.allOrders.sort((a: any, b: any) => {
const timeA = new Date(a.created_at || 0).getTime()
const timeB = new Date(b.created_at || 0).getTime()
return timeB - timeA
})
// 过滤最近的订单
this.recentOrders = this.allOrders.slice(0, 5)
// 更新角标统计 (确保状态码一致: 1=待支付, 2=待发货, 3=待收货, 4=待评价)
this.orderCounts = {
total: this.allOrders.length,
pending: this.allOrders.filter((o: any) => o.status === 1).length,
toship: this.allOrders.filter((o: any) => o.status === 2).length,
shipped: this.allOrders.filter((o: any) => o.status === 3).length,
review: this.allOrders.filter((o: any) => o.status === 4).length
}
} catch (e) {
console.error('加载订单异常', e)
}
},
// 切换订单Tab
switchOrderTab(tab: string) {
this.currentOrderTab = tab
},
// 获取当前订单部分标题
getOrderSectionTitle(): string {
const titles: Record<string, string> = {
'all': '全部订单',
'pending': '待支付订单',
'shipped': '待收货订单',
'review': '待评价订单'
}
return titles[this.currentOrderTab] || '我的订单'
},
initPage() {
const systemInfo = uni.getSystemInfoSync()
this.statusBarHeight = systemInfo.statusBarHeight || 0
},
loadUserProfile() {
// 模拟加载用户信息
this.userInfo = {
id: 'user_001',
phone: '13800138000',
email: 'user@example.com',
nickname: '张三',
avatar_url: '/static/avatar1.jpg',
gender: 1,
user_type: 1,
status: 1,
created_at: '2023-06-15T10:30:00'
}
this.userStats = {
points: 1580,
balance: 268.50,
level: 3
}
// orderCounts 将通过 loadOrders 从真实数据获取
// init with zeros
this.orderCounts = {
total: 0,
pending: 0,
toship: 0,
shipped: 0,
review: 0
}
this.serviceCounts = {
coupons: 5,
favorites: 12
}
// recentOrders 将通过 loadOrders 从真实数据获取
this.recentOrders = []
this.loadConsumptionStats()
},
loadConsumptionStats() {
// 模拟加载消费统计数据
const statsData: Record<string, ConsumptionStatsType> = {
month: {
total_amount: 1280.50,
order_count: 8,
avg_amount: 160.06,
save_amount: 85.20
},
quarter: {
total_amount: 3680.80,
order_count: 18,
avg_amount: 204.49,
save_amount: 256.30
},
year: {
total_amount: 15680.90,
order_count: 56,
avg_amount: 280.02,
save_amount: 986.50
},
all: {
total_amount: 25680.50,
order_count: 89,
avg_amount: 288.55,
save_amount: 1580.20
}
}
this.currentStats = statsData[this.activeStatsPeriod]
},
refreshData() {
// 刷新页面数据
this.loadUserProfile()
this.loadOrders()
this.updateCouponCount() // 更新优惠券数量
},
updateCouponCount() {
// 从本地存储读取领取的优惠券数量并叠加到基础数量上
const baseCoupons = 5
const claimedCoupons = uni.getStorageSync('claimedCoupons') || 0
this.serviceCounts.coupons = baseCoupons + (claimedCoupons as number)
},
getUserLevel(): string {
const levels = ['新手', '铜牌会员', '银牌会员', '金牌会员', '钻石会员']
return levels[this.userStats.level] || '新手'
},
getOrderStatusText(status: number): string {
const statusTexts = ['异常', '待支付', '待发货', '待收货', '已完成', '已取消']
return statusTexts[status] || '未知'
},
getOrderStatusClass(status: number): string {
const statusClasses = ['error', 'pending', 'processing', 'shipping', 'completed', 'cancelled']
return statusClasses[status] || 'error'
},
getOrderMainImage(order: any): string {
// 尝试从 ml_order_items 获取第一张图
const items = order['ml_order_items'] as any[]
if (items && items.length > 0) {
const firstItem = items[0]
// 数据库字段通常是 image_url
const img = firstItem['image_url'] || firstItem['product_image']
if (img) return img as string
}
return '/static/product1.jpg'
},
getOrderTitle(order: any): string {
const items = order['ml_order_items'] as any[]
if (items && items.length > 0) {
const firstItem = items[0]
const name = (firstItem['product_name'] || '商品') as string
if (items.length > 1) {
return `${name} 等${items.length}件商品`
}
return name
}
return '精选商品'
},
formatTime(timeStr: string): string {
const date = new Date(timeStr)
const now = new Date()
const diff = now.getTime() - date.getTime()
const days = Math.floor(diff / (1000 * 60 * 60 * 24))
if (days === 0) {
return '今天'
} else if (days === 1) {
return '昨天'
} else {
return `${days}天前`
}
},
switchStatsPeriod(period: string) {
this.activeStatsPeriod = period
this.loadConsumptionStats()
},
editProfile() {
uni.navigateTo({
url: '/pages/mall/consumer/edit-profile'
})
},
// 跳转设置
goToSettings() {
uni.navigateTo({
url: '/pages/mall/consumer/settings'
})
},
// 跳转钱包
goToWallet() {
const user = getCurrentUser()
if (!user) {
uni.showToast({
title: '请先登录',
icon: 'none'
})
uni.navigateTo({
url: '/pages/user/login'
})
return
}
uni.navigateTo({
url: '/pages/mall/consumer/wallet'
})
},
// 跳转积分
goToPoints() {
const user = getCurrentUser()
if (!user) {
uni.showToast({
title: '请先登录',
icon: 'none'
})
uni.navigateTo({
url: '/pages/user/login'
})
return
}
uni.navigateTo({
url: '/pages/mall/consumer/points'
})
},
goToOrders(type: string) {
uni.navigateTo({
url: `/pages/mall/consumer/orders?type=${type}`
})
},
goShopping() {
uni.switchTab({
url: '/pages/mall/consumer/index'
})
},
viewOrderDetail(order: OrderType) {
uni.navigateTo({
url: `/pages/mall/consumer/order-detail?orderId=${order.id}`
})
},
payOrder(order: OrderType) {
uni.navigateTo({
url: `/pages/mall/consumer/payment?orderId=${order.id}`
})
},
confirmReceive(order: OrderType) {
uni.showModal({
title: '确认收货',
content: '确认已收到商品吗?',
success: (res) => {
if (res.confirm) {
uni.showToast({
title: '确认收货成功',
icon: 'success'
})
this.refreshData()
}
}
})
},
reviewOrder(order: OrderType) {
uni.navigateTo({
url: `/pages/mall/consumer/review?orderId=${order.id}`
})
},
goToCoupons() {
uni.navigateTo({
url: '/pages/mall/consumer/coupons'
})
},
goToAddress() {
// 暂时跳转到设置页的地址管理
uni.navigateTo({
url: '/pages/mall/consumer/address-list'
})
},
goToFavorites() {
uni.navigateTo({
url: '/pages/mall/consumer/favorites'
})
},
goToFootprint() {
uni.navigateTo({
url: '/pages/mall/consumer/footprint'
})
},
goToRefund() {
uni.navigateTo({
url: '/pages/mall/consumer/orders?type=refund'
})
},
contactService() {
uni.navigateTo({
url: '/pages/mall/service/chat'
})
},
goToOrderReviews() {
uni.navigateTo({
url: '/pages/mall/consumer/orders?type=review'
})
},
goToMySubscriptions() {
uni.navigateTo({
url: '/pages/mall/consumer/subscription/my-subscriptions'
})
},
goToSubscriptions() {
uni.navigateTo({
url: '/pages/mall/consumer/subscription/plan-list'
})
},
changePassword() {
uni.navigateTo({
url: '/pages/mall/consumer/change-password'
})
},
bindPhone() {
uni.navigateTo({
url: '/pages/mall/consumer/bind-phone'
})
},
bindEmail() {
uni.navigateTo({
url: '/pages/mall/consumer/bind-email'
})
},
// 处理订单更新事件
handleOrderUpdated(data: any) {
// 当收到订单更新事件时,刷新订单数据
console.log('收到订单更新事件:', data)
this.refreshData()
// 显示提示
if (data.status === 1) {
uni.showToast({
title: '订单已保存到待支付',
icon: 'success'
})
} else if (data.status === 2) {
uni.showToast({
title: '支付成功,订单待发货',
icon: 'success'
})
}
}
}
}
</script>
<style>
.consumer-profile {
background-color: #f5f5f5;
min-height: 100vh;
}
/* 智能顶部导航栏 */
.smart-navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
background: linear-gradient(135deg, #4CAF50 0%, #2E7D32 100%);
z-index: 1000;
box-shadow: 0 2px 12px rgba(76, 175, 80, 0.15);
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.nav-container {
padding: 0 16px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
width: 100%;
max-width: 1400px;
margin: 0 auto;
height: 44px;
}
/* 导航栏用户信息区域 */
.nav-user-stats {
flex: 1;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start; /* 靠左对齐,紧跟头像 */
margin-right: 12px;
overflow: hidden; /* 防止溢出 */
}
.nav-user-name {
font-size: 16px;
font-weight: bold;
color: white;
margin-right: 12px;
max-width: 30%; /* 限制名字宽度 */
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.nav-stat-item {
display: flex;
flex-direction: row;
align-items: center;
background: rgba(255, 255, 255, 0.2);
border-radius: 12px;
padding: 2px 8px;
margin-right: 8px;
flex-shrink: 0; /* 防止被压缩 */
}
.nav-stat-label {
font-size: 11px;
color: rgba(255, 255, 255, 0.9);
margin-right: 4px;
}
.nav-stat-value {
font-size: 12px;
font-weight: bold;
color: white;
}
.nav-avatar {
width: 36px;
height: 36px;
border-radius: 18px;
border: 2px solid rgba(255, 255, 255, 0.8);
margin-right: 12px;
flex-shrink: 0;
}
.nav-actions {
display: flex;
flex-direction: row;
align-items: center;
flex-shrink: 0;
}
.action-btn {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
background: rgba(255, 255, 255, 0.2);
border-radius: 16px;
cursor: pointer;
}
.action-icon {
font-size: 18px;
color: white;
}
/* 导航栏占位符 */
.navbar-placeholder {
width: 100%;
flex-shrink: 0;
}
.order-shortcuts, .recent-orders, .my-services, .consumption-stats, .account-security {
background-color: #fff;
margin: 15px 15px; /* 顶部恢复 margin */
border-radius: 12px; /* 统一圆角 */
padding: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
}
.section-title {
font-size: 16px;
font-weight: bold;
color: #333;
margin-bottom: 16px;
}
.order-tabs {
display: flex;
flex-direction: row; /* 显式横向排列 */
justify-content: space-between;
width: 100%;
}
.order-tab {
flex: 1;
display: flex;
flex-direction: row; /* 关键:改为横向排列 */
align-items: center;
justify-content: center; /* 居中 */
position: relative;
padding: 8px 0;
}
.tab-icon {
font-size: 20px;
margin-right: 6px; /* 图标和文字间距 */
margin-bottom: 0; /* 移除底部间距 */
}
.tab-text {
font-size: 14px;
color: #333;
}
/* 选中状态的Tab */
.order-tab.active .tab-icon,
.order-tab.active .tab-text {
color: #4CAF50;
font-weight: bold;
}
.order-tab.active {
background-color: #f0f9f0;
border-radius: 8px;
}
.tab-badge {
position: absolute;
top: 0;
right: 10%; /* 调整位置 */
background-color: #ff4444;
color: #fff;
font-size: 10px;
padding: 1px 5px;
border-radius: 8px;
min-width: 14px;
text-align: center;
line-height: 1.2;
}
.empty-orders {
text-align: center;
padding: 80rpx 0;
}
.empty-text {
font-size: 28rpx;
color: #999;
margin-bottom: 30rpx;
}
.start-shopping {
background-color: #007aff;
color: #fff;
padding: 20rpx 40rpx;
border-radius: 25rpx;
font-size: 26rpx;
border: none;
}
.order-item {
padding: 25rpx 0;
border-bottom: 1rpx solid #f5f5f5;
}
.order-item:last-child {
border-bottom: none;
}
.order-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15rpx;
}
.order-no {
font-size: 26rpx;
color: #333;
}
.order-status {
font-size: 24rpx;
padding: 6rpx 12rpx;
border-radius: 10rpx;
color: #fff;
}
.order-status.pending {
background-color: #ffa726;
}
.order-status.processing {
background-color: #2196f3;
}
.order-status.shipping {
background-color: #9c27b0;
}
.order-status.completed {
background-color: #4caf50;
}
.order-content {
display: flex;
align-items: center;
margin-bottom: 15rpx;
}
.order-image {
width: 100rpx;
height: 100rpx;
border-radius: 8rpx;
margin-right: 20rpx;
}
.order-info {
flex: 1;
}
.order-title {
font-size: 26rpx;
color: #333;
margin-bottom: 8rpx;
}
.order-amount {
font-size: 28rpx;
color: #ff4444;
font-weight: bold;
margin-bottom: 5rpx;
}
.order-time {
font-size: 22rpx;
color: #999;
}
.order-actions {
display: flex;
justify-content: flex-end;
gap: 15rpx;
}
.action-btn {
padding: 12rpx 25rpx;
border-radius: 20rpx;
font-size: 24rpx;
border: none;
}
.action-btn.pay {
background-color: #ff4444;
color: #fff;
}
.action-btn.confirm {
background-color: #4caf50;
color: #fff;
}
.action-btn.review {
background-color: #ffa726;
color: #fff;
}
.service-grid {
display: flex;
flex-direction: row;
flex-wrap: wrap; /* 允许换行 */
gap: 16px 0; /* 行间距16px列间距由 flex 控制 */
justify-content: flex-start; /* 从左开始排列 */
}
.service-item {
width: 25%; /* 每行4个 */
display: flex;
flex-direction: column;
align-items: center;
position: relative;
box-sizing: border-box; /* 确保 padding 不影响宽度 */
}
.service-icon {
font-size: 48rpx;
margin-bottom: 15rpx;
}
.service-text {
font-size: 24rpx;
color: #333;
}
.service-badge {
position: absolute;
top: -5rpx;
right: 10rpx;
background-color: #ff4444;
color: #fff;
font-size: 18rpx;
padding: 4rpx 6rpx;
border-radius: 8rpx;
min-width: 24rpx;
text-align: center;
}
.stats-period {
display: flex;
gap: 30rpx;
margin-bottom: 30rpx;
}
.period-tab {
font-size: 26rpx;
color: #666;
padding: 12rpx 24rpx;
border-radius: 20rpx;
background-color: #f0f0f0;
}
.period-tab.active {
background-color: #007aff;
color: #fff;
}
.stats-content {
display: flex;
gap: 20rpx;
}
.stat-card {
flex: 1;
text-align: center;
padding: 30rpx 0;
background-color: #f8f9fa;
border-radius: 10rpx;
}
.stat-value {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 8rpx;
}
.stat-label {
font-size: 22rpx;
color: #666;
}
.security-items {
margin-top: 25rpx;
}
.security-item {
display: flex;
align-items: center;
padding: 25rpx 0;
border-bottom: 1rpx solid #f5f5f5;
}
.security-item:last-child {
border-bottom: none;
}
.security-icon {
font-size: 32rpx;
margin-right: 20rpx;
}
.security-text {
flex: 1;
font-size: 28rpx;
color: #333;
}
.security-status {
display: flex;
align-items: center;
}
.status-text {
font-size: 24rpx;
color: #999;
margin-right: 10rpx;
}
.status-text.bound {
color: #4caf50;
}
.security-arrow {
font-size: 24rpx;
color: #999;
}
</style>