ebd8c07147
支付后返回:支付成功进详情带 from=pay;返回一律 switchTab 首页(失败则 reLaunch),避免栈只有一页时 navigateBack 退出小程序。订单列表返回同样加固。
185 lines
6.3 KiB
TypeScript
185 lines
6.3 KiB
TypeScript
import { useCallback, useEffect, useState } from 'react';
|
|
import { View, Text, Image } from '@tarojs/components';
|
|
import Taro, { useDidShow, usePullDownRefresh, useRouter } from '@tarojs/taro';
|
|
import PageShell from '../../components/PageShell';
|
|
import SubPageHeader from '../../components/SubPageHeader';
|
|
import { request, toast } from '../../lib/api';
|
|
import { buildPayUrl } from '../../lib/checkout-nav';
|
|
|
|
import { ORDER_STATUS_LABELS } from '@dukang/shared-types';
|
|
|
|
const TABS = [
|
|
{ key: 'all', label: '全部订单' },
|
|
{ key: 'pending_pay', label: '待付款' },
|
|
{ key: 'paid', label: '已付款' },
|
|
{ key: 'completed', label: '已完成' },
|
|
] as const;
|
|
|
|
/** 兼容历史链接 tab=done */
|
|
function normalizeOrdersTab(raw?: string): string {
|
|
if (!raw) return 'all';
|
|
if (raw === 'done') return 'completed';
|
|
return TABS.some((t) => t.key === raw) ? raw : 'all';
|
|
}
|
|
|
|
function orderStatusLabel(tab: string, status?: string): string {
|
|
const tabLabel = TABS.find((t) => t.key === tab)?.label;
|
|
if (tab !== 'all' && tabLabel) return tabLabel;
|
|
if (!status) return '';
|
|
return ORDER_STATUS_LABELS[status] || status;
|
|
}
|
|
|
|
type OrderItem = {
|
|
productName?: string;
|
|
productImage?: string;
|
|
unitPrice?: number;
|
|
quantity?: number;
|
|
};
|
|
|
|
type OrderRow = {
|
|
id: string;
|
|
orderNo?: string;
|
|
status?: string;
|
|
payAmount?: number;
|
|
productName?: string;
|
|
qty?: number;
|
|
quantity?: number;
|
|
originOrderId?: string | null;
|
|
orderType?: string;
|
|
isProxyOrder?: boolean;
|
|
proxyPartnerName?: string | null;
|
|
items?: OrderItem[];
|
|
};
|
|
|
|
export default function OrdersPage() {
|
|
const router = useRouter();
|
|
const [tab, setTab] = useState(() => normalizeOrdersTab(router.params.tab as string));
|
|
const [orders, setOrders] = useState<OrderRow[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
const loadOrders = useCallback(() => {
|
|
setLoading(true);
|
|
return request<{ list?: OrderRow[]; items?: OrderRow[]; total?: number } | OrderRow[]>(
|
|
`/trade/orders?tab=${encodeURIComponent(tab)}&pageSize=20`,
|
|
)
|
|
.then((data) => {
|
|
if (Array.isArray(data)) setOrders(data);
|
|
else setOrders(Array.isArray(data?.list) ? data.list : Array.isArray(data?.items) ? data.items : []);
|
|
})
|
|
.catch((e) => {
|
|
toast(e instanceof Error ? e.message : '加载失败');
|
|
setOrders([]);
|
|
})
|
|
.finally(() => setLoading(false));
|
|
}, [tab]);
|
|
|
|
useEffect(() => {
|
|
void loadOrders();
|
|
}, [loadOrders]);
|
|
|
|
useDidShow(() => {
|
|
const next = normalizeOrdersTab(router.params.tab as string);
|
|
if (next !== tab) setTab(next);
|
|
else void loadOrders();
|
|
});
|
|
|
|
usePullDownRefresh(() => {
|
|
void loadOrders().finally(() => Taro.stopPullDownRefresh());
|
|
});
|
|
|
|
function goPay(orderId: string) {
|
|
Taro.navigateTo({ url: buildPayUrl({ orderId }) });
|
|
}
|
|
|
|
return (
|
|
<PageShell variant="sub" className="orders-page">
|
|
<SubPageHeader
|
|
title="我的订单"
|
|
onBack={() => {
|
|
Taro.switchTab({ url: '/pages/home/index' }).catch(() => {
|
|
Taro.reLaunch({ url: '/pages/home/index' });
|
|
});
|
|
}}
|
|
/>
|
|
<View className="order-tabs">
|
|
{TABS.map((t) => (
|
|
<Text
|
|
key={t.key}
|
|
className={`order-tab${tab === t.key ? ' order-tab--active' : ''}`}
|
|
onClick={() => setTab(t.key)}
|
|
>
|
|
{t.label}
|
|
</Text>
|
|
))}
|
|
</View>
|
|
|
|
{loading ? <View className="u-empty">加载中…</View> : null}
|
|
{!loading && orders.length === 0 ? <View className="u-empty">暂无订单</View> : null}
|
|
{!loading &&
|
|
orders.map((o) => {
|
|
const item = o.items?.[0];
|
|
const productName = item?.productName || o.productName || '杜康商品';
|
|
const productImage = (item?.productImage || '').trim();
|
|
const qty = item?.quantity ?? o.quantity ?? o.qty ?? 1;
|
|
const unitPrice = Number(item?.unitPrice ?? 0);
|
|
const canPay = o.status === 'PENDING_PAY' && !o.originOrderId;
|
|
const isProxy = o.isProxyOrder || o.orderType === 'PROXY';
|
|
|
|
return (
|
|
<View
|
|
key={o.id}
|
|
className="order-list-item"
|
|
onClick={() => Taro.navigateTo({ url: `/pages/order-detail/index?id=${o.id}` })}
|
|
>
|
|
<View className="order-list-head">
|
|
<View className="order-list-head-left">
|
|
<Text className="order-list-no">{o.orderNo || o.id}</Text>
|
|
{isProxy ? <Text className="order-proxy-badge">代下单</Text> : null}
|
|
</View>
|
|
<Text className="order-list-status">
|
|
{orderStatusLabel(tab, o.status)}
|
|
</Text>
|
|
</View>
|
|
{isProxy && o.proxyPartnerName ? (
|
|
<Text className="order-proxy-hint">由合伙人 {o.proxyPartnerName} 代下</Text>
|
|
) : null}
|
|
<View className="order-list-body">
|
|
<View className="order-list-thumb">
|
|
{productImage ? (
|
|
<Image className="order-list-thumb-img" src={productImage} mode="aspectFill" />
|
|
) : null}
|
|
</View>
|
|
<View style={{ flex: 1, minWidth: 0 }}>
|
|
<Text className="order-list-name">{productName}</Text>
|
|
<View className="order-list-meta-row">
|
|
<Text className="order-list-meta">数量 {qty}</Text>
|
|
<Text className="order-list-meta">单价 ¥{unitPrice.toFixed(2)}</Text>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
<View className="order-list-footer">
|
|
<View className="order-list-pay-amount">
|
|
<Text className="order-list-meta">实付</Text>
|
|
<Text className="order-product-price">
|
|
¥{Number(o.payAmount ?? 0).toFixed(2)}
|
|
</Text>
|
|
</View>
|
|
{canPay ? (
|
|
<View
|
|
className="order-list-pay-btn"
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
goPay(o.id);
|
|
}}
|
|
>
|
|
付款
|
|
</View>
|
|
) : null}
|
|
</View>
|
|
</View>
|
|
);
|
|
})}
|
|
</PageShell>
|
|
);
|
|
}
|