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
+42 -11
View File
@@ -2,7 +2,7 @@ import { useEffect, useMemo, useState } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';
import PageHeader from '@dukang/shared-ui/PageHeader';
import PullToRefresh from '@dukang/shared-ui/PullToRefresh';
import type { PartnerBillDto } from '@dukang/shared-types';
import type { PartnerBillDetailDto, PartnerBillDto, PartnerBillItemDto } from '@dukang/shared-types';
import { isLoggedIn, request } from '../lib/api';
import { toastError, toastSuccess } from '../lib/toast';
import { usePartnerPageView } from '../lib/usePageView';
@@ -34,6 +34,7 @@ export default function BillsPage() {
const [submitting, setSubmitting] = useState(false);
const [loading, setLoading] = useState(true);
const [selectedIds, setSelectedIds] = useState<string[]>([]);
const [detail, setDetail] = useState<PartnerBillDetailDto | null>(null);
async function loadBills() {
setLoading(true);
@@ -67,6 +68,44 @@ export default function BillsPage() {
const isRejected = status === 'REJECTED';
const isPaid = status === 'PAID';
useEffect(() => {
if (!bill?.id) {
setDetail(null);
return;
}
request<PartnerBillDetailDto>('PARTNER_H5', `/partner/settlement/bills/${bill.id}`)
.then(setDetail)
.catch(() => setDetail(null));
}, [bill?.id]);
function renderItemList(title: string, items: PartnerBillItemDto[] | undefined, subtotal: number) {
const list = items ?? [];
return (
<div style={{ marginTop: 16 }}>
<div className="partner-info-row" style={{ marginBottom: 8 }}>
<span className="body-md" style={{ fontWeight: 700 }}>{title}</span>
<span className="body-md" style={{ fontWeight: 700 }}>¥ {fmtMoney(subtotal)}</span>
</div>
{list.length === 0 ? (
<p className="label-md text-muted">本账期无明细</p>
) : (
list.map((it) => (
<div key={it.id} className="partner-info-row" style={{ alignItems: 'flex-start' }}>
<div>
<p className="body-md">{it.title || it.refNo}</p>
<p className="label-md text-muted">
{it.refNo}
{it.extra ? ` ${it.extra}` : ''} · {((it.rate ?? 0) * 100).toFixed(2)}%
</p>
</div>
<span className="body-md">¥ {fmtMoney(it.commission)}</span>
</div>
))
)}
</div>
);
}
function askConfirm(ids: string[]) {
if (!window.confirm(`确认 ${ids.length} 笔账单无误并提交?确认后状态将变为「未打款」,等待总部打款。`)) {
return;
@@ -183,16 +222,8 @@ export default function BillsPage() {
</div>
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
<div className="partner-info-row">
<span className="text-variant body-md">订单分佣收入</span>
<span className="body-md" style={{ fontWeight: 700 }}>¥ {fmtMoney(Number(bill.orderCommission || 0))}</span>
</div>
<div className="partner-info-row">
<span className="text-variant body-md">核销权益分佣</span>
<span className="body-md" style={{ fontWeight: 700 }}>¥ {fmtMoney(Number(bill.redeemCommission || 0))}</span>
</div>
</div>
{renderItemList('酒订单', detail?.orderItems, Number(detail?.orderCommission ?? bill.orderCommission ?? 0))}
{renderItemList('核销订单', detail?.redeemItems, Number(detail?.redeemCommission ?? bill.redeemCommission ?? 0))}
</div>
</section>
)}