fix(distribution-admin): 全面优化大盘、对账单、钱包与前台商城的列宽排版、中文化与防换行体验

This commit is contained in:
yml2213
2026-09-09 19:47:11 +08:00
parent 4098f8f50f
commit 1c16f26ae0
5 changed files with 183 additions and 26 deletions
+129 -14
View File
@@ -34,6 +34,46 @@ import {
} from '../api'
import { useMember } from '../MemberContext'
const ORDER_STATUS_MAP: Record<string, { label: string; color: string }> = {
pending_payment: { label: '待支付', color: 'orange' },
pending_handoff: { label: '待上号交付', color: 'processing' },
renting: { label: '在租中', color: 'cyan' },
overdue: { label: '已逾期', color: 'volcano' },
pending_checkout_confirm: { label: '待结单确认', color: 'blue' },
pending_checkout_accept: { label: '待号主验收', color: 'blue' },
checkout_disputing: { label: '结单争议中', color: 'magenta' },
disputing: { label: '维权中', color: 'magenta' },
abnormal: { label: '异常', color: 'error' },
completed: { label: '已完成', color: 'success' },
refunded: { label: '已退款', color: 'purple' },
cancelled: { label: '已取消', color: 'default' },
}
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' },
}
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 Dashboard() {
const member = useMember()
const [sites, setSites] = useState<Site[]>([])
@@ -266,23 +306,92 @@ export default function Dashboard() {
rowKey="order_id"
dataSource={recentOrders}
pagination={false}
scroll={{ x: 1050 }}
columns={[
{
title: '订单号',
dataIndex: 'order_no',
width: 170,
render: (v: string) => <Typography.Text copyable strong>{v}</Typography.Text>,
title: '订单与商品编号',
width: 260,
render: (_: unknown, row: DistributionOrder) => (
<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 4px',
lineHeight: '18px',
flexShrink: 0,
}}
>
订单
</Tag>
<Typography.Text
copyable={{ text: row.order_no, tooltips: ['复制订单号', '已复制'] }}
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' }}>
<Tag
color="blue"
style={{
margin: 0,
marginInlineEnd: 6,
fontSize: 11,
padding: '0 4px',
lineHeight: '18px',
flexShrink: 0,
}}
>
商品
</Tag>
<Typography.Text
copyable={{ text: row.listing_no, tooltips: ['复制商品编号', '已复制'] }}
style={{
fontSize: 13,
color: '#1677ff',
fontWeight: 600,
fontFamily: 'monospace',
whiteSpace: 'nowrap',
display: 'inline-flex',
alignItems: 'center',
}}
>
{row.listing_no}
</Typography.Text>
</div>
) : null}
</div>
),
},
{
title: '租赁账号与游戏',
minWidth: 180,
width: 240,
render: (_: unknown, row: DistributionOrder) => (
<div>
<Typography.Text strong style={{ display: 'block' }}>
<Typography.Text
strong
style={{ display: 'block', fontSize: 14, lineHeight: '20px' }}
ellipsis={{ tooltip: row.title }}
>
{row.title || (row.listing_no ? `商品 #${row.listing_no}` : `订单 #${row.order_id}`)}
</Typography.Text>
{row.game_name && <Tag color="blue" style={{ marginTop: 2 }}>{row.game_name}</Tag>}
{row.server_region && <Tag>{row.server_region}</Tag>}
<Space size={4} style={{ marginTop: 4 }} wrap>
{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>}
</Space>
</div>
),
},
@@ -290,16 +399,16 @@ export default function Dashboard() {
title: '实付金额',
width: 120,
render: (_: unknown, row: DistributionOrder) => (
<Typography.Text strong style={{ color: '#1677ff' }}>
<Typography.Text strong style={{ color: '#1677ff', fontSize: 15, whiteSpace: 'nowrap' }}>
{formatMoney(row.net_paid_amount_cent || row.gross_paid_amount_cent || 0)}
</Typography.Text>
),
},
{
title: '本站净收益',
width: 140,
width: 130,
render: (_: unknown, row: DistributionOrder) => (
<Typography.Text strong style={{ color: '#389e0d', fontSize: 15 }}>
<Typography.Text strong style={{ color: '#389e0d', fontSize: 15, whiteSpace: 'nowrap' }}>
+{formatMoney(row.distributor_earning_cent || 0)}
</Typography.Text>
),
@@ -308,20 +417,26 @@ export default function Dashboard() {
title: '订单状态',
dataIndex: 'status',
width: 110,
render: (v: string) => <Tag color={v === 'completed' || v === 'renting' ? 'green' : 'default'}>{v}</Tag>,
render: (v: string) => {
const conf = ORDER_STATUS_MAP[v] || { label: v, color: 'default' }
return <Tag color={conf.color}>{conf.label}</Tag>
},
},
{
title: '结算状态',
dataIndex: 'settlement_status',
width: 110,
render: (v: string) => <Tag color={v === 'settled' ? 'success' : 'warning'}>{v === 'settled' ? '已结算' : '待结算'}</Tag>,
render: (v: string) => {
const conf = SETTLEMENT_STATUS_MAP[v] || { label: v, color: 'default' }
return <Tag color={conf.color}>{conf.label}</Tag>
},
},
{
title: '下单时间',
dataIndex: 'created_at',
width: 160,
render: (v: string) => (
<span style={{ fontSize: 12, color: '#8c8c8c' }}>
<span style={{ fontSize: 12, color: '#8c8c8c', whiteSpace: 'nowrap' }}>
{v ? new Date(v).toLocaleString('zh-CN', { hour12: false }) : '-'}
</span>
),
+1 -1
View File
@@ -110,7 +110,7 @@ export default function Payments() {
columns={[
{ title: '商户配置 ID', dataIndex: 'config_id' },
{ title: '优先级', dataIndex: 'priority' },
{ title: '状态', dataIndex: 'status', render: (v: string) => <Tag color={v === 'active' ? 'green' : 'default'}>{v}</Tag> },
{ title: '状态', dataIndex: 'status', render: (v: string) => <Tag color={v === 'active' ? 'green' : 'default'}>{v === 'active' ? '正常生效' : (v || '已停用')}</Tag> },
{
title: '操作',
render: (_: unknown, row: PaymentChannel) => <a onClick={() => handleUnbind(row.id)}>解绑</a>,
+7 -4
View File
@@ -47,10 +47,12 @@ const STATUS_LABELS: Record<string, { label: string; color: string }> = {
}
const PARTY_ROLE_LABELS: Record<string, string> = {
seller: '卖出提成分账 (40%)',
distributor_b: '卖出提成分账 (40%)',
receiver: '收号提成分账 (35%)',
distributor_a: '收号提成分账 (35%)',
seller: '渠道代销分润 (40%)',
distributor_sell: '渠道代销分润 (40%)',
distributor_b: '渠道代销分润 (40%)',
receiver: '号源出租分润 (35%)',
distributor_receive: '号源出租分润 (35%)',
distributor_a: '号源出租分润 (35%)',
two_party_distributor: '分销商分润',
platform: '平台服务费',
}
@@ -212,6 +214,7 @@ export default function Settlements() {
loading={loading}
dataSource={batches}
pagination={false}
scroll={{ x: 1000 }}
locale={{
emptyText: (
<Empty
+19 -3
View File
@@ -35,6 +35,22 @@ import {
type PublicDistributionListing,
} from '../api'
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 Storefront() {
const { siteCode = 'demo' } = useParams<{ siteCode: string }>()
const [loading, setLoading] = useState(true)
@@ -247,7 +263,7 @@ export default function Storefront() {
buttonStyle="solid"
>
<Radio.Button value="all">全部游戏</Radio.Button>
<Radio.Button value="delta_force">三角洲行动</Radio.Button>
<Radio.Button value="delta_force">三角洲</Radio.Button>
<Radio.Button value="honor_of_kings">王者荣耀</Radio.Button>
</Radio.Group>
@@ -345,7 +361,7 @@ export default function Storefront() {
{/* 标签属性 */}
<Space wrap size={4} style={{ marginBottom: 12 }}>
<Tag color="blue" style={{ margin: 0 }}>
{item.game_name === 'delta_force' ? '三角洲行动' : item.game_name}
{formatGameName(item.game_name)}
</Tag>
{item.server_region && (
<Tag style={{ margin: 0, background: 'rgba(255,255,255,0.06)', color: '#cbd5e1', border: 'none' }}>
@@ -446,7 +462,7 @@ export default function Storefront() {
<Descriptions column={2} bordered size="small">
<Descriptions.Item label="所属游戏">
{selectedListing.game_name === 'delta_force' ? '三角洲行动' : selectedListing.game_name}
{formatGameName(selectedListing.game_name)}
</Descriptions.Item>
<Descriptions.Item label="游戏大区">{selectedListing.server_region || '全区通用'}</Descriptions.Item>
<Descriptions.Item label="登录平台">{selectedListing.login_platform || 'PC端'}</Descriptions.Item>
+27 -4
View File
@@ -251,12 +251,29 @@ export default function Wallet() {
showTotal: (tot) => `共 ${tot} 条提现记录`,
onChange: (p) => void loadData(p),
}}
scroll={{ x: 1100 }}
columns={[
{
title: '提现单号',
dataIndex: 'withdraw_no',
width: 170,
render: (v: string) => <Typography.Text copyable strong>{v}</Typography.Text>,
width: 200,
render: (v: string) => (
<div style={{ whiteSpace: 'nowrap' }}>
<Typography.Text
copyable={{ text: v, tooltips: ['复制单号', '已复制'] }}
strong
style={{
fontFamily: 'monospace',
fontSize: 13,
whiteSpace: 'nowrap',
display: 'inline-flex',
alignItems: 'center',
}}
>
{v}
</Typography.Text>
</div>
),
},
{
title: '提现金额',
@@ -325,14 +342,20 @@ export default function Wallet() {
title: '申请时间',
dataIndex: 'created_at',
width: 160,
render: (v: string) => <span style={{ fontSize: 12, color: '#666' }}>{v}</span>,
render: (v: string) => (
<span style={{ fontSize: 12, color: '#666', whiteSpace: 'nowrap' }}>
{v ? new Date(v).toLocaleString('zh-CN', { hour12: false }) : '-'}
</span>
),
},
{
title: '打款时间',
dataIndex: 'paid_at',
width: 160,
render: (v: string | undefined) => (
<span style={{ fontSize: 12, color: v ? '#52c41a' : '#999' }}>{v || '待打款'}</span>
<span style={{ fontSize: 12, color: v ? '#52c41a' : '#999', whiteSpace: 'nowrap' }}>
{v ? new Date(v).toLocaleString('zh-CN', { hour12: false }) : '待打款'}
</span>
),
},
]}