发布商品,商品图片使用oss服务器地址

This commit is contained in:
2026-07-06 08:53:03 +08:00
parent a0466f023e
commit 5ba69eb935
60 changed files with 2776 additions and 157 deletions
+52 -11
View File
@@ -6,6 +6,14 @@ function formatAmount(n: number) {
return n.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
}
type Preview = {
amount: number;
expireInSeconds: number;
user?: { userNo?: string; phone?: string; nickname?: string };
redeemType?: string;
boundStoreId?: string | null;
};
export default function RedeemConfirmPage() {
const navigate = useNavigate();
const [searchParams] = useSearchParams();
@@ -13,11 +21,15 @@ export default function RedeemConfirmPage() {
const [msg, setMsg] = useState('');
const [loading, setLoading] = useState(false);
const [storeName, setStoreName] = useState('');
const [previewAmount, setPreviewAmount] = useState(100);
const [preview, setPreview] = useState<Preview | null>(null);
const [storeClosed, setStoreClosed] = useState(false);
useEffect(() => {
request<Record<string, unknown>>('SHOP_H5', '/shop/store')
.then((s) => setStoreName(String(s.name || '当前门店')))
.then((s) => {
setStoreName(String(s.name || '当前门店'));
if (s.status && s.status !== 'OPEN') setStoreClosed(true);
})
.catch(() => setStoreName('当前门店'));
}, []);
@@ -26,7 +38,27 @@ export default function RedeemConfirmPage() {
if (scanned) setToken(scanned);
}, [searchParams]);
useEffect(() => {
if (!token.trim()) {
setPreview(null);
return;
}
request<Preview>('SHOP_H5', '/shop/redeem/preview', {
method: 'POST',
body: JSON.stringify({ token }),
})
.then(setPreview)
.catch((e) => {
setPreview(null);
setMsg(e instanceof Error ? e.message : '无法预览核销码');
});
}, [token]);
async function confirm() {
if (storeClosed) {
setMsg('门店未营业,无法核销');
return;
}
if (!token.trim()) {
setMsg('请在开发者选项中输入核销码');
return;
@@ -47,6 +79,9 @@ export default function RedeemConfirmPage() {
}
}
const previewAmount = preview?.amount ?? 0;
const userLabel = preview?.user?.nickname || preview?.user?.phone || preview?.user?.userNo || '待扫码确认';
return (
<div className="shop-redeem-page">
<header className="shop-redeem-header">
@@ -57,6 +92,9 @@ export default function RedeemConfirmPage() {
</header>
<main className="shop-redeem-main">
{storeClosed && (
<p className="shop-redeem-error" style={{ marginBottom: 12 }}></p>
)}
<section className="shop-redeem-card">
<div className="shop-redeem-banner">
<div className="shop-redeem-banner-icon">
@@ -75,7 +113,7 @@ export default function RedeemConfirmPage() {
<span></span>
</div>
<span className="headline-md" style={{ fontFamily: 'var(--font-headline)', fontWeight: 600 }}>
{userLabel}
</span>
</div>
@@ -91,7 +129,7 @@ export default function RedeemConfirmPage() {
<span className="material-symbols-outlined shop-fill-icon" style={{ fontSize: 16, color: 'var(--color-aged-amber)' }}>
confirmation_number
</span>
· {preview?.redeemType === 'COUPON' ? '单据核销' : '直接核销'}
</span>
</div>
@@ -102,8 +140,14 @@ export default function RedeemConfirmPage() {
</div>
<div className="shop-redeem-detail-row">
<span></span>
<span></span>
<span>{preview ? `${preview.expireInSeconds}` : '—'}</span>
</div>
{preview?.boundStoreId && (
<div className="shop-redeem-detail-row">
<span></span>
<span></span>
</div>
)}
</div>
{msg && <p className="shop-redeem-error">{msg}</p>}
@@ -111,13 +155,13 @@ export default function RedeemConfirmPage() {
<button
type="button"
className={`shop-redeem-confirm-btn${loading ? ' success' : ''}`}
disabled={loading}
disabled={loading || storeClosed || !preview}
onClick={confirm}
>
<span className="material-symbols-outlined shop-fill-icon">
{loading ? 'sync' : 'check_circle'}
</span>
<span>{loading ? '正在核销...' : `确认核销 ¥${formatAmount(previewAmount)}`}</span>
<span>{loading ? '正在核销...' : preview ? `确认核销 ¥${formatAmount(previewAmount)}` : '等待扫码'}</span>
</button>
<p className="shop-redeem-hint"></p>
@@ -127,10 +171,7 @@ export default function RedeemConfirmPage() {
<div className="shop-redeem-dev-body">
<input
value={token}
onChange={(e) => {
setToken(e.target.value);
if (e.target.value) setPreviewAmount(100);
}}
onChange={(e) => setToken(e.target.value)}
placeholder="粘贴用户核销码"
/>
</div>