继续补充功能页面,consumer模块完成度70%

This commit is contained in:
2026-01-26 08:16:41 +08:00
parent 0ed62a8258
commit be90f1213b
17 changed files with 4859 additions and 8793 deletions

View File

@@ -1,40 +1,110 @@
<!-- 消费者端 - 个人中心 -->
<template>
<view class="consumer-profile">
<!-- 用户信息头部 -->
<view class="profile-header">
<image :src="userInfo.avatar_url || '/static/default-avatar.png'" class="user-avatar" @click="editProfile" />
<view class="user-info">
<text class="user-name">{{ userInfo.nickname || userInfo.phone }}</text>
<text class="user-level">{{ getUserLevel() }}</text>
<view class="user-stats">
<text class="stat-item">积分: {{ userStats.points }}</text>
<text class="stat-item">余额: ¥{{ userStats.balance }}</text>
<!-- 智能顶部导航栏 - 与消息页保持一致 -->
<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">
<text class="nav-stat-label">积分</text>
<text class="nav-stat-value">{{ userStats.points }}</text>
</view>
<view class="nav-stat-item">
<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="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 class="settings-icon" @click="goToSettings">⚙️</view>
</view>
<!-- 订单状态快捷入口 -->
<view class="order-shortcuts">
<view class="section-title">我的订单</view>
<view class="order-tabs">
<view class="order-tab" @click="goToOrders('all')">
<view class="order-tab" :class="{ active: currentOrderTab === 'all' }" @click="switchOrderTab('all')">
<text class="tab-icon">📋</text>
<text class="tab-text">全部订单</text>
<text class="tab-text">全部</text>
<text v-if="orderCounts.total > 0" class="tab-badge">{{ orderCounts.total }}</text>
</view>
<view class="order-tab" @click="goToOrders('pending')">
<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" @click="goToOrders('shipped')">
<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 class="order-tab" @click="goToOrders('completed')">
<view class="order-tab" :class="{ active: currentOrderTab === 'review' }" @click="switchOrderTab('review')">
<text class="tab-icon">⭐</text>
<text class="tab-text">待评价</text>
<text v-if="orderCounts.review > 0" class="tab-badge">{{ orderCounts.review }}</text>
@@ -42,25 +112,25 @@
</view>
</view>
<!-- 最近订单 -->
<!-- 最近订单列表 (根据Tab切换显示) -->
<view class="recent-orders">
<view class="section-header">
<text class="section-title">最近订单</text>
<text class="view-all" @click="goToOrders('all')">查看全部 ></text>
<text class="section-title">{{ getOrderSectionTitle() }}</text>
<text class="view-all" @click="goToOrders(currentOrderTab)">查看更多 ></text>
</view>
<view v-if="recentOrders.length === 0" class="empty-orders">
<text class="empty-text">暂无订单记录</text>
<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 recentOrders" :key="order.id" class="order-item" @click="viewOrderDetail(order)">
<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" />
<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>
@@ -76,7 +146,7 @@
</view>
<!-- 我的服务 -->
<view class="my-services">
<!-- <view class="my-services">
<view class="section-title">我的服务</view>
<view class="service-grid">
<view class="service-item" @click="goToCoupons">
@@ -114,7 +184,7 @@
<text class="service-text">软件订阅</text>
</view>
</view>
</view>
</view> -->
<!-- 消费统计 -->
<view class="consumption-stats">
@@ -251,16 +321,150 @@ export default {
order_count: 0,
avg_amount: 0,
save_amount: 0
} as ConsumptionStatsType
} as ConsumptionStatsType,
statusBarHeight: 0,
currentOrderTab: 'all' as string, // 当前选中的订单Tab
allOrders: [] as Array<OrderType> // 存储所有订单数据
}
},
onLoad() {
this.initPage()
this.loadUserProfile()
this.loadMockOrders() // 加载Mock订单数据
},
onShow() {
this.refreshData()
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 === 'shipped') {
return this.allOrders.filter((order: OrderType): boolean => order.status === 2 || order.status === 3)
} else if (this.currentOrderTab === 'review') {
return this.allOrders.filter((order: OrderType): boolean => order.status === 4)
}
return []
}
},
methods: {
// 加载Mock订单数据
loadMockOrders() {
// 创建Mock数据
const mockData: Array<OrderType> = [
// 待支付订单
{
id: 'order_001',
order_no: 'ORD202401250001',
user_id: 'user_001',
merchant_id: 'merchant_001',
status: 1, // 待支付
total_amount: 299.00,
discount_amount: 30.00,
delivery_fee: 0.00,
actual_amount: 269.00,
payment_method: 1,
payment_status: 0,
delivery_address: {},
created_at: '2024-01-25T14:30:00'
},
// 待发货
{
id: 'order_002',
order_no: 'ORD202401240002',
user_id: 'user_001',
merchant_id: 'merchant_002',
status: 2, // 待发货
total_amount: 158.00,
discount_amount: 0,
delivery_fee: 6.00,
actual_amount: 164.00,
payment_method: 1,
payment_status: 1,
delivery_address: {},
created_at: '2024-01-24T09:20:00'
},
// 待收货
{
id: 'order_003',
order_no: 'ORD202401230003',
user_id: 'user_001',
merchant_id: 'merchant_001',
status: 3, // 待收货
total_amount: 89.90,
discount_amount: 10.00,
delivery_fee: 0.00,
actual_amount: 79.90,
payment_method: 1,
payment_status: 1,
delivery_address: {},
created_at: '2024-01-23T18:15:00'
},
// 待评价 (已完成)
{
id: 'order_004',
order_no: 'ORD202401200004',
user_id: 'user_001',
merchant_id: 'merchant_003',
status: 4, // 待评价
total_amount: 399.00,
discount_amount: 50.00,
delivery_fee: 0.00,
actual_amount: 349.00,
payment_method: 1,
payment_status: 1,
delivery_address: {},
created_at: '2024-01-20T11:30:00'
},
// 已完成 (已评价)
{
id: 'order_005',
order_no: 'ORD202401180005',
user_id: 'user_001',
merchant_id: 'merchant_001',
status: 5, // 已完成
total_amount: 128.00,
discount_amount: 0,
delivery_fee: 0.00,
actual_amount: 128.00,
payment_method: 1,
payment_status: 1,
delivery_address: {},
created_at: '2024-01-18T16:45:00'
}
]
this.allOrders = mockData
this.recentOrders = mockData // 初始显示全部
// 更新角标统计
this.orderCounts = {
total: mockData.length,
pending: mockData.filter((o: OrderType): boolean => o.status === 1).length,
shipped: mockData.filter((o: OrderType): boolean => o.status === 2 || o.status === 3).length,
review: mockData.filter((o: OrderType): boolean => o.status === 4).length
}
},
// 切换订单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 = {
@@ -364,6 +568,15 @@ export default {
refreshData() {
// 刷新页面数据
this.loadUserProfile()
this.loadMockOrders() // 加载Mock订单数据
this.updateCouponCount() // 更新优惠券数量
},
updateCouponCount() {
// 从本地存储读取领取的优惠券数量并叠加到基础数量上
const baseCoupons = 5
const claimedCoupons = uni.getStorageSync('claimedCoupons') || 0
this.serviceCounts.coupons = baseCoupons + (claimedCoupons as number)
},
getUserLevel(): string {
@@ -476,8 +689,9 @@ export default {
},
goToAddress() {
// 暂时跳转到设置页的地址管理
uni.navigateTo({
url: '/pages/mall/consumer/address'
url: '/pages/mall/consumer/address-list'
})
},
@@ -542,115 +756,183 @@ export default {
min-height: 100vh;
}
.profile-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 60rpx 30rpx 40rpx;
/* 智能顶部导航栏 */
.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;
color: #fff;
justify-content: center;
width: 32px;
height: 32px;
background: rgba(255, 255, 255, 0.2);
border-radius: 16px;
cursor: pointer;
}
.user-avatar {
width: 120rpx;
height: 120rpx;
border-radius: 60rpx;
margin-right: 30rpx;
border: 4rpx solid rgba(255, 255, 255, 0.3);
.action-icon {
font-size: 18px;
color: white;
}
.user-info {
flex: 1;
}
.user-name {
font-size: 36rpx;
font-weight: bold;
margin-bottom: 8rpx;
}
.user-level {
font-size: 24rpx;
background-color: rgba(255, 255, 255, 0.2);
padding: 6rpx 12rpx;
border-radius: 12rpx;
margin-bottom: 15rpx;
display: inline-block;
}
.user-stats {
display: flex;
gap: 30rpx;
}
.stat-item {
font-size: 24rpx;
opacity: 0.9;
}
.settings-icon {
font-size: 32rpx;
padding: 10rpx;
/* 导航栏占位符 */
.navbar-placeholder {
width: 100%;
flex-shrink: 0;
}
.order-shortcuts, .recent-orders, .my-services, .consumption-stats, .account-security {
background-color: #fff;
margin-bottom: 20rpx;
padding: 30rpx;
margin: 15px 15px; /* 顶部恢复 margin */
border-radius: 12px; /* 统一圆角 */
padding: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
}
.section-title {
font-size: 32rpx;
font-size: 16px;
font-weight: bold;
color: #333;
margin-bottom: 25rpx;
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 25rpx;
}
.view-all {
font-size: 24rpx;
color: #007aff;
margin-bottom: 16px;
}
.order-tabs {
display: flex;
flex-direction: row; /* 显式横向排列 */
justify-content: space-between;
width: 100%;
}
.order-tab {
flex: 1;
display: flex;
flex-direction: column;
flex-direction: row; /* 关键:改为横向排列 */
align-items: center;
justify-content: center; /* 居中 */
position: relative;
padding: 8px 0;
}
.tab-icon {
font-size: 40rpx;
margin-bottom: 10rpx;
font-size: 20px;
margin-right: 6px; /* 图标和文字间距 */
margin-bottom: 0; /* 移除底部间距 */
}
.tab-text {
font-size: 24rpx;
color: #666;
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: -8rpx;
right: 20rpx;
top: 0;
right: 10%; /* 调整位置 */
background-color: #ff4444;
color: #fff;
font-size: 20rpx;
padding: 4rpx 8rpx;
border-radius: 10rpx;
min-width: 32rpx;
font-size: 10px;
padding: 1px 5px;
border-radius: 8px;
min-width: 14px;
text-align: center;
line-height: 1.2;
}
.empty-orders {
@@ -782,16 +1064,19 @@ export default {
.service-grid {
display: flex;
flex-wrap: wrap;
gap: 30rpx;
flex-direction: row;
flex-wrap: wrap; /* 允许换行 */
gap: 16px 0; /* 行间距16px列间距由 flex 控制 */
justify-content: flex-start; /* 从左开始排列 */
}
.service-item {
width: 30%;
width: 25%; /* 每行4个 */
display: flex;
flex-direction: column;
align-items: center;
position: relative;
box-sizing: border-box; /* 确保 padding 不影响宽度 */
}
.service-icon {