|
@@ -5,29 +5,29 @@ import Taro from '@tarojs/taro'
|
|
|
import { orderClient } from '@/api'
|
|
import { orderClient } from '@/api'
|
|
|
import { InferResponseType } from 'hono'
|
|
import { InferResponseType } from 'hono'
|
|
|
import { Navbar } from '@/components/ui/navbar'
|
|
import { Navbar } from '@/components/ui/navbar'
|
|
|
-import { Card } from '@/components/ui/card'
|
|
|
|
|
-import { Button } from '@/components/ui/button'
|
|
|
|
|
import { useAuth } from '@/utils/auth'
|
|
import { useAuth } from '@/utils/auth'
|
|
|
|
|
+import OrderCard from '@/components/order/OrderCard'
|
|
|
|
|
+import './index.css'
|
|
|
|
|
|
|
|
type OrderResponse = InferResponseType<typeof orderClient.$get, 200>
|
|
type OrderResponse = InferResponseType<typeof orderClient.$get, 200>
|
|
|
type Order = OrderResponse['data'][0]
|
|
type Order = OrderResponse['data'][0]
|
|
|
|
|
|
|
|
-// 订单状态映射
|
|
|
|
|
|
|
+// 订单状态映射 - 根据tcb-shop-demo设计规范
|
|
|
const orderStatusMap = {
|
|
const orderStatusMap = {
|
|
|
- 0: { text: '待发货', color: 'text-orange-500' },
|
|
|
|
|
- 1: { text: '已发货', color: 'text-blue-500' },
|
|
|
|
|
- 2: { text: '已完成', color: 'text-green-500' },
|
|
|
|
|
- 3: { text: '已退货', color: 'text-red-500' }
|
|
|
|
|
|
|
+ 0: { text: '待发货', color: 'text-orange-500', bgColor: 'bg-orange-100' },
|
|
|
|
|
+ 1: { text: '已发货', color: 'text-blue-500', bgColor: 'bg-blue-100' },
|
|
|
|
|
+ 2: { text: '已完成', color: 'text-green-500', bgColor: 'bg-green-100' },
|
|
|
|
|
+ 3: { text: '已退货', color: 'text-red-500', bgColor: 'bg-red-100' }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// 支付状态映射
|
|
|
|
|
|
|
+// 支付状态映射 - 根据tcb-shop-demo设计规范
|
|
|
const payStatusMap = {
|
|
const payStatusMap = {
|
|
|
- 0: { text: '未支付', color: 'text-red-500' },
|
|
|
|
|
- 1: { text: '支付中', color: 'text-yellow-500' },
|
|
|
|
|
- 2: { text: '已支付', color: 'text-green-500' },
|
|
|
|
|
- 3: { text: '已退款', color: 'text-gray-500' },
|
|
|
|
|
- 4: { text: '支付失败', color: 'text-red-500' },
|
|
|
|
|
- 5: { text: '已关闭', color: 'text-gray-500' }
|
|
|
|
|
|
|
+ 0: { text: '未支付', color: 'text-red-500', bgColor: 'bg-red-100' },
|
|
|
|
|
+ 1: { text: '支付中', color: 'text-yellow-500', bgColor: 'bg-yellow-100' },
|
|
|
|
|
+ 2: { text: '已支付', color: 'text-green-500', bgColor: 'bg-green-100' },
|
|
|
|
|
+ 3: { text: '已退款', color: 'text-gray-500', bgColor: 'bg-gray-100' },
|
|
|
|
|
+ 4: { text: '支付失败', color: 'text-red-500', bgColor: 'bg-red-100' },
|
|
|
|
|
+ 5: { text: '已关闭', color: 'text-gray-500', bgColor: 'bg-gray-100' }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export default function OrderListPage() {
|
|
export default function OrderListPage() {
|
|
@@ -134,6 +134,7 @@ export default function OrderListPage() {
|
|
|
return goods.reduce((sum: number, item: any) => sum + (item.num || 0), 0)
|
|
return goods.reduce((sum: number, item: any) => sum + (item.num || 0), 0)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 根据tcb-shop-demo设计规范的标签配置
|
|
|
const tabs = [
|
|
const tabs = [
|
|
|
{ key: 'all', label: '全部' },
|
|
{ key: 'all', label: '全部' },
|
|
|
{ key: 'unpaid', label: '待付款' },
|
|
{ key: 'unpaid', label: '待付款' },
|
|
@@ -149,174 +150,80 @@ export default function OrderListPage() {
|
|
|
leftIcon="i-heroicons-chevron-left-20-solid"
|
|
leftIcon="i-heroicons-chevron-left-20-solid"
|
|
|
onClickLeft={() => Taro.navigateBack()}
|
|
onClickLeft={() => Taro.navigateBack()}
|
|
|
/>
|
|
/>
|
|
|
-
|
|
|
|
|
- <ScrollView
|
|
|
|
|
- className="flex-1"
|
|
|
|
|
- scrollY
|
|
|
|
|
- onScrollToLower={handleScrollToLower}
|
|
|
|
|
- refresherEnabled
|
|
|
|
|
- refresherTriggered={false}
|
|
|
|
|
- onRefresherRefresh={onPullDownRefresh}
|
|
|
|
|
- >
|
|
|
|
|
- {/* 标签栏 */}
|
|
|
|
|
- <View className="bg-white mb-4">
|
|
|
|
|
- <View className="flex">
|
|
|
|
|
|
|
+
|
|
|
|
|
+ {/* 顶部标签栏 - 根据tcb-shop-demo设计规范 */}
|
|
|
|
|
+ <View className="bg-white shadow-sm">
|
|
|
|
|
+ <ScrollView
|
|
|
|
|
+ className="flex-row"
|
|
|
|
|
+ scrollX
|
|
|
|
|
+ showsHorizontalScrollIndicator={false}
|
|
|
|
|
+ >
|
|
|
|
|
+ <View className="flex-row px-4">
|
|
|
{tabs.map((tab) => (
|
|
{tabs.map((tab) => (
|
|
|
<View
|
|
<View
|
|
|
key={tab.key}
|
|
key={tab.key}
|
|
|
- className={`flex-1 py-3 text-center ${
|
|
|
|
|
|
|
+ className={`flex-shrink-0 py-3 px-4 text-center ${
|
|
|
activeTab === tab.key
|
|
activeTab === tab.key
|
|
|
- ? 'text-blue-500 border-b-2 border-blue-500'
|
|
|
|
|
|
|
+ ? 'text-primary border-b-2 border-primary'
|
|
|
: 'text-gray-600'
|
|
: 'text-gray-600'
|
|
|
}`}
|
|
}`}
|
|
|
onClick={() => setActiveTab(tab.key)}
|
|
onClick={() => setActiveTab(tab.key)}
|
|
|
>
|
|
>
|
|
|
- {tab.label}
|
|
|
|
|
|
|
+ <Text className="text-sm font-medium">{tab.label}</Text>
|
|
|
</View>
|
|
</View>
|
|
|
))}
|
|
))}
|
|
|
</View>
|
|
</View>
|
|
|
- </View>
|
|
|
|
|
|
|
+ </ScrollView>
|
|
|
|
|
+ </View>
|
|
|
|
|
|
|
|
- <View className="px-4">
|
|
|
|
|
|
|
+ <ScrollView
|
|
|
|
|
+ className="flex-1"
|
|
|
|
|
+ scrollY
|
|
|
|
|
+ onScrollToLower={handleScrollToLower}
|
|
|
|
|
+ refresherEnabled
|
|
|
|
|
+ refresherTriggered={false}
|
|
|
|
|
+ onRefresherRefresh={onPullDownRefresh}
|
|
|
|
|
+ >
|
|
|
|
|
+ <View className="p-4">
|
|
|
{isLoading ? (
|
|
{isLoading ? (
|
|
|
<View className="flex justify-center py-10">
|
|
<View className="flex justify-center py-10">
|
|
|
- <View className="i-heroicons-arrow-path-20-solid animate-spin w-8 h-8 text-blue-500" />
|
|
|
|
|
|
|
+ <View className="i-heroicons-arrow-path-20-solid animate-spin w-8 h-8 text-primary" />
|
|
|
</View>
|
|
</View>
|
|
|
) : (
|
|
) : (
|
|
|
<>
|
|
<>
|
|
|
- {allOrders.map((order) => {
|
|
|
|
|
- const goods = parseGoodsDetail(order.goodsDetail)
|
|
|
|
|
- const totalQuantity = getOrderItemCount(order)
|
|
|
|
|
-
|
|
|
|
|
- return (
|
|
|
|
|
- <Card key={order.id} className="mb-4">
|
|
|
|
|
- <View className="p-4">
|
|
|
|
|
- {/* 订单头部 */}
|
|
|
|
|
- <View className="flex justify-between items-center mb-3 pb-3 border-b border-gray-100">
|
|
|
|
|
- <Text className="text-sm text-gray-600">
|
|
|
|
|
- 订单号: {order.orderNo}
|
|
|
|
|
- </Text>
|
|
|
|
|
- <Text className={`text-sm font-medium ${payStatusMap[order.payState as keyof typeof payStatusMap].color}`}>
|
|
|
|
|
- {payStatusMap[order.payState as keyof typeof payStatusMap].text}
|
|
|
|
|
- </Text>
|
|
|
|
|
- </View>
|
|
|
|
|
-
|
|
|
|
|
- {/* 商品列表 */}
|
|
|
|
|
- <View className="mb-3">
|
|
|
|
|
- {goods.slice(0, 3).map((item: any, index: number) => (
|
|
|
|
|
- <View key={index} className="flex items-center py-2">
|
|
|
|
|
- <img
|
|
|
|
|
- src={item.image || ''}
|
|
|
|
|
- className="w-16 h-16 rounded-lg mr-3"
|
|
|
|
|
- mode="aspectFill"
|
|
|
|
|
- />
|
|
|
|
|
- <View className="flex-1">
|
|
|
|
|
- <Text className="text-sm font-medium line-clamp-2">
|
|
|
|
|
- {item.name}
|
|
|
|
|
- </Text>
|
|
|
|
|
- <Text className="text-sm text-gray-500">
|
|
|
|
|
- ¥{item.price.toFixed(2)} × {item.num}
|
|
|
|
|
- </Text>
|
|
|
|
|
- </View>
|
|
|
|
|
- </View>
|
|
|
|
|
- ))}
|
|
|
|
|
-
|
|
|
|
|
- {goods.length > 3 && (
|
|
|
|
|
- <Text className="text-sm text-gray-500 text-center mt-2">
|
|
|
|
|
- 共 {totalQuantity} 件商品
|
|
|
|
|
- </Text>
|
|
|
|
|
- )}
|
|
|
|
|
- </View>
|
|
|
|
|
-
|
|
|
|
|
- {/* 订单信息 */}
|
|
|
|
|
- <View className="border-t border-gray-100 pt-3">
|
|
|
|
|
- <View className="flex justify-between items-center mb-3">
|
|
|
|
|
- <Text className="text-sm text-gray-600">
|
|
|
|
|
- 实付款: ¥{order.payAmount.toFixed(2)}
|
|
|
|
|
- </Text>
|
|
|
|
|
- <Text className={`text-sm font-medium ${orderStatusMap[order.state as keyof typeof orderStatusMap].color}`}>
|
|
|
|
|
- {orderStatusMap[order.state as keyof typeof orderStatusMap].text}
|
|
|
|
|
- </Text>
|
|
|
|
|
- </View>
|
|
|
|
|
|
|
+ {allOrders.map((order) => (
|
|
|
|
|
+ <OrderCard
|
|
|
|
|
+ key={order.id}
|
|
|
|
|
+ order={order}
|
|
|
|
|
+ orderStatusMap={orderStatusMap}
|
|
|
|
|
+ payStatusMap={payStatusMap}
|
|
|
|
|
+ onViewDetail={handleOrderDetail}
|
|
|
|
|
+ />
|
|
|
|
|
+ ))}
|
|
|
|
|
|
|
|
- {/* 操作按钮 */}
|
|
|
|
|
- <View className="flex justify-end space-x-2">
|
|
|
|
|
- <Button
|
|
|
|
|
- size="sm"
|
|
|
|
|
- variant="outline"
|
|
|
|
|
- onClick={() => handleOrderDetail(order)}
|
|
|
|
|
- >
|
|
|
|
|
- 查看详情
|
|
|
|
|
- </Button>
|
|
|
|
|
-
|
|
|
|
|
- {order.payState === 0 && (
|
|
|
|
|
- <Button
|
|
|
|
|
- size="sm"
|
|
|
|
|
- variant="primary"
|
|
|
|
|
- onClick={() => {
|
|
|
|
|
- // 跳转到支付页面
|
|
|
|
|
- Taro.navigateTo({
|
|
|
|
|
- url: `/pages/payment/index?orderId=${order.id}&amount=${order.payAmount}`
|
|
|
|
|
- })
|
|
|
|
|
- }}
|
|
|
|
|
- >
|
|
|
|
|
- 去支付
|
|
|
|
|
- </Button>
|
|
|
|
|
- )}
|
|
|
|
|
-
|
|
|
|
|
- {order.state === 2 && (
|
|
|
|
|
- <Button
|
|
|
|
|
- size="sm"
|
|
|
|
|
- variant="outline"
|
|
|
|
|
- onClick={() => {
|
|
|
|
|
- // 申请退款
|
|
|
|
|
- Taro.showModal({
|
|
|
|
|
- title: '确认收货',
|
|
|
|
|
- content: '确认已收到商品吗?',
|
|
|
|
|
- success: (res) => {
|
|
|
|
|
- if (res.confirm) {
|
|
|
|
|
- // 这里可以调用确认收货的API
|
|
|
|
|
- Taro.showToast({
|
|
|
|
|
- title: '已确认收货',
|
|
|
|
|
- icon: 'success'
|
|
|
|
|
- })
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
- }}
|
|
|
|
|
- >
|
|
|
|
|
- 确认收货
|
|
|
|
|
- </Button>
|
|
|
|
|
- )}
|
|
|
|
|
- </View>
|
|
|
|
|
- </View>
|
|
|
|
|
- </View>
|
|
|
|
|
- </Card>
|
|
|
|
|
- )
|
|
|
|
|
- })}
|
|
|
|
|
-
|
|
|
|
|
{isFetchingNextPage && (
|
|
{isFetchingNextPage && (
|
|
|
<View className="flex justify-center py-4">
|
|
<View className="flex justify-center py-4">
|
|
|
- <View className="i-heroicons-arrow-path-20-solid animate-spin w-6 h-6 text-blue-500" />
|
|
|
|
|
|
|
+ <View className="i-heroicons-arrow-path-20-solid animate-spin w-6 h-6 text-primary" />
|
|
|
<Text className="ml-2 text-sm text-gray-500">加载更多...</Text>
|
|
<Text className="ml-2 text-sm text-gray-500">加载更多...</Text>
|
|
|
</View>
|
|
</View>
|
|
|
)}
|
|
)}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
{!hasNextPage && allOrders.length > 0 && (
|
|
{!hasNextPage && allOrders.length > 0 && (
|
|
|
<View className="text-center py-4 text-sm text-gray-400">
|
|
<View className="text-center py-4 text-sm text-gray-400">
|
|
|
没有更多了
|
|
没有更多了
|
|
|
</View>
|
|
</View>
|
|
|
)}
|
|
)}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
{!isLoading && allOrders.length === 0 && (
|
|
{!isLoading && allOrders.length === 0 && (
|
|
|
<View className="flex flex-col items-center py-20">
|
|
<View className="flex flex-col items-center py-20">
|
|
|
<View className="i-heroicons-clipboard-document-list-20-solid w-16 h-16 text-gray-300 mb-4" />
|
|
<View className="i-heroicons-clipboard-document-list-20-solid w-16 h-16 text-gray-300 mb-4" />
|
|
|
<Text className="text-gray-500 mb-4">暂无订单</Text>
|
|
<Text className="text-gray-500 mb-4">暂无订单</Text>
|
|
|
- <Button
|
|
|
|
|
|
|
+ <View
|
|
|
|
|
+ className="bg-primary text-white px-6 py-2 rounded-full text-sm font-medium"
|
|
|
onClick={() => Taro.navigateTo({ url: '/pages/goods-list/index' })}
|
|
onClick={() => Taro.navigateTo({ url: '/pages/goods-list/index' })}
|
|
|
>
|
|
>
|
|
|
去购物
|
|
去购物
|
|
|
- </Button>
|
|
|
|
|
|
|
+ </View>
|
|
|
</View>
|
|
</View>
|
|
|
)}
|
|
)}
|
|
|
</>
|
|
</>
|