feat(order): 在待发货订单列表增加关闭订单功能
- 在 OrderCard 组件中新增 onCloseOrder 可选回调属性 - 待发货且未取消的订单显示“关闭订单”按钮 - 点击按钮阻止事件冒泡,避免触发卡片跳转 - 列表页实现 handleCloseOrder,弹窗确认后调用 updateShopOrder - 关闭订单后显示成功提示并刷新当前列表数据 - 复用订单详情页取消订单的状态更新逻辑,保持一致性
This commit is contained in:
@@ -303,3 +303,21 @@ adapter `/list` 接口忽略分页,一次返回全部收藏;前端 `listShop
|
|||||||
|
|
||||||
### 修改
|
### 修改
|
||||||
- **`src/pages/user/address-edit.tsx`**:识别区布局从 `relative` + `absolute` 叠加改为 flex 纵向布局——Textarea 在上,识别按钮 `flex justify-end mt-2` 在下方右对齐。去掉 `relative` class,按钮不再叠加在 Textarea 上。
|
- **`src/pages/user/address-edit.tsx`**:识别区布局从 `relative` + `absolute` 叠加改为 flex 纵向布局——Textarea 在上,识别按钮 `flex justify-end mt-2` 在下方右对齐。去掉 `relative` class,按钮不再叠加在 Textarea 上。
|
||||||
|
|
||||||
|
## 订单列表页待发货增加关闭订单功能(2026-07-14)
|
||||||
|
|
||||||
|
### 需求
|
||||||
|
`pages/order/list` 待发货状态的订单卡片需要支持客户关闭订单。
|
||||||
|
|
||||||
|
### 实现
|
||||||
|
1. **`src/components/common/OrderCard/index.tsx`**:
|
||||||
|
- 新增可选 prop `onCloseOrder?: (order: ShopOrder) => void`
|
||||||
|
- 当 `deliveryStatus === 10`(未发货)且订单未取消/未取消中时,在卡片底部显示「关闭订单」按钮
|
||||||
|
- 点击按钮阻止事件冒泡,避免触发卡片跳转详情
|
||||||
|
2. **`src/pages/order/list.tsx`**:
|
||||||
|
- 导入 `updateShopOrder` 和 `OrderStatus`
|
||||||
|
- 实现 `handleCloseOrder`:弹窗确认后调用 `updateShopOrder({ ...order, orderStatus: OrderStatus.Cancelled })`,成功后 toast 并刷新当前 tab
|
||||||
|
- 给 `OrderCard` 传入 `onCloseOrder` 回调
|
||||||
|
|
||||||
|
### 说明
|
||||||
|
复用订单详情页已有的取消订单逻辑(通过 `updateShopOrder` 将 `orderStatus` 改为 2)。
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { getCompressedImageUrl } from '@/utils/image'
|
|||||||
interface OrderCardProps {
|
interface OrderCardProps {
|
||||||
order: ShopOrder
|
order: ShopOrder
|
||||||
onClick?: () => void
|
onClick?: () => void
|
||||||
|
onCloseOrder?: (order: ShopOrder) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 综合 payStatus + deliveryStatus + orderStatus + payType 计算列表卡片状态文案 */
|
/** 综合 payStatus + deliveryStatus + orderStatus + payType 计算列表卡片状态文案 */
|
||||||
@@ -37,7 +38,7 @@ const getCardStatus = (order: ShopOrder): { text: string; color: string } => {
|
|||||||
return { text: '已付款', color: '#0e932e' }
|
return { text: '已付款', color: '#0e932e' }
|
||||||
}
|
}
|
||||||
|
|
||||||
const OrderCard: React.FC<OrderCardProps> = ({ order, onClick }) => {
|
const OrderCard: React.FC<OrderCardProps> = ({ order, onClick, onCloseOrder }) => {
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
if (onClick) {
|
if (onClick) {
|
||||||
onClick()
|
onClick()
|
||||||
@@ -46,8 +47,16 @@ const OrderCard: React.FC<OrderCardProps> = ({ order, onClick }) => {
|
|||||||
Taro.navigateTo({ url: `/pages/order/detail?id=${order.orderId}` })
|
Taro.navigateTo({ url: `/pages/order/detail?id=${order.orderId}` })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleClose = (e: any) => {
|
||||||
|
e?.stopPropagation?.()
|
||||||
|
onCloseOrder?.(order)
|
||||||
|
}
|
||||||
|
|
||||||
const { text: statusText, color: statusColor } = getCardStatus(order)
|
const { text: statusText, color: statusColor } = getCardStatus(order)
|
||||||
|
|
||||||
|
// 待发货状态(deliveryStatus=10 未发货)才显示关闭订单按钮
|
||||||
|
const showCloseButton = order.deliveryStatus === 10 && order.orderStatus !== 2 && order.orderStatus !== 3
|
||||||
|
|
||||||
// 获取首个商品图片作为封面,或显示默认占位
|
// 获取首个商品图片作为封面,或显示默认占位
|
||||||
const coverImage = order.orderGoods?.[0]?.image || ''
|
const coverImage = order.orderGoods?.[0]?.image || ''
|
||||||
const hasGoods = (order.orderGoods?.length || 0) > 0
|
const hasGoods = (order.orderGoods?.length || 0) > 0
|
||||||
@@ -127,7 +136,7 @@ const OrderCard: React.FC<OrderCardProps> = ({ order, onClick }) => {
|
|||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 底部:日期 + 金额汇总 */}
|
{/* 底部:日期 + 金额汇总 + 操作按钮 */}
|
||||||
<View className='flex justify-between items-center pt-2 border-t border-gray-50'>
|
<View className='flex justify-between items-center pt-2 border-t border-gray-50'>
|
||||||
<Text className='text-xs text-gray-500'>
|
<Text className='text-xs text-gray-500'>
|
||||||
{order.createTime?.slice(0, 10)}
|
{order.createTime?.slice(0, 10)}
|
||||||
@@ -140,6 +149,18 @@ const OrderCard: React.FC<OrderCardProps> = ({ order, onClick }) => {
|
|||||||
<Price price={order.payPrice || order.totalPrice || '0'} size='small' />
|
<Price price={order.payPrice || order.totalPrice || '0'} size='small' />
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
{/* 操作按钮区 */}
|
||||||
|
{showCloseButton && onCloseOrder && (
|
||||||
|
<View className='flex justify-end mt-3 pt-2 border-t border-gray-50'>
|
||||||
|
<View
|
||||||
|
className='px-3 py-1 rounded-full border border-gray-300'
|
||||||
|
onClick={handleClose}
|
||||||
|
>
|
||||||
|
<Text className='text-xs text-gray-600'>关闭订单</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import React, { useState, useEffect, useCallback, useRef } from 'react'
|
import React, { useState, useEffect, useCallback, useRef } from 'react'
|
||||||
import { View, Text, ScrollView } from '@tarojs/components'
|
import { View, Text, ScrollView } from '@tarojs/components'
|
||||||
import Taro from '@tarojs/taro'
|
import Taro from '@tarojs/taro'
|
||||||
import { pageShopOrder } from '@/api/shop/shopOrder'
|
import { pageShopOrder, updateShopOrder } from '@/api/shop/shopOrder'
|
||||||
import type { ShopOrder, ShopOrderParam } from '@/api/shop/shopOrder/model'
|
import type { ShopOrder, ShopOrderParam } from '@/api/shop/shopOrder/model'
|
||||||
import { useUser } from '@/hooks/useUser'
|
import { useUser } from '@/hooks/useUser'
|
||||||
import { OrderListStatus, OrderListTabText } from '@/types/order'
|
import { OrderListStatus, OrderListTabText, OrderStatus } from '@/types/order'
|
||||||
import OrderCard from '@/components/common/OrderCard'
|
import OrderCard from '@/components/common/OrderCard'
|
||||||
import EmptyState from '@/components/common/EmptyState'
|
import EmptyState from '@/components/common/EmptyState'
|
||||||
import LoadMore from '@/components/common/LoadMore'
|
import LoadMore from '@/components/common/LoadMore'
|
||||||
@@ -147,6 +147,27 @@ const OrderListPage: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 关闭订单(待发货状态下允许客户取消) */
|
||||||
|
const handleCloseOrder = (order: ShopOrder) => {
|
||||||
|
Taro.showModal({
|
||||||
|
title: '确认关闭订单',
|
||||||
|
content: '关闭后订单将取消,是否确认?',
|
||||||
|
confirmColor: '#ee0a24',
|
||||||
|
success: async (res) => {
|
||||||
|
if (res.confirm && order?.orderId) {
|
||||||
|
try {
|
||||||
|
await updateShopOrder({ ...order, orderStatus: OrderStatus.Cancelled })
|
||||||
|
Taro.showToast({ title: '订单已关闭', icon: 'success' })
|
||||||
|
// 刷新当前 tab
|
||||||
|
loadOrders(tabIndex, 1)
|
||||||
|
} catch (err: any) {
|
||||||
|
Taro.showToast({ title: err?.message || '关闭失败', icon: 'none' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const handleTabChange = (index: number) => {
|
const handleTabChange = (index: number) => {
|
||||||
if (index !== tabIndex) {
|
if (index !== tabIndex) {
|
||||||
setTabIndex(index)
|
setTabIndex(index)
|
||||||
@@ -209,7 +230,11 @@ const OrderListPage: React.FC = () => {
|
|||||||
<View className='p-3'>
|
<View className='p-3'>
|
||||||
{tabStates[idx].orders.length > 0 ? (
|
{tabStates[idx].orders.length > 0 ? (
|
||||||
tabStates[idx].orders.map(order => (
|
tabStates[idx].orders.map(order => (
|
||||||
<OrderCard key={order.orderId} order={order} />
|
<OrderCard
|
||||||
|
key={order.orderId}
|
||||||
|
order={order}
|
||||||
|
onCloseOrder={handleCloseOrder}
|
||||||
|
/>
|
||||||
))
|
))
|
||||||
) : tabStates[idx].initialized && !tabStates[idx].loading ? (
|
) : tabStates[idx].initialized && !tabStates[idx].loading ? (
|
||||||
<EmptyState text='暂无订单' />
|
<EmptyState text='暂无订单' />
|
||||||
|
|||||||
Reference in New Issue
Block a user