150 lines
5.5 KiB
TypeScript
150 lines
5.5 KiB
TypeScript
import { useCallback, useEffect, useState, type FormEvent } from 'react';
|
||
import { Link, useNavigate } from 'react-router-dom';
|
||
import PageHeader from '@dukang/shared-ui/PageHeader';
|
||
import PullToRefresh from '@dukang/shared-ui/PullToRefresh';
|
||
import type { PartnerProxyOrderListItem, PartnerProxyOrderListResponse } from '@dukang/shared-types';
|
||
import { isLoggedIn, request } from '../lib/api';
|
||
import {
|
||
proxyOrderStatusColor,
|
||
proxyOrderStatusLabel,
|
||
} from '../lib/proxyOrderStatus';
|
||
|
||
function fmtMoney(n: number) {
|
||
return n.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
||
}
|
||
|
||
function fmtTime(value: string | undefined) {
|
||
if (!value) return '—';
|
||
const d = new Date(value);
|
||
if (Number.isNaN(d.getTime())) return value;
|
||
const pad = (n: number) => String(n).padStart(2, '0');
|
||
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
||
}
|
||
|
||
function deliveryLabel(item: PartnerProxyOrderListItem) {
|
||
const t = String(item.deliveryType || '').toUpperCase();
|
||
if (t === 'ON_SITE_PICKUP') return '现场提货';
|
||
if (t === 'CROSS_CITY') return '跨城配送';
|
||
if (t === 'LOCAL') return '同城配送';
|
||
return '线下代下单';
|
||
}
|
||
|
||
function coverUrl(item: PartnerProxyOrderListItem) {
|
||
return item.imageResource?.url || '';
|
||
}
|
||
|
||
export default function ProxyOrderListPage() {
|
||
const navigate = useNavigate();
|
||
const [list, setList] = useState<PartnerProxyOrderListItem[]>([]);
|
||
const [total, setTotal] = useState(0);
|
||
const [keyword, setKeyword] = useState('');
|
||
const [q, setQ] = useState('');
|
||
const [loading, setLoading] = useState(true);
|
||
|
||
const loadList = useCallback(() => {
|
||
if (!isLoggedIn()) {
|
||
navigate('/login');
|
||
return Promise.resolve();
|
||
}
|
||
setLoading(true);
|
||
const params = new URLSearchParams({ page: '1', pageSize: '50' });
|
||
if (q.trim()) params.set('keyword', q.trim());
|
||
return request<PartnerProxyOrderListResponse>('PARTNER_H5', `/partner/proxy-orders?${params}`)
|
||
.then((res) => {
|
||
setList(Array.isArray(res.list) ? res.list : []);
|
||
setTotal(Number(res.total) || 0);
|
||
})
|
||
.catch(() => {
|
||
setList([]);
|
||
setTotal(0);
|
||
})
|
||
.finally(() => setLoading(false));
|
||
}, [navigate, q]);
|
||
|
||
useEffect(() => {
|
||
document.title = '代下单列表';
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
void loadList();
|
||
}, [loadList]);
|
||
|
||
function submitSearch(e: FormEvent) {
|
||
e.preventDefault();
|
||
setQ(keyword.trim());
|
||
}
|
||
|
||
return (
|
||
<PullToRefresh onRefresh={loadList} className="page-no-tab partner-orders-page">
|
||
<PageHeader title="代下单列表" onBack={() => navigate('/center')} />
|
||
|
||
<div style={{ padding: '0 20px 12px' }}>
|
||
<form className="partner-search" onSubmit={submitSearch}>
|
||
<span className="material-symbols-outlined">search</span>
|
||
<input
|
||
placeholder="订单号 / 手机号 / 姓名 / 商品"
|
||
value={keyword}
|
||
onChange={(e) => setKeyword(e.target.value)}
|
||
/>
|
||
</form>
|
||
<p className="label-md text-muted" style={{ marginTop: 8 }}>
|
||
{loading ? '加载中…' : `共 ${total} 笔代下单`}
|
||
</p>
|
||
</div>
|
||
|
||
<div style={{ padding: '0 16px 24px' }}>
|
||
{!loading && list.length === 0 && <div className="empty">暂无代下单记录</div>}
|
||
|
||
{list.map((o) => {
|
||
const orderId = String(o.id);
|
||
const img = coverUrl(o);
|
||
return (
|
||
<Link key={orderId} to={`/center/proxy-orders/${orderId}`} className="partner-order-card" style={{ marginBottom: 12 }}>
|
||
<div className="partner-order-card-top">
|
||
<span className="label-md text-muted">NO. {o.orderNo}</span>
|
||
<span
|
||
className="label-md"
|
||
style={{ color: proxyOrderStatusColor(o.status), fontWeight: 600 }}
|
||
>
|
||
{proxyOrderStatusLabel(o.status)}
|
||
</span>
|
||
</div>
|
||
<div className="partner-order-product">
|
||
<div
|
||
className="partner-order-product-img"
|
||
style={{
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
overflow: 'hidden',
|
||
background: img ? `center/cover no-repeat url(${img})` : undefined,
|
||
}}
|
||
>
|
||
{!img && <span className="material-symbols-outlined text-muted">liquor</span>}
|
||
</div>
|
||
<div style={{ flex: 1, minWidth: 0 }}>
|
||
<h3 className="headline-md line-2-clamp">{o.productName || '杜康好酒'}</h3>
|
||
<p className="text-variant body-md" style={{ marginTop: 4 }}>
|
||
×{o.quantity} · ¥{fmtMoney(Number(o.payAmount || 0))}
|
||
</p>
|
||
<p className="label-md text-muted" style={{ marginTop: 4 }}>
|
||
{deliveryLabel(o)} · {fmtTime(o.createdAt)}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
<div className="partner-order-address">
|
||
<span className="material-symbols-outlined" style={{ fontSize: 18 }}>person</span>
|
||
<p className="line-2-clamp">
|
||
{o.receiverName || '客户'}
|
||
{o.receiverPhone ? ` · ${o.receiverPhone}` : ''}
|
||
{o.receiverAddress ? ` · ${o.receiverAddress}` : ''}
|
||
</p>
|
||
</div>
|
||
</Link>
|
||
);
|
||
})}
|
||
</div>
|
||
</PullToRefresh>
|
||
);
|
||
}
|