init
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { request } from '../lib/api';
|
||||
|
||||
function formatAmount(n: number) {
|
||||
return n.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
||||
}
|
||||
|
||||
export default function RedeemConfirmPage() {
|
||||
const navigate = useNavigate();
|
||||
const [token, setToken] = useState('');
|
||||
const [msg, setMsg] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [storeName, setStoreName] = useState('');
|
||||
const [previewAmount, setPreviewAmount] = useState(100);
|
||||
|
||||
useEffect(() => {
|
||||
request<Record<string, unknown>>('SHOP_H5', '/shop/store')
|
||||
.then((s) => setStoreName(String(s.name || '当前门店')))
|
||||
.catch(() => setStoreName('当前门店'));
|
||||
}, []);
|
||||
|
||||
async function confirm() {
|
||||
if (!token.trim()) {
|
||||
setMsg('请在开发者选项中输入核销码');
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
setMsg('');
|
||||
try {
|
||||
const result = await request<Record<string, unknown>>('SHOP_H5', '/shop/redeem/confirm', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ token }),
|
||||
});
|
||||
sessionStorage.setItem('lastRedeemResult', JSON.stringify(result));
|
||||
navigate('/redeem/success', { state: { result, storeName } });
|
||||
} catch (e) {
|
||||
setMsg(e instanceof Error ? e.message : '核销失败');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="shop-redeem-page">
|
||||
<header className="shop-redeem-header">
|
||||
<button type="button" className="shop-redeem-back" onClick={() => navigate(-1)} aria-label="返回">
|
||||
<span className="material-symbols-outlined">arrow_back</span>
|
||||
</button>
|
||||
<h1 className="app-page-title">核销确认</h1>
|
||||
</header>
|
||||
|
||||
<main className="shop-redeem-main">
|
||||
<section className="shop-redeem-card">
|
||||
<div className="shop-redeem-banner">
|
||||
<div className="shop-redeem-banner-icon">
|
||||
<span className="material-symbols-outlined shop-fill-icon">verified_user</span>
|
||||
</div>
|
||||
<div>
|
||||
<p className="shop-redeem-banner-label">当前登录核销门店</p>
|
||||
<h2 className="shop-redeem-banner-name">{storeName}</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="shop-redeem-body">
|
||||
<div className="shop-redeem-user">
|
||||
<div className="shop-redeem-user-left">
|
||||
<span className="material-symbols-outlined">person</span>
|
||||
<span>下单用户</span>
|
||||
</div>
|
||||
<span className="headline-md" style={{ fontFamily: 'var(--font-headline)', fontWeight: 600 }}>
|
||||
待扫码确认
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="shop-redeem-amount-section">
|
||||
<span className="shop-redeem-notch shop-redeem-notch--left" />
|
||||
<span className="shop-redeem-notch shop-redeem-notch--right" />
|
||||
<p className="shop-redeem-amount-label">核销金额</p>
|
||||
<div className="shop-redeem-amount">
|
||||
<span className="shop-redeem-amount-symbol">¥</span>
|
||||
<span className="shop-redeem-amount-value">{formatAmount(previewAmount)}</span>
|
||||
</div>
|
||||
<span className="shop-redeem-benefit">
|
||||
<span className="material-symbols-outlined shop-fill-icon" style={{ fontSize: 16, color: 'var(--color-aged-amber)' }}>
|
||||
confirmation_number
|
||||
</span>
|
||||
好客权益
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="shop-redeem-details">
|
||||
<div className="shop-redeem-detail-row">
|
||||
<span>券编号</span>
|
||||
<span>{token ? `…${token.slice(-8)}` : '扫码后显示'}</span>
|
||||
</div>
|
||||
<div className="shop-redeem-detail-row">
|
||||
<span>有效期</span>
|
||||
<span>永久</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{msg && <p className="shop-redeem-error">{msg}</p>}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className={`shop-redeem-confirm-btn${loading ? ' success' : ''}`}
|
||||
disabled={loading}
|
||||
onClick={confirm}
|
||||
>
|
||||
<span className="material-symbols-outlined shop-fill-icon">
|
||||
{loading ? 'sync' : 'check_circle'}
|
||||
</span>
|
||||
<span>{loading ? '正在核销...' : `确认核销 ¥${formatAmount(previewAmount)}`}</span>
|
||||
</button>
|
||||
|
||||
<p className="shop-redeem-hint">请核对金额后点击确认</p>
|
||||
|
||||
<details className="shop-redeem-dev">
|
||||
<summary>开发者选项 · 手动输入核销码</summary>
|
||||
<div className="shop-redeem-dev-body">
|
||||
<input
|
||||
value={token}
|
||||
onChange={(e) => {
|
||||
setToken(e.target.value);
|
||||
if (e.target.value) setPreviewAmount(100);
|
||||
}}
|
||||
placeholder="粘贴用户核销码"
|
||||
/>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div className="shop-redeem-ornament">
|
||||
<span className="material-symbols-outlined" style={{ fontSize: 64, color: 'var(--color-heritage-red)' }}>
|
||||
wine_bar
|
||||
</span>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user