550697c346
去掉总部发送与合伙人确认,财务打款后上传凭证,合伙人即可查看状态。 Co-authored-by: Cursor <cursoragent@cursor.com>
176 lines
6.8 KiB
TypeScript
176 lines
6.8 KiB
TypeScript
import { useCallback, useEffect, useMemo, 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 { PartnerBillDto, PartnerSettlementPreviewDto } from '@dukang/shared-types';
|
|
import { isLoggedIn, request } from '../lib/api';
|
|
import { formatBillPeriod, formatIssueLabel } from '../lib/settlement';
|
|
|
|
type StatusFilter = 'all' | 'unpaid' | 'paid';
|
|
|
|
function fmtMoney(n: number) {
|
|
return n.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
|
}
|
|
|
|
function billStatusLabel(status: string) {
|
|
switch (status) {
|
|
case 'UNPAID': return '未打款';
|
|
case 'PAID': return '已打款';
|
|
default: return status;
|
|
}
|
|
}
|
|
|
|
function billStatusClass(status: string) {
|
|
switch (status) {
|
|
case 'UNPAID': return 'partner-settlement-status--reviewing';
|
|
case 'PAID': return 'partner-settlement-status--settled';
|
|
default: return '';
|
|
}
|
|
}
|
|
|
|
function billPeriodLabel(bill: PartnerBillDto) {
|
|
return formatBillPeriod(bill.periodStart, bill.periodEnd);
|
|
}
|
|
|
|
export default function SettlementPage() {
|
|
const navigate = useNavigate();
|
|
const [bills, setBills] = useState<PartnerBillDto[]>([]);
|
|
const [preview, setPreview] = useState<PartnerSettlementPreviewDto | null>(null);
|
|
const [statusFilter, setStatusFilter] = useState<StatusFilter>('all');
|
|
|
|
const loadBills = useCallback(() => {
|
|
return Promise.all([
|
|
request<PartnerBillDto[]>('PARTNER_H5', '/partner/settlement/bills').then(setBills),
|
|
request<PartnerSettlementPreviewDto>('PARTNER_H5', '/partner/settlement/preview')
|
|
.then(setPreview)
|
|
.catch(() => setPreview(null)),
|
|
]).then(() => undefined);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (!isLoggedIn()) { navigate('/login'); return; }
|
|
void loadBills();
|
|
}, [navigate, loadBills]);
|
|
|
|
const summary = useMemo(() => {
|
|
const unpaid = bills.filter((b) => b.status === 'UNPAID');
|
|
const settled = bills.filter((b) => b.status === 'PAID');
|
|
return {
|
|
pendingTotal: unpaid.reduce((s, b) => s + Number(b.totalAmount || 0), 0),
|
|
settledTotal: settled.reduce((s, b) => s + Number(b.totalAmount || 0), 0),
|
|
};
|
|
}, [bills]);
|
|
|
|
const filteredBills = useMemo(() => {
|
|
return bills.filter((b) => {
|
|
if (statusFilter === 'all') return true;
|
|
if (statusFilter === 'unpaid') return b.status === 'UNPAID';
|
|
if (statusFilter === 'paid') return b.status === 'PAID';
|
|
return true;
|
|
});
|
|
}, [bills, statusFilter]);
|
|
|
|
function openBill(bill: PartnerBillDto) {
|
|
navigate(bill.id ? `/center/bills?id=${bill.id}` : '/center/bills');
|
|
}
|
|
|
|
const statusTabs: Array<{ key: StatusFilter; label: string }> = [
|
|
{ key: 'all', label: '全部' },
|
|
{ key: 'unpaid', label: '未打款' },
|
|
{ key: 'paid', label: '已打款' },
|
|
];
|
|
|
|
return (
|
|
<PullToRefresh onRefresh={loadBills} className="page-no-tab partner-settlement-page">
|
|
<PageHeader title="财务对账中心" onBack={() => navigate('/')} />
|
|
|
|
<main className="partner-settlement-body">
|
|
<section className="partner-settlement-summary">
|
|
<div className="partner-settlement-summary-deco" aria-hidden>
|
|
<span className="material-symbols-outlined">account_balance_wallet</span>
|
|
</div>
|
|
<p className="partner-settlement-summary-label">待结算总额</p>
|
|
<div className="partner-settlement-summary-amount">
|
|
<span className="partner-settlement-currency">¥</span>
|
|
{fmtMoney(summary.pendingTotal)}
|
|
</div>
|
|
<div className="partner-settlement-summary-grid">
|
|
<div>
|
|
<p className="partner-settlement-summary-sub">累计已结算</p>
|
|
<p className="partner-settlement-summary-value">¥{fmtMoney(summary.settledTotal)}</p>
|
|
</div>
|
|
<div className="partner-settlement-summary-divider" />
|
|
<div>
|
|
<p className="partner-settlement-summary-sub">本周预付款</p>
|
|
<p className="partner-settlement-summary-value partner-settlement-summary-value--accent">
|
|
¥{fmtMoney(preview?.prepaymentAmount ?? 0)}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section className="partner-settlement-filters">
|
|
<p className="label-md text-muted" style={{ margin: 0, lineHeight: 1.5 }}>
|
|
账期 {formatBillPeriod(preview?.periodStart, preview?.periodEnd)} · {formatIssueLabel(preview)}
|
|
</p>
|
|
</section>
|
|
|
|
<div className="partner-settlement-chips">
|
|
{statusTabs.map((tab) => (
|
|
<button
|
|
key={tab.key}
|
|
type="button"
|
|
className={`partner-settlement-chip${statusFilter === tab.key ? ' partner-settlement-chip--active' : ''}`}
|
|
onClick={() => setStatusFilter(tab.key)}
|
|
>
|
|
{tab.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
<section className="partner-settlement-list-section">
|
|
<h3 className="partner-settlement-list-title">对账明细记录</h3>
|
|
|
|
{filteredBills.length === 0 && (
|
|
<div className="empty" style={{ padding: '32px 0' }}>暂无对账记录</div>
|
|
)}
|
|
|
|
<div className="partner-settlement-list">
|
|
{filteredBills.map((bill) => (
|
|
<button
|
|
key={bill.id}
|
|
type="button"
|
|
className="partner-settlement-item"
|
|
onClick={() => openBill(bill)}
|
|
>
|
|
<div className="partner-settlement-item-main">
|
|
<div className="partner-settlement-item-head">
|
|
<span className="partner-settlement-item-no">{bill.billNo}</span>
|
|
<span className={`partner-settlement-status ${billStatusClass(bill.status)}`}>
|
|
{billStatusLabel(bill.status)}
|
|
</span>
|
|
</div>
|
|
<p className="partner-settlement-item-meta">
|
|
<span className="material-symbols-outlined">event</span>
|
|
{billPeriodLabel(bill)}
|
|
<span className="partner-settlement-dot" />
|
|
订单分佣 ¥{fmtMoney(Number(bill.orderCommission || 0))}
|
|
</p>
|
|
<p className={`partner-settlement-item-amount${bill.status === 'UNPAID' ? ' text-primary' : ''}`}>
|
|
¥{fmtMoney(Number(bill.totalAmount || 0))}
|
|
</p>
|
|
</div>
|
|
<span className="material-symbols-outlined text-muted">chevron_right</span>
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
{filteredBills.length > 0 && (
|
|
<p className="partner-settlement-footer-note">已展示全部记录</p>
|
|
)}
|
|
</section>
|
|
</main>
|
|
</PullToRefresh>
|
|
);
|
|
}
|