feat(assoc): v4.0.1 合伙人关联码、分佣账单与 H5 用户管理

订单佣金只认关联用户;合伙人备注写入独立表;H5 增加用户管理与首页统计。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-30 14:35:39 +08:00
parent 3b669f7e38
commit 9c8d5f2cad
125 changed files with 6355 additions and 1436 deletions
@@ -0,0 +1,67 @@
import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import PageHeader from '@dukang/shared-ui/PageHeader';
import PullToRefresh from '@dukang/shared-ui/PullToRefresh';
import type { PartnerCommissionOrderItem } from '@dukang/shared-types';
import { request } from '../lib/api';
import { toastError } from '../lib/toast';
import { usePartnerPageView } from '../lib/usePageView';
function fmtMoney(n: number) {
return n.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
}
type ListRes = { items: PartnerCommissionOrderItem[]; total: number };
export default function CommissionOrdersPage() {
usePartnerPageView('partner_commission_orders_view');
const navigate = useNavigate();
const [items, setItems] = useState<PartnerCommissionOrderItem[]>([]);
const [total, setTotal] = useState(0);
const [loading, setLoading] = useState(true);
async function load() {
setLoading(true);
try {
const res = await request<ListRes>('PARTNER_H5', '/partner/commissions/orders?page=1&pageSize=50');
setItems(res.items ?? []);
setTotal(res.total ?? 0);
} catch (e) {
toastError(e instanceof Error ? e.message : '加载失败');
setItems([]);
} finally {
setLoading(false);
}
}
useEffect(() => {
void load();
}, []);
return (
<PullToRefresh onRefresh={load}>
<PageHeader title="订单佣金" onBack={() => navigate(-1)} />
<div style={{ padding: '0 20px 24px' }}>
<p className="label-md text-muted" style={{ margin: '12px 0' }}>
{loading ? '加载中…' : `共 ${total} 笔关联酒单`}
</p>
{!loading && items.length === 0 && <div className="empty">暂无订单佣金</div>}
{items.map((o) => (
<div key={o.id} className="partner-store-card" style={{ marginBottom: 12 }}>
<div className="partner-store-card-header">
<div>
<p className="body-md">{o.productName}</p>
<p className="label-md text-muted">{o.orderNo} · ×{o.quantity}</p>
<p className="label-md text-muted">{o.paidAt ? o.paidAt.slice(0, 16).replace('T', ' ') : ''}</p>
</div>
<span className="amount-lg" style={{ fontSize: 18 }}>¥{fmtMoney(o.commission)}</span>
</div>
<p className="label-md text-muted">
实付 ¥{fmtMoney(o.payAmount)} × {((o.rate ?? 0) * 100).toFixed(2)}%
</p>
</div>
))}
</div>
</PullToRefresh>
);
}