consumer模块完成度95%,准备部署消费者端测试

This commit is contained in:
cyh666666
2026-03-05 08:45:00 +08:00
parent cceb556c62
commit 7f7f723d93
1043 changed files with 53958 additions and 3445 deletions

View File

@@ -1,4 +1,4 @@
<!-- pages/mall/consumer/orders.uvue -->
<!-- pages/mall/consumer/orders.uvue -->
<template>
<view class="orders-page">
<!-- 顶部标题栏 -->
@@ -74,9 +74,12 @@
<text class="shop-name">{{ order.shop_name != null && order.shop_name != '' ? order.shop_name : '自营店铺' }}</text>
<text class="arrow-right"></text>
</view>
<text :class="['order-status', getStatusClass(order.status)]">
{{ getStatusText(order.status) }}
</text>
<view class="status-row">
<text :class="['order-status', getStatusClass(order.status)]">
{{ getStatusText(order.status) }}
</text>
<text class="more-btn" @click.stop="showOrderMenu(order)">⋯</text>
</view>
</view>
<!-- 订单商品 -->
@@ -141,6 +144,16 @@
<view v-if="order.status === 5" class="action-buttons">
<button class="action-btn view" @click="viewOrderDetail(order.id)">查看详情</button>
</view>
<view v-if="order.status === 6" class="action-buttons">
<button class="action-btn view" @click="viewOrderDetail(order.id)">查看详情</button>
<button class="action-btn refund" @click="viewRefundProgress(order.id)">退款进度</button>
</view>
<view v-if="order.status === 7" class="action-buttons">
<button class="action-btn view" @click="viewOrderDetail(order.id)">查看详情</button>
<button class="action-btn repurchase" @click="repurchase(order)">再次购买</button>
</view>
</view>
</view>
</view>
@@ -218,6 +231,7 @@ const orderTabs = ref<OrderTabItem[]>([
{ id: 'shipping', name: '待发货', count: 0 },
{ id: 'delivering', name: '待收货', count: 0 },
{ id: 'completed', name: '已完成', count: 0 },
{ id: 'aftersale', name: '售后', count: 0 },
{ id: 'cancelled', name: '已取消', count: 0 }
])
@@ -234,6 +248,7 @@ const getStatusByTab = (tabId: string): number => {
if (tabId == 'delivering') return 3
if (tabId == 'completed') return 4
if (tabId == 'cancelled') return 5
if (tabId == 'aftersale') return 6
return 0
}
@@ -314,27 +329,31 @@ function parseSpecText(specs: any): string {
// 辅助函数:更新标签计数
const updateTabsCounts = (allOrders: OrderItem[]) => {
// 计算各状态数量
const countAll = allOrders.length
const countPending = allOrders.filter((o: OrderItem) => o.status === 1).length
const countShipping = allOrders.filter((o: OrderItem) => o.status === 2).length
const countDelivering = allOrders.filter((o: OrderItem) => o.status === 3).length
const countCompleted = allOrders.filter((o: OrderItem) => o.status === 4).length
const countCancelled = allOrders.filter((o: OrderItem) => o.status === 5).length
const countAftersale = allOrders.filter((o: OrderItem) => o.status === 6 || o.status === 7).length
// 更新数组元素
orderTabs.value[0].count = countAll
orderTabs.value[1].count = countPending
orderTabs.value[2].count = countShipping
orderTabs.value[3].count = countDelivering
orderTabs.value[4].count = countCompleted
orderTabs.value[5].count = countCancelled
orderTabs.value[5].count = countAftersale
orderTabs.value[6].count = countCancelled
}
// 辅助函数:按标签筛选订单
const filterOrdersByTab = () => {
if (activeTab.value === 'all') {
orders.value = allOrdersList.value
} else if (activeTab.value === 'aftersale') {
orders.value = allOrdersList.value.filter((o: OrderItem) => {
return o.status === 6 || o.status === 7
})
} else {
const targetStatus = getStatusByTab(activeTab.value)
orders.value = allOrdersList.value.filter((o: OrderItem) => {
@@ -489,7 +508,7 @@ onLoad((options) => {
const statusVal = options['status']
if (statusVal != null) {
const status = statusVal as string
if (['all', 'pending', 'shipping', 'delivering', 'completed', 'cancelled'].includes(status)) {
if (['all', 'pending', 'shipping', 'delivering', 'completed', 'aftersale', 'cancelled'].includes(status)) {
activeTab.value = status
}
}
@@ -608,6 +627,47 @@ const getStatusClass = (status: number): string => {
return 'status-unknown'
}
// 联系卖家
const contactSeller = (order: OrderItem) => {
if (order.merchant_id != '') {
uni.navigateTo({
url: `/pages/mall/consumer/chat?merchantId=${order.merchant_id}`
})
} else {
uni.showToast({
title: '暂无卖家联系方式',
icon: 'none'
})
}
}
// 删除订单
const deleteOrder = (orderId: string) => {
uni.showModal({
title: '删除订单',
content: '确定要删除此订单吗?',
success: (res) => {
if (res.confirm) {
uni.showLoading({ title: '删除中...' })
supabaseService.deleteOrder(orderId).then(() => {
uni.hideLoading()
uni.showToast({
title: '订单已删除',
icon: 'success'
})
loadOrders()
}).catch(() => {
uni.hideLoading()
uni.showToast({
title: '删除失败',
icon: 'none'
})
})
}
}
})
}
// 下拉刷新
const onRefresh = () => {
refreshing.value = true
@@ -636,22 +696,28 @@ const cancelOrder = (orderId: string) => {
content: '确定要取消此订单吗?',
success: (res) => {
if (res.confirm) {
// 这里应该是实际的API调用
uni.showToast({
title: '订单已取消',
icon: 'success'
uni.showLoading({ title: '取消中...' })
supabaseService.cancelOrder(orderId).then((success) => {
uni.hideLoading()
if (success) {
uni.showToast({
title: '订单已取消',
icon: 'success'
})
loadOrders()
} else {
uni.showToast({
title: '取消失败',
icon: 'none'
})
}
}).catch(() => {
uni.hideLoading()
uni.showToast({
title: '取消失败',
icon: 'none'
})
})
// 更新订单状态
const index = orders.value.findIndex((o: any) => {
const obj = o as Record<string, any>
return obj['id'] === orderId
})
if (index !== -1) {
const orderObj = orders.value[index] as Record<string, any>
orderObj['status'] = 5
orders.value = [...orders.value]
}
}
}
})
@@ -663,7 +729,35 @@ const payOrder = (orderId: string) => {
})
}
const remindShipping = (orderId: string) => {
const remindShipping = async (orderId: string) => {
// 基础提醒
uni.showLoading({ title: '正在提醒...' })
try {
// 查找订单中的商家ID
const order = orders.value.find(o => o.id === orderId)
if (order != null) {
const merchantId = order.merchant_id
const orderNo = order.order_no
if (merchantId != '') {
// 向商家发送自动催单消息
const message = `你好,我的订单[${orderNo}]还没有发货,请尽快安排,谢谢。`
const success = await supabaseService.sendChatMessage(message, merchantId)
if (success) {
console.log('催单消息发送成功')
} else {
console.warn('催单消息发送失败,可能是由于网络原因')
}
}
}
} catch (e) {
console.error('提醒发货异常:', e)
} finally {
uni.hideLoading()
}
uni.showToast({
title: '已提醒卖家发货',
icon: 'success'
@@ -752,19 +846,81 @@ const confirmReceipt = (orderId: string) => {
}
const repurchase = (order: any) => {
uni.showModal({
title: '再次购买',
content: '确定要将这些商品加入购物车吗?',
success: (res) => {
if (res.confirm) {
// 这里应该是实际的API调用
uni.showToast({
title: '已加入购物车',
icon: 'success'
})
const orderObj = order as Record<string, any>
const products = orderObj['products'] as any[]
if (products == null || products.length === 0) {
uni.showToast({
title: '订单无商品',
icon: 'none'
})
return
}
uni.showLoading({ title: '处理中...' })
let completed = 0
const total = products.length
let successCount = 0
for (let i = 0; i < products.length; i++) {
const pObj = products[i] as Record<string, any>
const productId = pObj['id'] as string
const merchantId = orderObj['merchant_id'] as string
if (productId != null && productId !== '') {
supabaseService.addToCart(productId, 1, '', merchantId ?? '').then((success) => {
completed++
if (success) successCount++
if (completed === total) {
uni.hideLoading()
if (successCount > 0) {
uni.showToast({
title: `已添加${successCount}件商品`,
icon: 'success'
})
} else {
uni.showToast({
title: '添加失败',
icon: 'none'
})
}
}
}).catch(() => {
completed++
if (completed === total) {
uni.hideLoading()
if (successCount > 0) {
uni.showToast({
title: `已添加${successCount}件商品`,
icon: 'success'
})
} else {
uni.showToast({
title: '添加失败',
icon: 'none'
})
}
}
})
} else {
completed++
if (completed === total) {
uni.hideLoading()
if (successCount > 0) {
uni.showToast({
title: `已添加${successCount}件商品`,
icon: 'success'
})
} else {
uni.showToast({
title: '添加失败',
icon: 'none'
})
}
}
}
})
}
}
const viewOrderDetail = (orderId: string) => {
@@ -781,6 +937,65 @@ const onApplyRefund = (order: any) => {
})
}
const viewRefundProgress = (orderId: string) => {
uni.navigateTo({
url: `/pages/mall/consumer/refund?orderId=${orderId}`
})
}
// 处理订单操作
const handleOrderAction = (order: OrderItem, action: string) => {
if (action === '取消订单') {
cancelOrder(order.id)
} else if (action === '联系卖家') {
contactSeller(order)
} else if (action === '提醒发货') {
remindShipping(order.id)
} else if (action === '申请退款' || action === '申请售后') {
onApplyRefund(order)
} else if (action === '查看物流') {
viewLogistics(order.id)
} else if (action === '确认收货') {
confirmReceipt(order.id)
} else if (action === '再次购买') {
repurchase(order)
} else if (action === '删除订单') {
deleteOrder(order.id)
} else if (action === '退款进度') {
viewRefundProgress(order.id)
}
}
// 显示订单操作菜单
const showOrderMenu = (order: OrderItem) => {
const status = order.status
let actions: string[] = []
if (status === 1) {
actions = ['取消订单', '联系卖家']
} else if (status === 2) {
actions = ['提醒发货', '申请退款', '联系卖家']
} else if (status === 3) {
actions = ['查看物流', '确认收货', '申请退款', '联系卖家']
} else if (status === 4) {
actions = ['申请售后', '再次购买', '联系卖家']
} else if (status === 5) {
actions = ['删除订单', '再次购买', '联系卖家']
} else if (status === 6) {
actions = ['退款进度', '联系卖家']
} else if (status === 7) {
actions = ['再次购买', '联系卖家']
}
uni.showActionSheet({
itemList: actions,
success: (res) => {
const action = actions[res.tapIndex]
handleOrderAction(order, action)
}
})
}
// 导航函数
const navigateToSearch = () => {
uni.navigateTo({ url: '/pages/mall/consumer/search' })
@@ -799,12 +1014,14 @@ const goShopping = () => {
<style>
.orders-page {
width: 100%;
height: 100vh;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
flex-direction: column;
background-color: #f5f5f5;
position: relative;
overflow: hidden;
}
@@ -816,9 +1033,8 @@ const goShopping = () => {
align-items: center;
justify-content: center;
border-bottom: 1px solid #eee;
/* position: sticky; removed */
/* top: 0; removed */
z-index: 10;
flex-shrink: 0;
}
.header-search.full-width {
@@ -879,10 +1095,29 @@ const goShopping = () => {
align-items: center;
width: 100%;
z-index: 10;
height: 50px;
flex-shrink: 0;
}
/* 安卓端滚动修复 */
.orders-content {
flex: 1;
width: 100%;
height: 0; /* 关键:强制 flex: 1 生效 */
}
.orders-header {
background-color: white;
padding: 15px;
display: flex;
align-items: center;
justify-content: center;
border-bottom: 1px solid #eee;
flex-shrink: 0;
}
.tab-item-fixed {
padding: 15px 15px;
padding: 0 15px;
text-align: center;
position: relative;
display: flex;
@@ -891,6 +1126,7 @@ const goShopping = () => {
white-space: nowrap;
flex-shrink: 0;
min-width: 60px;
height: 100%;
}
.tab-item-fixed.active {
@@ -958,8 +1194,8 @@ const goShopping = () => {
/* 内容区 */
.orders-content {
flex: 1;
height: 0;
width: 100%;
height: 0; /* 关键:强制让 flex:1 在安卓端生效,防止内容撑开父容器 */
}
/* 空状态 */
@@ -1001,6 +1237,8 @@ const goShopping = () => {
/* 订单列表 */
.order-list {
padding: 10px;
width: 100%;
box-sizing: border-box;
}
.order-card {
@@ -1009,6 +1247,8 @@ const goShopping = () => {
margin-bottom: 10px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
flex-shrink: 0;
box-sizing: border-box;
}
/* 订单头部 */
@@ -1268,15 +1508,20 @@ const goShopping = () => {
display: flex;
flex-direction: row;
flex-wrap: wrap;
padding: 20px;
width: 100%;
max-width: 1200px;
margin: 0 auto;
justify-content: flex-start;
align-content: flex-start;
box-sizing: border-box;
}
.order-card {
width: 48%;
margin: 0 1% 20px 1%;
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
flex: none;
box-sizing: border-box;
}
}
@@ -1284,6 +1529,8 @@ const goShopping = () => {
.order-card {
width: 31%;
margin: 0 1% 20px 1%;
flex: none;
box-sizing: border-box;
}
}
@@ -1297,6 +1544,19 @@ const goShopping = () => {
border-bottom: 1px solid #f9f9f9;
}
.status-row {
display: flex;
flex-direction: row;
align-items: center;
}
.more-btn {
font-size: 18px;
color: #999;
margin-left: 8px;
padding: 0 5px;
}
.shop-info {
display: flex;
flex-direction: row;
@@ -1389,3 +1649,4 @@ const goShopping = () => {
}
}
</style>