feat(partner): complete proxy order with dual SMS and pickup
CI / verify (pull_request) Has been cancelled
CI / verify (pull_request) Has been cancelled
Add partner/customer SMS confirm, address auto-receive or on-site pickup, proxy placer fields, PARTNER_PROXY user source, and C-end badge. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||
import PageHeader from '@dukang/shared-ui/PageHeader';
|
||||
import { request } from '../lib/api';
|
||||
import { toastError } from '../lib/toast';
|
||||
import type { PartnerProxyOrderOptions, PartnerProxyOrderProductOption } from '@dukang/shared-types';
|
||||
|
||||
function fmtMoney(n: number) {
|
||||
return n.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
||||
}
|
||||
|
||||
export default function ProxyOrderProductsPage() {
|
||||
const navigate = useNavigate();
|
||||
const [searchParams] = useSearchParams();
|
||||
const selectedId = searchParams.get('selected') || '';
|
||||
const [products, setProducts] = useState<PartnerProxyOrderProductOption[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
request<PartnerProxyOrderOptions>('PARTNER_H5', '/partner/proxy-orders/options')
|
||||
.then((data) => setProducts(Array.isArray(data.products) ? data.products : []))
|
||||
.catch((e) => toastError(e instanceof Error ? e.message : '加载失败'))
|
||||
.finally(() => setLoading(false));
|
||||
}, []);
|
||||
|
||||
function pick(product: PartnerProxyOrderProductOption) {
|
||||
navigate(`/proxy-order?productId=${encodeURIComponent(product.id)}`, { replace: true });
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="page partner-proxy-order-page">
|
||||
<PageHeader title="选择酒品" onBack={() => navigate(-1)} />
|
||||
<main className="partner-proxy-product-list">
|
||||
{loading ? <p className="label-md text-muted">加载中…</p> : null}
|
||||
{!loading && products.length === 0 ? (
|
||||
<p className="label-md text-muted">暂无可售商品</p>
|
||||
) : null}
|
||||
{products.map((p) => {
|
||||
const benefit = p.benefitAmount != null ? Number(p.benefitAmount) : Number(p.price);
|
||||
const active = p.id === selectedId;
|
||||
return (
|
||||
<button
|
||||
key={p.id}
|
||||
type="button"
|
||||
className={`partner-proxy-product-card${active ? ' partner-proxy-product-card--active' : ''}`}
|
||||
onClick={() => pick(p)}
|
||||
>
|
||||
<div className="partner-proxy-product-thumb">
|
||||
{p.coverUrl ? (
|
||||
<img src={p.coverUrl} alt="" />
|
||||
) : (
|
||||
<span className="partner-proxy-product-thumb-empty" />
|
||||
)}
|
||||
</div>
|
||||
<div className="partner-proxy-product-main">
|
||||
<div className="partner-proxy-product-row">
|
||||
<span className="partner-proxy-product-name">{p.name}</span>
|
||||
<span className="partner-proxy-product-price">¥{fmtMoney(p.price)}</span>
|
||||
</div>
|
||||
<p className="partner-proxy-product-spec">{p.spec}</p>
|
||||
<p className="partner-proxy-product-benefit">好客权益 ¥{fmtMoney(benefit)}</p>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user