弱网核销功能
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||
import WeakNetFallbackPanel from '../components/WeakNetFallbackPanel';
|
||||
import { request } from '../lib/api';
|
||||
import { reportRedeemFailure } from '../lib/redeem-failure';
|
||||
|
||||
function formatAmount(n: number) {
|
||||
return n.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
||||
@@ -23,6 +25,8 @@ export default function RedeemConfirmPage() {
|
||||
const [storeName, setStoreName] = useState('');
|
||||
const [preview, setPreview] = useState<Preview | null>(null);
|
||||
const [storeClosed, setStoreClosed] = useState(false);
|
||||
const [failCount, setFailCount] = useState(0);
|
||||
const [showWeakNet, setShowWeakNet] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
request<Record<string, unknown>>('SHOP_H5', '/shop/store')
|
||||
@@ -52,9 +56,16 @@ export default function RedeemConfirmPage() {
|
||||
body: JSON.stringify({ token }),
|
||||
})
|
||||
.then(setPreview)
|
||||
.catch((e) => {
|
||||
.catch(async (e) => {
|
||||
setPreview(null);
|
||||
setMsg(e instanceof Error ? e.message : '无法预览核销码');
|
||||
const report = await reportRedeemFailure(token, 'preview', e);
|
||||
if (report?.thresholdReached) {
|
||||
setFailCount(report.failCount);
|
||||
setShowWeakNet(true);
|
||||
} else if (report) {
|
||||
setFailCount(report.failCount);
|
||||
}
|
||||
});
|
||||
}, [token]);
|
||||
|
||||
@@ -78,6 +89,13 @@ export default function RedeemConfirmPage() {
|
||||
navigate('/redeem/success', { state: { result, storeName, user: preview?.user } });
|
||||
} catch (e) {
|
||||
setMsg(e instanceof Error ? e.message : '核销失败');
|
||||
const report = await reportRedeemFailure(token, 'confirm', e);
|
||||
if (report?.thresholdReached) {
|
||||
setFailCount(report.failCount);
|
||||
setShowWeakNet(true);
|
||||
} else if (report) {
|
||||
setFailCount(report.failCount);
|
||||
}
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -139,8 +157,10 @@ export default function RedeemConfirmPage() {
|
||||
|
||||
<div className="shop-redeem-details">
|
||||
<div className="shop-redeem-detail-row">
|
||||
<span>券编号</span>
|
||||
<span>{token ? `…${token.slice(-8)}` : '扫码后显示'}</span>
|
||||
<span>核销码 ID</span>
|
||||
<span style={{ wordBreak: 'break-all', maxWidth: '60%', textAlign: 'right' }}>
|
||||
{token || '扫码后显示'}
|
||||
</span>
|
||||
</div>
|
||||
<div className="shop-redeem-detail-row">
|
||||
<span>有效期</span>
|
||||
@@ -152,26 +172,39 @@ export default function RedeemConfirmPage() {
|
||||
<span>仅限指定门店</span>
|
||||
</div>
|
||||
)}
|
||||
{failCount > 0 && !showWeakNet && (
|
||||
<div className="shop-redeem-detail-row">
|
||||
<span>网络失败</span>
|
||||
<span>{failCount} / 5 次</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{msg && <p className="shop-redeem-error">{msg}</p>}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className={`shop-redeem-confirm-btn${loading ? ' success' : ''}`}
|
||||
disabled={loading || storeClosed || !preview}
|
||||
onClick={confirm}
|
||||
>
|
||||
<span className="material-symbols-outlined shop-fill-icon">
|
||||
{loading ? 'sync' : 'check_circle'}
|
||||
</span>
|
||||
<span>{loading ? '正在核销...' : preview ? `确认核销 ¥${formatAmount(previewAmount)}` : '加载中…'}</span>
|
||||
</button>
|
||||
|
||||
<p className="shop-redeem-hint">请核对金额后点击确认</p>
|
||||
{!showWeakNet && (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
className={`shop-redeem-confirm-btn${loading ? ' success' : ''}`}
|
||||
disabled={loading || storeClosed || !preview}
|
||||
onClick={() => void confirm()}
|
||||
>
|
||||
<span className="material-symbols-outlined shop-fill-icon">
|
||||
{loading ? 'sync' : 'check_circle'}
|
||||
</span>
|
||||
<span>{loading ? '正在核销...' : preview ? `确认核销 ¥${formatAmount(previewAmount)}` : '加载中…'}</span>
|
||||
</button>
|
||||
<p className="shop-redeem-hint">请核对金额后点击确认</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{showWeakNet && token && (
|
||||
<WeakNetFallbackPanel redeemToken={token} failCount={failCount} />
|
||||
)}
|
||||
|
||||
<div className="shop-redeem-ornament">
|
||||
<span className="material-symbols-outlined" style={{ fontSize: 64, color: 'var(--color-heritage-red)' }}>
|
||||
wine_bar
|
||||
|
||||
Reference in New Issue
Block a user