feat(distribution): 通道费改主站承担,并按冷却期自动释放结算

利润不再扣支付通道费;站点可配置结算冷却期,到期自动入账,已释放后退款从收款站钱包回冲。同时修复当日自动批次无法追加、三方回冲打错钱包,以及测试库自增重置被 MySQL 统计缓存跳过的问题。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
yml2213
2026-09-10 17:11:58 +08:00
co-authored by Cursor
parent 47ceb53c09
commit 647fdc0b4a
24 changed files with 1399 additions and 129 deletions
+3
View File
@@ -152,6 +152,8 @@ export interface DistributionOrder {
handoff_status?: string
refund_status: string
settlement_status: string
distributor_settlement_status?: string
release_at?: string
distribution_mode: string
gross_paid_amount_cent?: number
refund_amount_cent?: number
@@ -504,6 +506,7 @@ export interface SiteWallet {
site_id: number
available_balance_cent: number
frozen_balance_cent: number
pending_release_cent: number
total_settled_cent: number
total_withdrawn_cent: number
}
+23 -7
View File
@@ -67,6 +67,25 @@ const SETTLEMENT_STATUS_MAP: Record<string, { label: string; color: string }> =
closed: { label: '已关闭', color: 'default' },
}
function settlementTag(row: DistributionOrder): { label: string; color: string } {
if (row.distributor_settlement_status === 'settled') {
return { label: '已释放入账', color: 'success' }
}
if (row.distributor_settlement_status === 'pending' && row.release_at) {
const releaseDate = new Date(row.release_at).toLocaleDateString('zh-CN', {
month: 'numeric',
day: 'numeric',
})
return { label: `待释放 ${releaseDate}`, color: 'processing' }
}
return (
SETTLEMENT_STATUS_MAP[row.settlement_status] || {
label: row.settlement_status,
color: 'default',
}
)
}
const REFUND_STATUS_MAP: Record<string, { label: string; color: string }> = {
none: { label: '未退款', color: 'default' },
pending: { label: '退款审核中', color: 'orange' },
@@ -455,12 +474,9 @@ export default function Orders({ kind }: { kind: 'all' | 'sold' | 'receive' }) {
},
{
title: '结算状态',
width: 110,
width: 130,
render: (_: unknown, row: DistributionOrder) => {
const conf = SETTLEMENT_STATUS_MAP[row.settlement_status] || {
label: row.settlement_status,
color: 'default',
}
const conf = settlementTag(row)
return <Tag color={conf.color}>{conf.label}</Tag>
},
},
@@ -873,10 +889,10 @@ export default function Orders({ kind }: { kind: 'all' | 'sold' | 'receive' }) {
<Col span={8}>
<div style={{ color: '#8c8c8c', fontSize: 12, marginBottom: 4 }}>结算状态</div>
<Tag
color={SETTLEMENT_STATUS_MAP[selectedOrder.settlement_status]?.color || 'default'}
color={settlementTag(selectedOrder).color}
style={{ fontSize: 13, padding: '2px 8px' }}
>
{SETTLEMENT_STATUS_MAP[selectedOrder.settlement_status]?.label || selectedOrder.settlement_status}
{settlementTag(selectedOrder).label}
</Tag>
</Col>
</Row>
+9 -9
View File
@@ -166,12 +166,12 @@ export default function Settlements() {
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div>
<Typography.Title level={3} style={{ marginBottom: 4 }}>
{isSuperadmin ? '结算管理与批次出账' : '周期结算单与财务对账'}
{isSuperadmin ? '结算管理与批次对账' : '结算对账单与财务对账'}
</Typography.Title>
<Typography.Text type="secondary">
{isSuperadmin
? '主站财务管理员可按周期创建结算批次并执行打款审核'
: '查看主站定期出具的结算账单,核对订单分成明细与资金入账凭证'}
? '系统按站点自动结算入账并生成批次;也可手工创建批次立即结算'
: '订单完成冷却期结束后系统自动释放入账,此处查看对账批次与入账明细'}
</Typography.Text>
</div>
{isSuperadmin && sites.length > 1 && (
@@ -191,18 +191,18 @@ export default function Settlements() {
<Alert
type="info"
showIcon
message="财务对账与结算说明"
description="分销订单在完成履约且双方验收确认后自动归集出账。结算单经主站财务审核打款后,收益将100%直接计入商户钱包可用余额,可随时在「资金与提现」中申请提现。"
message="自动结算与对账说明"
description="订单完成后进入站点结算冷却期(由主站后台按商户配置,默认 7 天,0 天为立即释放),期满系统自动生成结算批次并将收益释放到「资金与提现」的可提现余额;退款或维权中的订单会暂停释放。"
/>
{/* Superadmin batch creation controls */}
{isSuperadmin && (
<Card title="管理员批次出账操作" size="small" style={{ background: '#f8fafc' }}>
<Card title="管理员手工出账(立即结算)" size="small" style={{ background: '#f8fafc' }}>
<Space wrap>
<Typography.Text strong>选择结算结算周期:</Typography.Text>
<Typography.Text strong>选择结算周期:</Typography.Text>
<DatePicker.RangePicker showTime onChange={(value) => setRange(value)} />
<Button type="primary" icon={<PlusOutlined />} onClick={handleCreate} loading={creating}>
生成结算账单批次
生成结算批次并结算
</Button>
</Space>
</Card>
@@ -219,7 +219,7 @@ export default function Settlements() {
emptyText: (
<Empty
image={Empty.PRESENTED_IMAGE_SIMPLE}
description="暂无结算账单。当期订单履约完成后将在下一个结算周期出具对账单。"
description="暂无结算批次。订单完成冷却期结束后系统会自动出具对账单并入账。"
/>
),
}}
+16 -4
View File
@@ -24,6 +24,7 @@ import {
DollarCircleOutlined,
LockOutlined,
CheckCircleOutlined,
HourglassOutlined,
} from '@ant-design/icons'
import {
fetchSiteWallet,
@@ -193,7 +194,7 @@ export default function Wallet() {
</div>
<Row gutter={16}>
<Col span={6}>
<Col flex="1">
<Card bordered={false} style={{ background: 'linear-gradient(135deg, #1677ff 0%, #0958d9 100%)', color: '#fff' }}>
<Statistic
title={<span style={{ color: 'rgba(255,255,255,0.85)' }}>可提现余额</span>}
@@ -204,7 +205,18 @@ export default function Wallet() {
/>
</Card>
</Col>
<Col span={6}>
<Col flex="1">
<Card bordered={false} style={{ background: '#fafafa' }}>
<Statistic
title="待释放收益 (订单完成冷却中)"
value={((wallet?.pending_release_cent ?? 0) / 100).toFixed(2)}
prefix={<HourglassOutlined style={{ color: '#1677ff' }} />}
suffix="元"
valueStyle={{ color: '#1677ff' }}
/>
</Card>
</Col>
<Col flex="1">
<Card bordered={false} style={{ background: '#fafafa' }}>
<Statistic
title="冻结中余额 (提现审核中)"
@@ -215,7 +227,7 @@ export default function Wallet() {
/>
</Card>
</Col>
<Col span={6}>
<Col flex="1">
<Card bordered={false} style={{ background: '#fafafa' }}>
<Statistic
title="累计已结算收益"
@@ -226,7 +238,7 @@ export default function Wallet() {
/>
</Card>
</Col>
<Col span={6}>
<Col flex="1">
<Card bordered={false} style={{ background: '#fafafa' }}>
<Statistic
title="累计已成功提现"