consumer模块完成度95%,准备部署消费者端测试
This commit is contained in:
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user