Files
dukang/apps/mini-user/src/pages/orders/index.tsx
T
jacy ebd8c07147 数量加减:同城/跨城/现场取货确认页加减号不再置灰;点减到低于起购时 toast,数量仍可降到 1(不能到 0)。
支付后返回:支付成功进详情带 from=pay;返回一律 switchTab 首页(失败则 reLaunch),避免栈只有一页时 navigateBack 退出小程序。订单列表返回同样加固。
2026-08-03 13:22:12 +08:00

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>
);
}