feat(assoc): v4.0.1 合伙人关联码、分佣账单与 H5 用户管理
订单佣金只认关联用户;合伙人备注写入独立表;H5 增加用户管理与首页统计。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import PageHeader from '@dukang/shared-ui/PageHeader';
|
||||
import type { PartnerAssocSummary } from '@dukang/shared-types';
|
||||
import { request } from '../lib/api';
|
||||
import { toastError, toastSuccess } from '../lib/toast';
|
||||
import { isWechatEnv } from '../lib/weixin';
|
||||
import { usePartnerPageView } from '../lib/usePageView';
|
||||
|
||||
export default function AssocQrcodePage() {
|
||||
usePartnerPageView('partner_assoc_qrcode_view');
|
||||
const navigate = useNavigate();
|
||||
const [summary, setSummary] = useState<PartnerAssocSummary | null>(null);
|
||||
const [previewUrl, setPreviewUrl] = useState<string | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
request<PartnerAssocSummary>('PARTNER_H5', '/partner/assoc')
|
||||
.then(setSummary)
|
||||
.catch((e) => toastError(e instanceof Error ? e.message : '加载失败'))
|
||||
.finally(() => setLoading(false));
|
||||
}, []);
|
||||
|
||||
useEffect(() => () => {
|
||||
if (previewUrl) URL.revokeObjectURL(previewUrl);
|
||||
}, [previewUrl]);
|
||||
|
||||
async function downloadQr() {
|
||||
const token = localStorage.getItem('accessToken');
|
||||
try {
|
||||
const res = await fetch('/api/v1/partner/assoc/qrcode', {
|
||||
headers: {
|
||||
Authorization: token ? `Bearer ${token}` : '',
|
||||
'X-Client-App': 'PARTNER_H5',
|
||||
},
|
||||
});
|
||||
if (!res.ok) throw new Error('下载失败');
|
||||
const blob = await res.blob();
|
||||
const url = URL.createObjectURL(blob);
|
||||
if (isWechatEnv()) {
|
||||
setPreviewUrl(url);
|
||||
toastSuccess('请长按图片保存到相册');
|
||||
return;
|
||||
}
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `partner-assoc-${summary?.partnerId || 'qr'}.png`;
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
toastSuccess('已开始下载');
|
||||
} catch (e) {
|
||||
if (summary?.qrcodeUrl) {
|
||||
setPreviewUrl(summary.qrcodeUrl);
|
||||
toastSuccess('请长按图片保存到相册');
|
||||
return;
|
||||
}
|
||||
toastError(e instanceof Error ? e.message : '下载失败');
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PageHeader title="关联码" onBack={() => navigate(-1)} />
|
||||
{loading && <div className="empty">加载中…</div>}
|
||||
{!loading && (
|
||||
<section className="partner-bill-card" style={{ margin: 16 }}>
|
||||
<div style={{ padding: 24, textAlign: 'center' }}>
|
||||
<p className="body-md text-muted" style={{ marginBottom: 16 }}>
|
||||
用户扫码后首次锁定本合伙人,后续酒单按订单佣金结算
|
||||
</p>
|
||||
{summary?.qrcodeUrl ? (
|
||||
<img
|
||||
src={previewUrl || summary.qrcodeUrl}
|
||||
alt="关联码"
|
||||
style={{ width: 220, height: 220, background: '#fff' }}
|
||||
/>
|
||||
) : (
|
||||
<p className="body-md text-muted">关联码尚未生成,请稍后重试或联系总部补发</p>
|
||||
)}
|
||||
<p className="label-md text-muted" style={{ marginTop: 12 }}>
|
||||
已关联 {summary?.userCount ?? 0} 人
|
||||
</p>
|
||||
<button type="button" className="partner-btn-primary" style={{ marginTop: 20 }} onClick={() => void downloadQr()}>
|
||||
下载二维码
|
||||
</button>
|
||||
{previewUrl && isWechatEnv() && (
|
||||
<p className="label-md text-muted" style={{ marginTop: 12 }}>
|
||||
微信内请长按上方图片保存
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user