fix(distribution): 修复分销结账退款分成计算逻辑与利润统计,优化分销订单表格列宽与展示体验
This commit is contained in:
@@ -72,7 +72,17 @@ const TX_OPTIONS = [
|
||||
|
||||
function formatGameName(name?: string) {
|
||||
if (!name) return '默认游戏'
|
||||
if (name === 'delta_force') return '三角洲行动'
|
||||
const lower = name.toLowerCase().trim()
|
||||
if (
|
||||
lower === 'delta_force' ||
|
||||
lower === 'deltaforce' ||
|
||||
lower === 'delta' ||
|
||||
lower.includes('delta_force') ||
|
||||
lower.includes('delta') ||
|
||||
name.includes('三角洲')
|
||||
) {
|
||||
return '三角洲'
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
@@ -882,7 +892,7 @@ export default function Accounts() {
|
||||
width={580}
|
||||
destroyOnClose
|
||||
>
|
||||
<Space direction="vertical" style={{ orientation: 'vertical', width: '100%', padding: '8px 0' }} size="middle">
|
||||
<Space direction="vertical" style={{ width: '100%', padding: '8px 0' }} size="middle">
|
||||
<Alert
|
||||
type="success"
|
||||
showIcon
|
||||
|
||||
@@ -58,9 +58,19 @@ const ORDER_STATUS_MAP: Record<string, { label: string; color: string }> = {
|
||||
const SETTLEMENT_STATUS_MAP: Record<string, { label: string; color: string }> = {
|
||||
settled: { label: '已结算入账', color: 'success' },
|
||||
pending: { label: '履约中待结算', color: 'warning' },
|
||||
unsettled: { label: '未结算', color: 'default' },
|
||||
settling: { label: '结算中', color: 'processing' },
|
||||
disputed: { label: '争议冻结', color: 'magenta' },
|
||||
failed: { label: '结算异常', color: 'error' },
|
||||
}
|
||||
|
||||
const REFUND_STATUS_MAP: Record<string, { label: string; color: string }> = {
|
||||
none: { label: '未退款', color: 'default' },
|
||||
refunding: { label: '退款中', color: 'orange' },
|
||||
refunded: { label: '已退押金/差额', color: 'blue' },
|
||||
failed: { label: '退款失败', color: 'error' },
|
||||
}
|
||||
|
||||
const REVIEW_STATUS_LABELS: Record<string, { label: string; color: string }> = {
|
||||
pending: { label: '待审核', color: 'orange' },
|
||||
approved: { label: '审核通过', color: 'success' },
|
||||
@@ -80,6 +90,22 @@ function maskPhone(phone?: string): string {
|
||||
return phone.slice(0, 3) + '****' + phone.slice(-4)
|
||||
}
|
||||
|
||||
function formatGameName(gameName?: string): string {
|
||||
if (!gameName) return ''
|
||||
const lower = gameName.toLowerCase().trim()
|
||||
if (
|
||||
lower === 'delta_force' ||
|
||||
lower === 'deltaforce' ||
|
||||
lower === 'delta' ||
|
||||
lower.includes('delta_force') ||
|
||||
lower.includes('delta') ||
|
||||
gameName.includes('三角洲')
|
||||
) {
|
||||
return '三角洲'
|
||||
}
|
||||
return gameName
|
||||
}
|
||||
|
||||
export default function Orders({ kind }: { kind: 'all' | 'sold' | 'receive' }) {
|
||||
const member = useMember()
|
||||
const [sites, setSites] = useState<Site[]>([])
|
||||
@@ -223,14 +249,70 @@ export default function Orders({ kind }: { kind: 'all' | 'sold' | 'receive' }) {
|
||||
|
||||
const orderColumns = [
|
||||
{
|
||||
title: '订单号 / 时间',
|
||||
width: 190,
|
||||
title: '订单与商品编号',
|
||||
width: 270,
|
||||
render: (_: unknown, row: DistributionOrder) => (
|
||||
<div>
|
||||
<Typography.Text copyable strong style={{ fontSize: 13 }}>
|
||||
{row.order_no}
|
||||
</Typography.Text>
|
||||
<div style={{ fontSize: 12, color: '#8c8c8c', marginTop: 2 }}>
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', whiteSpace: 'nowrap', marginBottom: 4 }}>
|
||||
<Tag
|
||||
color="default"
|
||||
style={{
|
||||
margin: 0,
|
||||
marginInlineEnd: 6,
|
||||
fontSize: 11,
|
||||
padding: '0 5px',
|
||||
lineHeight: '18px',
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
订单
|
||||
</Tag>
|
||||
<Typography.Text
|
||||
copyable={{ text: row.order_no }}
|
||||
strong
|
||||
style={{
|
||||
fontSize: 13,
|
||||
fontFamily: 'monospace',
|
||||
whiteSpace: 'nowrap',
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
{row.order_no}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
{row.listing_no ? (
|
||||
<div style={{ display: 'flex', alignItems: 'center', whiteSpace: 'nowrap', marginBottom: 4 }}>
|
||||
<Tag
|
||||
color="blue"
|
||||
style={{
|
||||
margin: 0,
|
||||
marginInlineEnd: 6,
|
||||
fontSize: 11,
|
||||
padding: '0 5px',
|
||||
lineHeight: '18px',
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
商品
|
||||
</Tag>
|
||||
<Typography.Text
|
||||
copyable={{ text: row.listing_no }}
|
||||
style={{
|
||||
fontSize: 13,
|
||||
color: '#1677ff',
|
||||
fontWeight: 600,
|
||||
fontFamily: 'monospace',
|
||||
whiteSpace: 'nowrap',
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
{row.listing_no}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
) : null}
|
||||
<div style={{ fontSize: 12, color: '#8c8c8c', whiteSpace: 'nowrap', marginTop: 2 }}>
|
||||
{row.created_at ? new Date(row.created_at).toLocaleString('zh-CN', { hour12: false }) : '-'}
|
||||
</div>
|
||||
</div>
|
||||
@@ -238,14 +320,18 @@ export default function Orders({ kind }: { kind: 'all' | 'sold' | 'receive' }) {
|
||||
},
|
||||
{
|
||||
title: '商品与游戏',
|
||||
minWidth: 220,
|
||||
width: 260,
|
||||
render: (_: unknown, row: DistributionOrder) => (
|
||||
<div>
|
||||
<Typography.Text strong style={{ display: 'block', fontSize: 14 }}>
|
||||
{row.title || (row.listing_no ? `商品 #${row.listing_no}` : `订单商品 #${row.order_id}`)}
|
||||
<Typography.Text
|
||||
strong
|
||||
style={{ fontSize: 14, lineHeight: '20px', display: 'block' }}
|
||||
ellipsis={{ tooltip: row.title }}
|
||||
>
|
||||
{row.title || `商品 #${row.listing_no || row.order_id}`}
|
||||
</Typography.Text>
|
||||
<Space size={4} style={{ marginTop: 4 }} wrap>
|
||||
{row.game_name && <Tag color="blue">{row.game_name}</Tag>}
|
||||
{row.game_name && <Tag color="blue">{formatGameName(row.game_name)}</Tag>}
|
||||
{row.server_region && <Tag>{row.server_region}</Tag>}
|
||||
{row.login_platform && <Tag color="cyan">{row.login_platform}</Tag>}
|
||||
{row.rent_duration_hours ? <Tag color="purple">租期: {row.rent_duration_hours}h</Tag> : null}
|
||||
@@ -255,28 +341,30 @@ export default function Orders({ kind }: { kind: 'all' | 'sold' | 'receive' }) {
|
||||
},
|
||||
{
|
||||
title: '租客',
|
||||
width: 140,
|
||||
width: 130,
|
||||
render: (_: unknown, row: DistributionOrder) => (
|
||||
<div>
|
||||
<div style={{ fontWeight: 500 }}>{row.renter_nickname || '平台租客'}</div>
|
||||
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
|
||||
<div style={{ fontWeight: 500, whiteSpace: 'nowrap' }}>{row.renter_nickname || '平台租客'}</div>
|
||||
<Typography.Text type="secondary" style={{ fontSize: 12, whiteSpace: 'nowrap' }}>
|
||||
{maskPhone(row.renter_phone)}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '实付租金 / 押金',
|
||||
title: '实付 / 押金',
|
||||
width: 140,
|
||||
render: (_: unknown, row: DistributionOrder) => {
|
||||
const netPaid = row.net_paid_amount_cent || row.gross_paid_amount_cent || 0
|
||||
return (
|
||||
<div>
|
||||
<Typography.Text strong style={{ color: '#1677ff', fontSize: 15 }}>
|
||||
<Typography.Text strong style={{ color: '#1677ff', fontSize: 15, whiteSpace: 'nowrap', display: 'block' }}>
|
||||
{formatMoney(netPaid)}
|
||||
</Typography.Text>
|
||||
{row.deposit_amount_cent ? (
|
||||
<div style={{ fontSize: 12, color: '#8c8c8c' }}>押金: {formatMoney(row.deposit_amount_cent)}</div>
|
||||
<div style={{ fontSize: 12, color: '#8c8c8c', whiteSpace: 'nowrap', marginTop: 2 }}>
|
||||
押金: {formatMoney(row.deposit_amount_cent)}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
@@ -284,30 +372,42 @@ export default function Orders({ kind }: { kind: 'all' | 'sold' | 'receive' }) {
|
||||
},
|
||||
{
|
||||
title: '本站净收益',
|
||||
width: 180,
|
||||
width: 150,
|
||||
render: (_: unknown, row: DistributionOrder) => {
|
||||
const earning = row.distributor_earning_cent ?? 0
|
||||
const isSell = row.distributor_role?.includes('sell')
|
||||
const isRecv = row.distributor_role?.includes('receive')
|
||||
const roleLabel =
|
||||
row.distributor_role === 'seller'
|
||||
? '售出方'
|
||||
: row.distributor_role === 'receiver'
|
||||
? '收号方'
|
||||
: row.distributor_role === 'two_party_distributor'
|
||||
? '分销方'
|
||||
isSell && isRecv
|
||||
? '自收自售'
|
||||
: isSell
|
||||
? '渠道代销'
|
||||
: isRecv
|
||||
? '号源出租'
|
||||
: '本站收益'
|
||||
const tagColor =
|
||||
isSell && isRecv
|
||||
? 'purple'
|
||||
: isSell
|
||||
? 'green'
|
||||
: isRecv
|
||||
? 'blue'
|
||||
: earning > 0
|
||||
? 'green'
|
||||
: 'default'
|
||||
return (
|
||||
<div>
|
||||
<Typography.Text strong style={{ color: '#389e0d', fontSize: 16 }}>
|
||||
<Typography.Text strong style={{ color: '#389e0d', fontSize: 16, whiteSpace: 'nowrap', display: 'block' }}>
|
||||
+{formatMoney(earning)}
|
||||
</Typography.Text>
|
||||
<div style={{ marginTop: 2 }}>
|
||||
<Tag color={earning > 0 ? 'green' : 'default'} style={{ fontSize: 11 }}>
|
||||
<Tag color={tagColor} style={{ fontSize: 11, margin: 0 }}>
|
||||
{roleLabel}
|
||||
</Tag>
|
||||
</div>
|
||||
{row.distributor_markup_cent && row.distributor_markup_cent > 0 ? (
|
||||
<div style={{ fontSize: 11, color: '#52c41a' }}>
|
||||
含自主溢价: +{formatMoney(row.distributor_markup_cent)}
|
||||
<div style={{ fontSize: 11, color: '#52c41a', whiteSpace: 'nowrap', marginTop: 2 }}>
|
||||
含加价: +{formatMoney(row.distributor_markup_cent)}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
@@ -315,22 +415,11 @@ export default function Orders({ kind }: { kind: 'all' | 'sold' | 'receive' }) {
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '订单履约状态',
|
||||
width: 120,
|
||||
title: '履约状态',
|
||||
width: 110,
|
||||
render: (_: unknown, row: DistributionOrder) => {
|
||||
const conf = ORDER_STATUS_MAP[row.status] || { label: row.status, color: 'default' }
|
||||
return (
|
||||
<div>
|
||||
<Tag color={conf.color}>{conf.label}</Tag>
|
||||
{row.refund_status && row.refund_status !== 'none' && (
|
||||
<div style={{ marginTop: 2 }}>
|
||||
<Tag color="magenta" style={{ fontSize: 11 }}>
|
||||
退款: {row.refund_status}
|
||||
</Tag>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
return <Tag color={conf.color}>{conf.label}</Tag>
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -346,12 +435,14 @@ export default function Orders({ kind }: { kind: 'all' | 'sold' | 'receive' }) {
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
width: 110,
|
||||
width: 90,
|
||||
fixed: 'right' as const,
|
||||
render: (_: unknown, row: DistributionOrder) => (
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
icon={<FileTextOutlined />}
|
||||
style={{ padding: 0 }}
|
||||
onClick={() => {
|
||||
setSelectedOrder(row)
|
||||
setDrawerVisible(true)
|
||||
@@ -474,7 +565,7 @@ export default function Orders({ kind }: { kind: 'all' | 'sold' | 'receive' }) {
|
||||
{row.title || '无标题'}
|
||||
</Typography.Text>
|
||||
<Space size={4} style={{ marginTop: 4 }}>
|
||||
<Tag color="blue">{row.game_name}</Tag>
|
||||
<Tag color="blue">{formatGameName(row.game_name)}</Tag>
|
||||
{row.server_region && <Tag>{row.server_region}</Tag>}
|
||||
{row.login_platform && <Tag>{row.login_platform}</Tag>}
|
||||
{row.rank_level && <Tag color="purple">{row.rank_level}</Tag>}
|
||||
@@ -604,6 +695,7 @@ export default function Orders({ kind }: { kind: 'all' | 'sold' | 'receive' }) {
|
||||
loading={orderLoading}
|
||||
dataSource={orders}
|
||||
columns={orderColumns}
|
||||
scroll={{ x: 1200 }}
|
||||
pagination={{
|
||||
current: orderPage,
|
||||
pageSize,
|
||||
@@ -657,6 +749,7 @@ export default function Orders({ kind }: { kind: 'all' | 'sold' | 'receive' }) {
|
||||
loading={orderLoading}
|
||||
dataSource={orders}
|
||||
columns={orderColumns}
|
||||
scroll={{ x: 1200 }}
|
||||
pagination={{
|
||||
current: orderPage,
|
||||
pageSize,
|
||||
@@ -741,6 +834,22 @@ export default function Orders({ kind }: { kind: 'all' | 'sold' | 'receive' }) {
|
||||
size="small"
|
||||
column={2}
|
||||
items={[
|
||||
{
|
||||
key: 'order_no',
|
||||
label: '订单编号',
|
||||
children: <Typography.Text copyable>{selectedOrder.order_no}</Typography.Text>,
|
||||
},
|
||||
{
|
||||
key: 'listing_no',
|
||||
label: '商品编号',
|
||||
children: selectedOrder.listing_no ? (
|
||||
<Typography.Text copyable={{ text: selectedOrder.listing_no }} strong style={{ color: '#1677ff' }}>
|
||||
{selectedOrder.listing_no}
|
||||
</Typography.Text>
|
||||
) : (
|
||||
'-'
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'title',
|
||||
label: '商品名称',
|
||||
@@ -750,7 +859,7 @@ export default function Orders({ kind }: { kind: 'all' | 'sold' | 'receive' }) {
|
||||
{
|
||||
key: 'game',
|
||||
label: '游戏 / 区服',
|
||||
children: `${selectedOrder.game_name || '-'} / ${selectedOrder.server_region || '-'}`,
|
||||
children: `${formatGameName(selectedOrder.game_name) || '-'} / ${selectedOrder.server_region || '-'}`,
|
||||
},
|
||||
{
|
||||
key: 'platform',
|
||||
@@ -781,6 +890,20 @@ export default function Orders({ kind }: { kind: 'all' | 'sold' | 'receive' }) {
|
||||
</Tag>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'refund_status',
|
||||
label: '资金原路退还',
|
||||
children:
|
||||
selectedOrder.refund_status && selectedOrder.refund_status !== 'none' ? (
|
||||
<Tag color={REFUND_STATUS_MAP[selectedOrder.refund_status]?.color || 'default'}>
|
||||
{selectedOrder.status === 'completed' && selectedOrder.refund_status === 'refunded'
|
||||
? '已退还押金/租金差额'
|
||||
: REFUND_STATUS_MAP[selectedOrder.refund_status]?.label || selectedOrder.refund_status}
|
||||
</Tag>
|
||||
) : (
|
||||
'无退款'
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'created_at',
|
||||
label: '下单时间',
|
||||
@@ -837,10 +960,12 @@ export default function Orders({ kind }: { kind: 'all' | 'sold' | 'receive' }) {
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<Tag color="blue">
|
||||
本分销站角色:
|
||||
{selectedOrder.distributor_role === 'seller'
|
||||
? '售出方 (享 40% 提成分润 + 100% 自主加价溢价)'
|
||||
: selectedOrder.distributor_role === 'receiver'
|
||||
? '收号方 (享 35% 提成分润)'
|
||||
{selectedOrder.distributor_role?.includes('sell') && selectedOrder.distributor_role?.includes('receive')
|
||||
? '自收自售 (独享全部分润与自主溢价)'
|
||||
: selectedOrder.distributor_role?.includes('sell')
|
||||
? '售出方 / 渠道代销 (享 40% 提成分润 + 100% 自主加价溢价)'
|
||||
: selectedOrder.distributor_role?.includes('receive')
|
||||
? '供号方 / 收号出租 (享 35% 提成分润)'
|
||||
: '分销合作方'}
|
||||
</Tag>
|
||||
</div>
|
||||
|
||||
@@ -348,7 +348,7 @@ export default function SiteSettings() {
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={18}>
|
||||
<Space orientation="vertical" style={{ width: '100%' }} size="small">
|
||||
<Space direction="vertical" style={{ width: '100%' }} size="small">
|
||||
<Input
|
||||
placeholder="输入图片 URL (https://...)"
|
||||
value={item.image_url}
|
||||
|
||||
Reference in New Issue
Block a user