style(frontend): 全项目表格统一百分比布局并居中

This commit is contained in:
yml2213
2026-10-24 14:49:23 +08:00
parent a96229a106
commit ce8efa6bad
52 changed files with 346 additions and 145 deletions
@@ -0,0 +1,32 @@
import { Table as AntTable } from 'antd'
import type { TableProps } from 'antd'
import { normalizePercentColumns } from '@/utils/percent-table-layout'
/**
* 全项目统一表格:列宽转百分比、表头与内容居中。
*
* 业务表格仍按原列宽数值表达相对比例,由这里统一归一化为 100%。
* rowSelection / expandable 会额外占用 AntD 内置列,因此预留少量百分比。
*/
export default function PercentTable<RecordType extends object = Record<string, unknown>>(
props: TableProps<RecordType>,
) {
const { columns, scroll, tableLayout: _tableLayout, ...rest } = props
const reservedPercent =
(props.rowSelection ? 4 : 0) +
(props.expandable && typeof props.expandable === 'object' ? 4 : 0)
const normalizedColumns = columns
? normalizePercentColumns(columns, { reservedPercent })
: columns
const scrollConfig = typeof scroll === 'object' && scroll ? scroll : {}
return (
<AntTable<RecordType>
{...rest}
columns={normalizedColumns}
tableLayout="fixed"
scroll={{ ...scrollConfig, x: '100%' }}
/>
)
}
@@ -1,5 +1,6 @@
import { ReloadOutlined, SearchOutlined } from '@ant-design/icons' import { ReloadOutlined, SearchOutlined } from '@ant-design/icons'
import { Alert, Button, Card, Empty, Form, Input, Select, Space, Table, Typography } from 'antd' import { Alert, Button, Card, Empty, Form, Input, Select, Space, Typography } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useQuery } from '@tanstack/react-query' import { useQuery } from '@tanstack/react-query'
import { useMemo } from 'react' import { useMemo } from 'react'
@@ -203,7 +204,7 @@ export default function AdminAuditLogsPage() {
) : null} ) : null}
<Card> <Card>
<Table<AdminAuditLogItem> <PercentTable<AdminAuditLogItem>
rowKey="logId" rowKey="logId"
loading={query.isLoading || query.isFetching} loading={query.isLoading || query.isFetching}
columns={columns} columns={columns}
@@ -10,10 +10,10 @@ import {
Skeleton, Skeleton,
Space, Space,
Statistic, Statistic,
Table,
Tag, Tag,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useQuery } from '@tanstack/react-query' import { useQuery } from '@tanstack/react-query'
import { useMemo, useState } from 'react' import { useMemo, useState } from 'react'
@@ -226,7 +226,7 @@ export default function AdminDashboardPage() {
/> />
) : null} ) : null}
<Table<AdminLoginLogItem> <PercentTable<AdminLoginLogItem>
rowKey="logId" rowKey="logId"
loading={loginQuery.isLoading || loginQuery.isFetching} loading={loginQuery.isLoading || loginQuery.isFetching}
columns={columns} columns={columns}
@@ -16,10 +16,10 @@ import {
Popconfirm, Popconfirm,
Select, Select,
Space, Space,
Table,
Tag, Tag,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useEffect, useMemo, useRef, useState } from 'react' import { useEffect, useMemo, useRef, useState } from 'react'
@@ -377,7 +377,7 @@ export default function AdminDouyinMashidaCertificatePage() {
<div className="kuaishou-industry-split"> <div className="kuaishou-industry-split">
<Card title="本地券码" className="kuaishou-industry-voucher-card"> <Card title="本地券码" className="kuaishou-industry-voucher-card">
<Table <PercentTable
rowKey="id" rowKey="id"
size="middle" size="middle"
tableLayout="fixed" tableLayout="fixed"
@@ -10,10 +10,10 @@ import {
Select, Select,
Space, Space,
Statistic, Statistic,
Table,
Tag, Tag,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useState } from 'react' import { useState } from 'react'
@@ -224,7 +224,7 @@ export default function AdminFinancePage() {
</Button> </Button>
} }
> >
<Table<AdminFinanceDailyItem> <PercentTable<AdminFinanceDailyItem>
rowKey="date" rowKey="date"
loading={summaryQuery.isLoading} loading={summaryQuery.isLoading}
dataSource={daily} dataSource={daily}
@@ -252,7 +252,7 @@ export default function AdminFinancePage() {
</Space> </Space>
} }
> >
<Table<AdminFinanceChannelDailyItem> <PercentTable<AdminFinanceChannelDailyItem>
rowKey={(row) => `${row.date}-${row.channel}-${row.category}`} rowKey={(row) => `${row.date}-${row.channel}-${row.category}`}
loading={summaryQuery.isLoading} loading={summaryQuery.isLoading}
dataSource={channelDaily} dataSource={channelDaily}
@@ -304,7 +304,7 @@ export default function AdminFinancePage() {
</Space> </Space>
} }
> >
<Table<AdminFinanceTransaction> <PercentTable<AdminFinanceTransaction>
rowKey={(row) => `${row.category}-${row.sourceId}-${row.occurredAt}`} rowKey={(row) => `${row.category}-${row.sourceId}-${row.occurredAt}`}
loading={transactionsQuery.isLoading} loading={transactionsQuery.isLoading}
dataSource={transactionData?.items || []} dataSource={transactionData?.items || []}
@@ -18,11 +18,11 @@ import {
Popconfirm, Popconfirm,
Select, Select,
Space, Space,
Table,
Tabs, Tabs,
Tag, Tag,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType, TabsProps } from 'antd' import type { TableColumnsType, TabsProps } from 'antd'
import { useEffect, useMemo, useRef, useState } from 'react' import { useEffect, useMemo, useRef, useState } from 'react'
@@ -963,7 +963,7 @@ export default function AdminKuaishouIndustryPage() {
function renderVoucherTable(scrollX?: number) { function renderVoucherTable(scrollX?: number) {
return ( return (
<Table <PercentTable
rowKey="id" rowKey="id"
size="middle" size="middle"
tableLayout="fixed" tableLayout="fixed"
@@ -1297,7 +1297,7 @@ export default function AdminKuaishouIndustryPage() {
查询售后 查询售后
</Button> </Button>
</Space> </Space>
<Table <PercentTable
rowKey={(row) => String(row.refundId || row.oid || JSON.stringify(row))} rowKey={(row) => String(row.refundId || row.oid || JSON.stringify(row))}
columns={refundColumns} columns={refundColumns}
dataSource={refundRows} dataSource={refundRows}
@@ -20,10 +20,10 @@ import {
Modal, Modal,
Space, Space,
Statistic, Statistic,
Table,
Tag, Tag,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useState } from 'react' import { useState } from 'react'
@@ -245,7 +245,7 @@ export default function AdminManualFulfillmentPage() {
</Space> </Space>
<Card bordered={false}> <Card bordered={false}>
<Table <PercentTable
rowKey="orderItemId" rowKey="orderItemId"
size="small" size="small"
columns={columns} columns={columns}
@@ -16,10 +16,10 @@ import {
Modal, Modal,
Skeleton, Skeleton,
Space, Space,
Table,
Tag, Tag,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
@@ -318,7 +318,7 @@ export default function AdminOrderDetailPage() {
</Card> </Card>
<Card title="商品明细"> <Card title="商品明细">
<Table<AdminOrderDetail['items'][number]> <PercentTable<AdminOrderDetail['items'][number]>
rowKey="orderItemId" rowKey="orderItemId"
pagination={false} pagination={false}
dataSource={detail.items} dataSource={detail.items}
@@ -354,7 +354,7 @@ export default function AdminOrderDetailPage() {
</Card> </Card>
<Card title="任务"> <Card title="任务">
<Table<AdminTaskListItem> <PercentTable<AdminTaskListItem>
rowKey="taskId" rowKey="taskId"
pagination={false} pagination={false}
dataSource={detail.tasks} dataSource={detail.tasks}
@@ -16,11 +16,11 @@ import {
Segmented, Segmented,
Select, Select,
Space, Space,
Table,
Tag, Tag,
Tooltip, Tooltip,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useQuery } from '@tanstack/react-query' import { useQuery } from '@tanstack/react-query'
import { useEffect, useMemo } from 'react' import { useEffect, useMemo } from 'react'
@@ -503,7 +503,7 @@ export default function AdminOrdersPage() {
</Card> </Card>
<Card> <Card>
<Table<AdminOrderListItem> <PercentTable<AdminOrderListItem>
rowKey="orderId" rowKey="orderId"
loading={query.isLoading || query.isFetching} loading={query.isLoading || query.isFetching}
columns={columns} columns={columns}
@@ -11,11 +11,11 @@ import {
Select, Select,
Space, Space,
Statistic, Statistic,
Table,
Tabs, Tabs,
Tag, Tag,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useState } from 'react' import { useState } from 'react'
@@ -386,7 +386,7 @@ export default function AdminSalesProfitPage() {
key: 'daily', key: 'daily',
label: '日报', label: '日报',
children: ( children: (
<Table <PercentTable
rowKey="statDate" rowKey="statDate"
size="small" size="small"
columns={dailyColumns} columns={dailyColumns}
@@ -401,7 +401,7 @@ export default function AdminSalesProfitPage() {
key: 'product', key: 'product',
label: '商品', label: '商品',
children: ( children: (
<Table <PercentTable
rowKey={(row) => `${row.canonicalProductId || 'unmapped'}`} rowKey={(row) => `${row.canonicalProductId || 'unmapped'}`}
size="small" size="small"
columns={productColumns} columns={productColumns}
@@ -416,7 +416,7 @@ export default function AdminSalesProfitPage() {
key: 'fulfillment-mode', key: 'fulfillment-mode',
label: '履约方式', label: '履约方式',
children: ( children: (
<Table <PercentTable
rowKey="fulfillmentMode" rowKey="fulfillmentMode"
size="small" size="small"
columns={fulfillmentModeColumns} columns={fulfillmentModeColumns}
@@ -431,7 +431,7 @@ export default function AdminSalesProfitPage() {
key: 'facts', key: 'facts',
label: '事实明细', label: '事实明细',
children: ( children: (
<Table <PercentTable
rowKey="id" rowKey="id"
size="small" size="small"
columns={factColumns} columns={factColumns}
@@ -28,12 +28,12 @@ import {
Skeleton, Skeleton,
Space, Space,
Spin, Spin,
Table,
Tabs, Tabs,
Tag, Tag,
Tooltip, Tooltip,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useMutation, useQuery } from '@tanstack/react-query' import { useMutation, useQuery } from '@tanstack/react-query'
import { useEffect, useMemo, useState } from 'react' import { useEffect, useMemo, useState } from 'react'
@@ -898,7 +898,7 @@ export default function AdminTaskDetailPage() {
key: 'events', key: 'events',
label: `事件流水 (${resolvedDetail.events.length})`, label: `事件流水 (${resolvedDetail.events.length})`,
children: ( children: (
<Table<TaskEvent> <PercentTable<TaskEvent>
rowKey="eventId" rowKey="eventId"
pagination={false} pagination={false}
columns={eventColumns} columns={eventColumns}
@@ -1757,7 +1757,7 @@ function KuaishouIndustryVoucherPanel({ voucher }: { voucher: KuaishouIndustryVo
) : null} ) : null}
{consumeDetails.length > 0 ? ( {consumeDetails.length > 0 ? (
<Table<Record<string, unknown>> <PercentTable<Record<string, unknown>>
className="platform-section-gap" className="platform-section-gap"
rowKey={(_, index) => String(index ?? 0)} rowKey={(_, index) => String(index ?? 0)}
pagination={false} pagination={false}
@@ -1905,7 +1905,7 @@ function KuaishouCloudPanel({
{flow.rebind.history.length > 0 ? ( {flow.rebind.history.length > 0 ? (
<Card title="换绑记录"> <Card title="换绑记录">
<Table <PercentTable
rowKey={(row) => `${row.attempt}-${row.requestedAt || ''}`} rowKey={(row) => `${row.attempt}-${row.requestedAt || ''}`}
pagination={false} pagination={false}
dataSource={flow.rebind.history} dataSource={flow.rebind.history}
@@ -1969,7 +1969,7 @@ function RedeemResolutionPanel({
</Descriptions.Item> </Descriptions.Item>
</Descriptions> </Descriptions>
<Table <PercentTable
className="platform-section-gap" className="platform-section-gap"
rowKey={(row) => `${row.attempt}-${row.codeMasked}`} rowKey={(row) => `${row.attempt}-${row.codeMasked}`}
pagination={false} pagination={false}
@@ -19,11 +19,11 @@ import {
Select, Select,
Space, Space,
Spin, Spin,
Table,
Tag, Tag,
Tooltip, Tooltip,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useQuery } from '@tanstack/react-query' import { useQuery } from '@tanstack/react-query'
import { useEffect, useMemo, useState } from 'react' import { useEffect, useMemo, useState } from 'react'
@@ -576,7 +576,7 @@ export default function AdminTasksPage() {
) : null} ) : null}
<Card> <Card>
<Table<AdminTaskListItem> <PercentTable<AdminTaskListItem>
rowKey="taskId" rowKey="taskId"
loading={query.isLoading || query.isFetching} loading={query.isLoading || query.isFetching}
columns={columns} columns={columns}
@@ -12,10 +12,10 @@ import {
Select, Select,
Space, Space,
Switch, Switch,
Table,
Tag, Tag,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { MenuProps, TableColumnsType } from 'antd' import type { MenuProps, TableColumnsType } from 'antd'
import { useQuery, useQueryClient } from '@tanstack/react-query' import { useQuery, useQueryClient } from '@tanstack/react-query'
import { useMemo, useState } from 'react' import { useMemo, useState } from 'react'
@@ -675,7 +675,7 @@ export default function AdminUsersPage() {
</Typography.Text> </Typography.Text>
} }
> >
<Table<AdminUserListItem> <PercentTable<AdminUserListItem>
rowKey="userId" rowKey="userId"
loading={query.isLoading || query.isFetching} loading={query.isLoading || query.isFetching}
columns={columns} columns={columns}
@@ -5,7 +5,8 @@
* 不写渠道映射,也不维护游戏分类。 * 不写渠道映射,也不维护游戏分类。
*/ */
import { ReloadOutlined, SyncOutlined } from '@ant-design/icons' import { ReloadOutlined, SyncOutlined } from '@ant-design/icons'
import { Alert, App, Button, Card, Space, Switch, Table, Tag, Typography } from 'antd' import { Alert, App, Button, Card, Space, Switch, Tag, Typography } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import { useQuery, useQueryClient } from '@tanstack/react-query' import { useQuery, useQueryClient } from '@tanstack/react-query'
import { useState } from 'react' import { useState } from 'react'
@@ -134,7 +135,7 @@ export function AffiliateSkuPanel() {
style={{ marginBottom: 12 }} style={{ marginBottom: 12 }}
message="自动发货只按上游货源 SKU 配采购成本:订单项直接按 aff:<skuCode> 归一,不走渠道映射;这里不维护游戏分类和商品上下架,那些只属于接单平台。" message="自动发货只按上游货源 SKU 配采购成本:订单项直接按 aff:<skuCode> 归一,不走渠道映射;这里不维护游戏分类和商品上下架,那些只属于接单平台。"
/> />
<Table <PercentTable
tableLayout="fixed" tableLayout="fixed"
rowKey="id" rowKey="id"
size="small" size="small"
@@ -15,10 +15,10 @@ import {
Select, Select,
Space, Space,
Switch, Switch,
Table,
Tag, Tag,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useQuery } from '@tanstack/react-query' import { useQuery } from '@tanstack/react-query'
import { useState } from 'react' import { useState } from 'react'
@@ -427,7 +427,7 @@ export function ChannelMappingPanel() {
</Button> </Button>
<Button onClick={() => setExpandedMappingProductIds([])}>收起全部</Button> <Button onClick={() => setExpandedMappingProductIds([])}>收起全部</Button>
</Space> </Space>
<Table<ChannelProductMappingGroup> <PercentTable<ChannelProductMappingGroup>
tableLayout="fixed" tableLayout="fixed"
rowKey={(row) => String(row.canonicalProductId)} rowKey={(row) => String(row.canonicalProductId)}
size="small" size="small"
@@ -445,7 +445,7 @@ export function ChannelMappingPanel() {
<Typography.Text type="secondary"> <Typography.Text type="secondary">
该标准商品下共有 {group.mappings.length} 条渠道映射 该标准商品下共有 {group.mappings.length} 条渠道映射
</Typography.Text> </Typography.Text>
<Table<ChannelProductMapping> <PercentTable<ChannelProductMapping>
tableLayout="fixed" tableLayout="fixed"
rowKey="id" rowKey="id"
size="small" size="small"
@@ -4,7 +4,8 @@
* 异常表不再存履约载体,履约方式从 order_items.fulfillment_mode join 得到; * 异常表不再存履约载体,履约方式从 order_items.fulfillment_mode join 得到;
* 前端按履约方式筛选时传 fulfillmentMode 参数。 * 前端按履约方式筛选时传 fulfillmentMode 参数。
*/ */
import { App, Button, Card, Select, Space, Table, Tag, Typography } from 'antd' import { App, Button, Card, Select, Space, Tag, Typography } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useQuery } from '@tanstack/react-query' import { useQuery } from '@tanstack/react-query'
import { useState } from 'react' import { useState } from 'react'
@@ -160,7 +161,7 @@ export function CostExceptionPanel() {
/> />
} }
> >
<Table <PercentTable
tableLayout="fixed" tableLayout="fixed"
rowKey="id" rowKey="id"
size="small" size="small"
@@ -6,20 +6,8 @@
* 通用成本模型(平台费 / 支付费 / 售后损失 / 其他)对所有履约方式生效。 * 通用成本模型(平台费 / 支付费 / 售后损失 / 其他)对所有履约方式生效。
*/ */
import { PlusOutlined, SearchOutlined } from '@ant-design/icons' import { PlusOutlined, SearchOutlined } from '@ant-design/icons'
import { import { Alert, App, Button, Card, Form, Input, Modal, Select, Space, Tag, Typography } from 'antd'
Alert, import PercentTable from '@/components/common/PercentTable'
App,
Button,
Card,
Form,
Input,
Modal,
Select,
Space,
Table,
Tag,
Typography,
} from 'antd'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useQuery } from '@tanstack/react-query' import { useQuery } from '@tanstack/react-query'
import { useState } from 'react' import { useState } from 'react'
@@ -244,7 +232,7 @@ export function CostItemPanel() {
style={{ width: 260 }} style={{ width: 260 }}
/> />
</Space> </Space>
<Table <PercentTable
tableLayout="fixed" tableLayout="fixed"
rowKey="id" rowKey="id"
size="small" size="small"
@@ -3,18 +3,8 @@
* *
* 履约方式直接读 order_items.fulfillment_mode,页面只做展示,不允许改判。 * 履约方式直接读 order_items.fulfillment_mode,页面只做展示,不允许改判。
*/ */
import { import { App, Alert, Button, Card, Descriptions, Empty, InputNumber, Space, Typography } from 'antd'
App, import PercentTable from '@/components/common/PercentTable'
Alert,
Button,
Card,
Descriptions,
Empty,
InputNumber,
Space,
Table,
Typography,
} from 'antd'
import { useState } from 'react' import { useState } from 'react'
import { createAdminCostSnapshot, previewAdminCost } from '@/services/admin' import { createAdminCostSnapshot, previewAdminCost } from '@/services/admin'
@@ -150,7 +140,7 @@ export function CostPreviewPanel() {
/> />
) : null} ) : null}
<Table <PercentTable
tableLayout="fixed" tableLayout="fixed"
rowKey={(row) => `${row.costItemId}-${row.costVersionId}`} rowKey={(row) => `${row.costItemId}-${row.costVersionId}`}
size="small" size="small"
@@ -17,10 +17,10 @@ import {
Modal, Modal,
Select, Select,
Space, Space,
Table,
Tag, Tag,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useQuery } from '@tanstack/react-query' import { useQuery } from '@tanstack/react-query'
import { useState } from 'react' import { useState } from 'react'
@@ -402,7 +402,7 @@ export function CostVersionPanel() {
style={{ width: 140 }} style={{ width: 140 }}
/> />
</Space> </Space>
<Table <PercentTable
tableLayout="fixed" tableLayout="fixed"
rowKey="id" rowKey="id"
size="small" size="small"
@@ -33,10 +33,10 @@ import {
Select, Select,
Space, Space,
Statistic, Statistic,
Table,
Tag, Tag,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { useState } from 'react' import { useState } from 'react'
@@ -382,7 +382,7 @@ export function ManualSkuConfigPanel() {
</Button> </Button>
</Space> </Space>
<Table <PercentTable
rowKey="id" rowKey="id"
size="small" size="small"
columns={columns} columns={columns}
@@ -23,11 +23,11 @@ import {
Select, Select,
Space, Space,
Switch, Switch,
Table,
Tabs, Tabs,
Tag, Tag,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useQuery, useQueryClient } from '@tanstack/react-query' import { useQuery, useQueryClient } from '@tanstack/react-query'
import { useState } from 'react' import { useState } from 'react'
@@ -559,7 +559,7 @@ export function ProductCatalogPanel() {
style={{ width: 280 }} style={{ width: 280 }}
/> />
</Space> </Space>
<Table <PercentTable
tableLayout="fixed" tableLayout="fixed"
rowKey="id" rowKey="id"
size="small" size="small"
@@ -24,11 +24,11 @@ import {
Select, Select,
Space, Space,
Statistic, Statistic,
Table,
Tabs, Tabs,
Tag, Tag,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import type { Dayjs } from 'dayjs' import type { Dayjs } from 'dayjs'
@@ -1048,7 +1048,7 @@ export default function FundManagementView({ role }: { role: ManagementRole }) {
) : null ) : null
} }
> >
<Table<AdminFundAccount> <PercentTable<AdminFundAccount>
rowKey="id" rowKey="id"
size="small" size="small"
columns={buildAccountColumns('agent')} columns={buildAccountColumns('agent')}
@@ -1074,7 +1074,7 @@ export default function FundManagementView({ role }: { role: ManagementRole }) {
) : null ) : null
} }
> >
<Table<AdminFundAccount> <PercentTable<AdminFundAccount>
rowKey="id" rowKey="id"
size="small" size="small"
columns={buildAccountColumns('supervisor')} columns={buildAccountColumns('supervisor')}
@@ -1139,7 +1139,7 @@ export default function FundManagementView({ role }: { role: ManagementRole }) {
}} }}
/> />
</Space> </Space>
<Table<AdminFundExpense> <PercentTable<AdminFundExpense>
rowKey="id" rowKey="id"
size="small" size="small"
columns={expenseColumns} columns={expenseColumns}
@@ -1188,7 +1188,7 @@ export default function FundManagementView({ role }: { role: ManagementRole }) {
)} )}
/> />
</Space> </Space>
<Table<AdminFundReconciliation> <PercentTable<AdminFundReconciliation>
rowKey="id" rowKey="id"
size="small" size="small"
columns={reconciliationColumns} columns={reconciliationColumns}
@@ -1227,7 +1227,7 @@ export default function FundManagementView({ role }: { role: ManagementRole }) {
</Space> </Space>
} }
> >
<Table<AdminFundAccount> <PercentTable<AdminFundAccount>
rowKey="id" rowKey="id"
size="small" size="small"
columns={buildAccountColumns('supervisor')} columns={buildAccountColumns('supervisor')}
@@ -1262,7 +1262,7 @@ export default function FundManagementView({ role }: { role: ManagementRole }) {
</Space> </Space>
} }
> >
<Table<AdminFundAccount> <PercentTable<AdminFundAccount>
rowKey="id" rowKey="id"
size="small" size="small"
columns={buildAccountColumns('agent')} columns={buildAccountColumns('agent')}
@@ -1793,7 +1793,7 @@ export default function FundManagementView({ role }: { role: ManagementRole }) {
</Descriptions.Item> </Descriptions.Item>
</Descriptions> </Descriptions>
<Card title="资金流水" style={{ marginTop: 16 }}> <Card title="资金流水" style={{ marginTop: 16 }}>
<Table<AdminFundEntry> <PercentTable<AdminFundEntry>
rowKey="id" rowKey="id"
size="small" size="small"
columns={detailEntryColumns} columns={detailEntryColumns}
@@ -18,11 +18,11 @@ import {
Select, Select,
Space, Space,
Statistic, Statistic,
Table,
Tabs, Tabs,
Tag, Tag,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { useState } from 'react' import { useState } from 'react'
@@ -497,7 +497,7 @@ export default function FundSupportView() {
key: 'credit-entries', key: 'credit-entries',
label: '积分流水', label: '积分流水',
children: ( children: (
<Table<PlatformCreditEntry> <PercentTable<PlatformCreditEntry>
rowKey="id" rowKey="id"
size="small" size="small"
columns={creditEntryColumns} columns={creditEntryColumns}
@@ -514,7 +514,7 @@ export default function FundSupportView() {
key: 'entries', key: 'entries',
label: '备用金流水', label: '备用金流水',
children: ( children: (
<Table<AdminFundEntry> <PercentTable<AdminFundEntry>
rowKey="id" rowKey="id"
size="small" size="small"
columns={entryColumns} columns={entryColumns}
@@ -529,7 +529,7 @@ export default function FundSupportView() {
key: 'expenses', key: 'expenses',
label: '我的支出', label: '我的支出',
children: ( children: (
<Table<AdminFundExpense> <PercentTable<AdminFundExpense>
rowKey="id" rowKey="id"
size="small" size="small"
columns={expenseColumns} columns={expenseColumns}
@@ -24,10 +24,10 @@ import {
Select, Select,
Space, Space,
Statistic, Statistic,
Table,
Tag, Tag,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useState } from 'react' import { useState } from 'react'
@@ -399,7 +399,7 @@ export function PlatformCreditPanel() {
<Typography.Title level={5} style={{ margin: '8px 0 12px' }}> <Typography.Title level={5} style={{ margin: '8px 0 12px' }}>
客服积分余额 客服积分余额
</Typography.Title> </Typography.Title>
<Table<PlatformCreditAccount> <PercentTable<PlatformCreditAccount>
rowKey="id" rowKey="id"
size="small" size="small"
columns={accountColumns} columns={accountColumns}
@@ -413,7 +413,7 @@ export function PlatformCreditPanel() {
<Typography.Title level={5} style={{ margin: '24px 0 12px' }}> <Typography.Title level={5} style={{ margin: '24px 0 12px' }}>
积分流水 积分流水
</Typography.Title> </Typography.Title>
<Table <PercentTable
rowKey="id" rowKey="id"
size="small" size="small"
columns={entryColumns} columns={entryColumns}
@@ -11,10 +11,10 @@ import {
Modal, Modal,
Select, Select,
Space, Space,
Table,
Tag, Tag,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import { forwardRef, useImperativeHandle, useState } from 'react' import { forwardRef, useImperativeHandle, useState } from 'react'
import ImageUpload from '@/components/files/ImageUpload' import ImageUpload from '@/components/files/ImageUpload'
@@ -195,7 +195,7 @@ const AfterSalesPanel = forwardRef<AfterSalesPanelHandle>(function AfterSalesPan
} }
bordered={false} bordered={false}
> >
<Table<WorkerAfterSalesCase> <PercentTable<WorkerAfterSalesCase>
rowKey="caseId" rowKey="caseId"
loading={afterSalesCasesQuery.isLoading} loading={afterSalesCasesQuery.isLoading}
dataSource={afterSalesCasesQuery.data?.data.items || []} dataSource={afterSalesCasesQuery.data?.data.items || []}
@@ -1,6 +1,7 @@
import { ReloadOutlined } from '@ant-design/icons' import { ReloadOutlined } from '@ant-design/icons'
import { useQuery, useQueryClient } from '@tanstack/react-query' import { useQuery, useQueryClient } from '@tanstack/react-query'
import { App, Button, Card, Form, Input, Modal, Space, Table, Tag, Typography } from 'antd' import { App, Button, Card, Form, Input, Modal, Space, Tag, Typography } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useSearchParams } from 'react-router' import { useSearchParams } from 'react-router'
@@ -147,7 +148,7 @@ export default function CancelRequestsPanel() {
} }
bordered={false} bordered={false}
> >
<Table<WorkerCancelRequest> <PercentTable<WorkerCancelRequest>
rowKey="requestId" rowKey="requestId"
size="small" size="small"
loading={requestsQuery.isLoading} loading={requestsQuery.isLoading}
@@ -11,11 +11,11 @@ import {
Modal, Modal,
Select, Select,
Space, Space,
Table,
Tag, Tag,
Typography, Typography,
Upload, Upload,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useMemo, useState } from 'react' import { useMemo, useState } from 'react'
@@ -312,7 +312,7 @@ export default function CategoriesPanel() {
</Form> </Form>
</Card> </Card>
<Card title="分类列表(树形层级)" bordered={false}> <Card title="分类列表(树形层级)" bordered={false}>
<Table<WorkCategory> <PercentTable<WorkCategory>
rowKey="categoryId" rowKey="categoryId"
loading={categoriesQuery.isLoading} loading={categoriesQuery.isLoading}
dataSource={treeData} dataSource={treeData}
@@ -18,11 +18,11 @@ import {
Space, Space,
Statistic, Statistic,
Switch, Switch,
Table,
Tag, Tag,
Tooltip, Tooltip,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useState } from 'react' import { useState } from 'react'
@@ -839,7 +839,7 @@ export default function ConsignmentInventoryPanel() {
} }
/> />
) : null} ) : null}
<Table <PercentTable
rowKey="id" rowKey="id"
columns={columns} columns={columns}
dataSource={items} dataSource={items}
@@ -20,12 +20,12 @@ import {
Row, Row,
Select, Select,
Space, Space,
Table,
Tag, Tag,
Tooltip, Tooltip,
Typography, Typography,
App, App,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useState } from 'react' import { useState } from 'react'
@@ -457,7 +457,7 @@ export default function ConsignmentSubmissionsPanel() {
} }
/> />
) : null} ) : null}
<Table <PercentTable
rowKey="id" rowKey="id"
columns={submissionColumns} columns={submissionColumns}
dataSource={submissions} dataSource={submissions}
@@ -1,6 +1,7 @@
import { ReloadOutlined } from '@ant-design/icons' import { ReloadOutlined } from '@ant-design/icons'
import { useQuery, useQueryClient } from '@tanstack/react-query' import { useQuery, useQueryClient } from '@tanstack/react-query'
import { App, Button, Card, Form, Input, Modal, Space, Table, Tag, Typography } from 'antd' import { App, Button, Card, Form, Input, Modal, Space, Tag, Typography } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useSearchParams } from 'react-router' import { useSearchParams } from 'react-router'
@@ -123,7 +124,7 @@ export default function FeedbacksPanel() {
} }
bordered={false} bordered={false}
> >
<Table<WorkerOrderFeedback> <PercentTable<WorkerOrderFeedback>
rowKey="feedbackId" rowKey="feedbackId"
size="small" size="small"
loading={feedbacksQuery.isLoading} loading={feedbacksQuery.isLoading}
@@ -13,10 +13,10 @@ import {
Select, Select,
Space, Space,
Switch, Switch,
Table,
Tag, Tag,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useSearchParams } from 'react-router' import { useSearchParams } from 'react-router'
@@ -585,7 +585,7 @@ export default function FinancePanel() {
totalCount={financeRequestsQuery.data?.data.summary?.totalCount} totalCount={financeRequestsQuery.data?.data.summary?.totalCount}
totalAmount={financeRequestsQuery.data?.data.summary?.totalAmount} totalAmount={financeRequestsQuery.data?.data.summary?.totalAmount}
/> />
<Table<WorkerFinanceRequest> <PercentTable<WorkerFinanceRequest>
rowKey="requestId" rowKey="requestId"
loading={financeRequestsQuery.isLoading} loading={financeRequestsQuery.isLoading}
dataSource={financeRequestsQuery.data?.data.items || []} dataSource={financeRequestsQuery.data?.data.items || []}
@@ -11,10 +11,10 @@ import {
InputNumber, InputNumber,
Space, Space,
Switch, Switch,
Table,
Tag, Tag,
Upload, Upload,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import { useEffect, useMemo, useState } from 'react' import { useEffect, useMemo, useState } from 'react'
import { import {
@@ -182,7 +182,7 @@ export default function HallConfigPanel() {
一级分类限额将限制该游戏及旗下所有子分类的总单量;二级分类可单独设置细化限额。 一级分类限额将限制该游戏及旗下所有子分类的总单量;二级分类可单独设置细化限额。
</span> </span>
</div> </div>
<Table<WorkCategory> <PercentTable<WorkCategory>
rowKey="categoryId" rowKey="categoryId"
size="small" size="small"
pagination={false} pagination={false}
@@ -1,5 +1,6 @@
import { useQuery } from '@tanstack/react-query' import { useQuery } from '@tanstack/react-query'
import { Card, Segmented, Space, Table, Tag, Typography } from 'antd' import { Card, Segmented, Space, Tag, Typography } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useState } from 'react' import { useState } from 'react'
@@ -134,7 +135,7 @@ export default function LeaderboardPanel() {
: ''} : ''}
</Typography.Text> </Typography.Text>
</Space> </Space>
<Table<AdminWorkerLeaderboardEntry> <PercentTable<AdminWorkerLeaderboardEntry>
rowKey="workerId" rowKey="workerId"
columns={columns} columns={columns}
dataSource={items} dataSource={items}
@@ -9,10 +9,10 @@ import {
Modal, Modal,
Space, Space,
Switch, Switch,
Table,
Tag, Tag,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useState } from 'react' import { useState } from 'react'
@@ -225,7 +225,7 @@ export default function LevelsPanel() {
</Form> </Form>
</Card> </Card>
<Card title="等级列表" bordered={false}> <Card title="等级列表" bordered={false}>
<Table<WorkerLevel> <PercentTable<WorkerLevel>
rowKey="levelId" rowKey="levelId"
loading={levelsQuery.isLoading} loading={levelsQuery.isLoading}
dataSource={levelsQuery.data?.data.items || []} dataSource={levelsQuery.data?.data.items || []}
@@ -1,5 +1,6 @@
import { useQuery, useQueryClient } from '@tanstack/react-query' import { useQuery, useQueryClient } from '@tanstack/react-query'
import { App, Alert, Button, Card, Space, Switch, Table, Typography } from 'antd' import { App, Alert, Button, Card, Space, Switch, Typography } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
@@ -143,7 +144,7 @@ export default function NotificationsPanel() {
message="配置仅影响保存后产生的通知" message="配置仅影响保存后产生的通知"
description="关闭后台待办后,声音播报会同步关闭;已创建的待办不会被隐藏或删除。" description="关闭后台待办后,声音播报会同步关闭;已创建的待办不会被隐藏或删除。"
/> />
<Table <PercentTable
rowKey="key" rowKey="key"
columns={columns} columns={columns}
dataSource={notificationEventRows} dataSource={notificationEventRows}
@@ -18,11 +18,11 @@ import {
Select, Select,
Space, Space,
Switch, Switch,
Table,
Tabs, Tabs,
Tag, Tag,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useNavigate } from 'react-router' import { useNavigate } from 'react-router'
@@ -359,7 +359,7 @@ export default function ProductMatchPanel() {
发现新商品后,点击「绑定到模板」在接单模板页配置匹配 发现新商品后,点击「绑定到模板」在接单模板页配置匹配
</Typography.Text> </Typography.Text>
</Space> </Space>
<Table<KuaishouMatchSource> <PercentTable<KuaishouMatchSource>
rowKey={(row) => rowKey={(row) =>
`${row.sellerId}-${row.relItemId}-${row.itemTitle}-${row.relSkuId}-${row.skuNick}` `${row.sellerId}-${row.relItemId}-${row.itemTitle}-${row.relSkuId}-${row.skuNick}`
} }
@@ -660,7 +660,7 @@ export default function ProductMatchPanel() {
</Button> </Button>
</Popconfirm> </Popconfirm>
</div> </div>
<Table<WorkProductMatchLog> <PercentTable<WorkProductMatchLog>
rowKey="logId" rowKey="logId"
loading={logsQuery.isLoading} loading={logsQuery.isLoading}
columns={logColumns} columns={logColumns}
@@ -23,11 +23,11 @@ import {
Select, Select,
Space, Space,
Switch, Switch,
Table,
Tabs, Tabs,
Tag, Tag,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useEffect, useMemo, useRef, useState } from 'react' import { useEffect, useMemo, useRef, useState } from 'react'
import { useNavigate, useSearchParams } from 'react-router' import { useNavigate, useSearchParams } from 'react-router'
@@ -1350,7 +1350,7 @@ export default function ProductRulesPanel() {
</div> </div>
) : null} ) : null}
<Table<WorkProductRule> <PercentTable<WorkProductRule>
rowKey="ruleId" rowKey="ruleId"
size="small" size="small"
loading={rulesQuery.isLoading || mappingsQuery.isLoading} loading={rulesQuery.isLoading || mappingsQuery.isLoading}
@@ -11,9 +11,9 @@ import {
Select, Select,
Space, Space,
Switch, Switch,
Table,
Tag, Tag,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { ColumnsType } from 'antd/es/table' import type { ColumnsType } from 'antd/es/table'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
@@ -381,7 +381,7 @@ export default function RiskControlPanel() {
</Button> </Button>
} }
> >
<Table <PercentTable
rowKey="key" rowKey="key"
size="small" size="small"
columns={trackerColumns} columns={trackerColumns}
@@ -427,7 +427,7 @@ export default function RiskControlPanel() {
</Button> </Button>
</Space> </Space>
<Table <PercentTable
rowKey="id" rowKey="id"
size="small" size="small"
columns={eventColumns} columns={eventColumns}
@@ -32,11 +32,11 @@ import {
Select, Select,
Space, Space,
Switch, Switch,
Table,
Tabs, Tabs,
Tag, Tag,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useEffect, useMemo, useRef, useState } from 'react' import { useEffect, useMemo, useRef, useState } from 'react'
import { useNavigate, useSearchParams } from 'react-router' import { useNavigate, useSearchParams } from 'react-router'
@@ -2076,7 +2076,7 @@ export default function WorkOrdersPanel() {
} }
bordered={false} bordered={false}
> >
<Table<WorkOrder> <PercentTable<WorkOrder>
rowKey="workOrderId" rowKey="workOrderId"
loading={ordersQuery.isLoading} loading={ordersQuery.isLoading}
dataSource={ordersQuery.data?.data.items || []} dataSource={ordersQuery.data?.data.items || []}
@@ -3139,7 +3139,7 @@ export default function WorkOrdersPanel() {
</div> </div>
</Space> </Space>
) : null} ) : null}
<Table<WorkOrderShare> <PercentTable<WorkOrderShare>
rowKey="shareId" rowKey="shareId"
size="small" size="small"
dataSource={sharingShares} dataSource={sharingShares}
@@ -1,5 +1,6 @@
import { useState } from 'react' import { useState } from 'react'
import { Card, Descriptions, Drawer, Select, Space, Table, Tabs, Tag, Typography } from 'antd' import { Card, Descriptions, Drawer, Select, Space, Tabs, Tag, Typography } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useQuery } from '@tanstack/react-query' import { useQuery } from '@tanstack/react-query'
@@ -303,7 +304,7 @@ function UnfreezesSection({ workerId }: { workerId: number }) {
}, },
] ]
return ( return (
<Table<WorkerDepositUnfreeze> <PercentTable<WorkerDepositUnfreeze>
rowKey="id" rowKey="id"
size="small" size="small"
columns={columns} columns={columns}
@@ -398,7 +399,7 @@ function LedgersSection({ workerId }: { workerId: number }) {
setPage(1) setPage(1)
}} }}
/> />
<Table<WorkerWalletLedger> <PercentTable<WorkerWalletLedger>
rowKey="ledgerId" rowKey="ledgerId"
size="small" size="small"
columns={columns} columns={columns}
@@ -463,7 +464,7 @@ function OrdersSection({ workerId }: { workerId: number }) {
}, },
] ]
return ( return (
<Table<WorkOrder> <PercentTable<WorkOrder>
rowKey="workOrderId" rowKey="workOrderId"
size="small" size="small"
columns={columns} columns={columns}
@@ -13,11 +13,11 @@ import {
Select, Select,
Space, Space,
Switch, Switch,
Table,
Tag, Tag,
Tooltip, Tooltip,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { useSearchParams } from 'react-router' import { useSearchParams } from 'react-router'
@@ -952,7 +952,7 @@ export default function WorkersPanel() {
: '寄卖白名单已关闭:全部打手均可发布寄卖。下方开关仅在重新开启白名单后生效。' : '寄卖白名单已关闭:全部打手均可发布寄卖。下方开关仅在重新开启白名单后生效。'
} }
/> />
<Table<WorkerUser> <PercentTable<WorkerUser>
rowKey="workerId" rowKey="workerId"
loading={workersQuery.isLoading} loading={workersQuery.isLoading}
dataSource={workersQuery.data?.data.items || []} dataSource={workersQuery.data?.data.items || []}
@@ -18,7 +18,6 @@ import {
Space, Space,
Spin, Spin,
Switch, Switch,
Table,
Tag, Tag,
Typography, Typography,
} from 'antd' } from 'antd'
@@ -19,11 +19,11 @@ import {
Space, Space,
Spin, Spin,
Switch, Switch,
Table,
Tabs, Tabs,
Tag, Tag,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useSearchParams } from 'react-router' import { useSearchParams } from 'react-router'
@@ -1106,7 +1106,7 @@ function KuaishouIndustryPanel({
{shops.length === 0 ? ( {shops.length === 0 ? (
<Empty description="暂无店铺授权" /> <Empty description="暂无店铺授权" />
) : ( ) : (
<Table<AdminKuaishouIndustryShopConfig> <PercentTable<AdminKuaishouIndustryShopConfig>
rowKey={(row, index) => buildIndustryShopRowKey(row, index || 0)} rowKey={(row, index) => buildIndustryShopRowKey(row, index || 0)}
columns={shopColumns} columns={shopColumns}
dataSource={shops} dataSource={shops}
@@ -1694,7 +1694,7 @@ function AffiliateDashPlatformPanel() {
<Typography.Text code>apps/backend/.../affiliate-dash/sku-mapping.ts</Typography.Text> <Typography.Text code>apps/backend/.../affiliate-dash/sku-mapping.ts</Typography.Text>
,与平台商品目录对齐。 ,与平台商品目录对齐。
</Typography.Paragraph> </Typography.Paragraph>
<Table<SkuMappingRow> <PercentTable<SkuMappingRow>
rowKey={(row) => row.productNo} rowKey={(row) => row.productNo}
size="small" size="small"
pagination={{ pageSize: 10, showSizeChanger: false }} pagination={{ pageSize: 10, showSizeChanger: false }}
@@ -1760,7 +1760,7 @@ function AffiliateDashPlatformPanel() {
</Typography.Text> </Typography.Text>
) : null} ) : null}
</Space> </Space>
<Table<AdminAffiliateDashProductItem> <PercentTable<AdminAffiliateDashProductItem>
rowKey="sku" rowKey="sku"
size="small" size="small"
loading={productsLoading} loading={productsLoading}
@@ -39,11 +39,11 @@ import {
Spin, Spin,
Statistic, Statistic,
Switch, Switch,
Table,
Tag, Tag,
Tooltip, Tooltip,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
@@ -986,7 +986,7 @@ export function PddPlatformPanel() {
</Button> </Button>
} }
> >
<Table <PercentTable
rowKey="shopId" rowKey="shopId"
columns={columns} columns={columns}
dataSource={config.stores} dataSource={config.stores}
@@ -16,11 +16,11 @@ import {
Modal, Modal,
Segmented, Segmented,
Space, Space,
Table,
Tabs, Tabs,
Typography, Typography,
type InputRef, type InputRef,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { Navigate, useNavigate } from 'react-router' import { Navigate, useNavigate } from 'react-router'
@@ -665,7 +665,7 @@ export default function WorkerLoginPage() {
message="验证账号密码后,可删除旧设备。PC 和手机分别最多同时在线 3 台。" message="验证账号密码后,可删除旧设备。PC 和手机分别最多同时在线 3 台。"
style={{ marginBottom: 16 }} style={{ marginBottom: 16 }}
/> />
<Table <PercentTable
size="small" size="small"
rowKey="sessionId" rowKey="sessionId"
loading={deviceManagerLoading} loading={deviceManagerLoading}
@@ -6,7 +6,8 @@ import {
ThunderboltOutlined, ThunderboltOutlined,
WarningOutlined, WarningOutlined,
} from '@ant-design/icons' } from '@ant-design/icons'
import { Alert, Button, Card, Empty, Input, Space, Table, Tabs, Typography } from 'antd' import { Alert, Button, Card, Empty, Input, Space, Tabs, Typography } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { TableColumnsType } from 'antd' import type { TableColumnsType } from 'antd'
import type { Pagination, WorkerOrderOverviewItem, WorkOrder } from '@/types/worker-platform' import type { Pagination, WorkerOrderOverviewItem, WorkOrder } from '@/types/worker-platform'
@@ -255,7 +256,7 @@ export function WorkerOrderDesktopList({
/> />
) : null} ) : null}
<Table<WorkOrder> <PercentTable<WorkOrder>
rowKey="workOrderId" rowKey="workOrderId"
size="middle" size="middle"
loading={loading} loading={loading}
@@ -8,9 +8,9 @@ import {
Input, Input,
Modal, Modal,
Space, Space,
Table,
Typography, Typography,
} from 'antd' } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { FormInstance } from 'antd' import type { FormInstance } from 'antd'
import type { WorkerFinanceConfig, WorkerSessionDevice, WorkerUser } from '@/types/worker-platform' import type { WorkerFinanceConfig, WorkerSessionDevice, WorkerUser } from '@/types/worker-platform'
@@ -93,7 +93,7 @@ export function WorkerProfileAccountModals({
type="info" type="info"
message={`PC 和手机分别最多同时在线 ${maxDevices} 台(当前 PC ${deviceCounts.pc} 台、手机 ${deviceCounts.mobile} 台),删除对应旧设备后才能登录。`} message={`PC 和手机分别最多同时在线 ${maxDevices} 台(当前 PC ${deviceCounts.pc} 台、手机 ${deviceCounts.mobile} 台),删除对应旧设备后才能登录。`}
/> />
<Table<WorkerSessionDevice> <PercentTable<WorkerSessionDevice>
size="small" size="small"
loading={devicesLoading} loading={devicesLoading}
rowKey="sessionId" rowKey="sessionId"
@@ -1,5 +1,6 @@
import { ReloadOutlined } from '@ant-design/icons' import { ReloadOutlined } from '@ant-design/icons'
import { Button, Card, Empty, Pagination, Select, Space, Spin, Table, Tag } from 'antd' import { Button, Card, Empty, Pagination, Select, Space, Spin, Tag } from 'antd'
import PercentTable from '@/components/common/PercentTable'
import type { import type {
WorkerFinanceRequest, WorkerFinanceRequest,
@@ -293,7 +294,7 @@ export function WorkerProfileDesktopLedgerRecords({
</Space> </Space>
} }
> >
<Table<WorkerWalletLedger> <PercentTable<WorkerWalletLedger>
rowKey="ledgerId" rowKey="ledgerId"
size="small" size="small"
loading={loading} loading={loading}
@@ -353,7 +354,7 @@ export function WorkerProfileDesktopRequestRecords({
</Space> </Space>
} }
> >
<Table<WorkerFinanceRequest> <PercentTable<WorkerFinanceRequest>
rowKey="requestId" rowKey="requestId"
size="small" size="small"
loading={loading} loading={loading}
+1
View File
@@ -11,3 +11,4 @@
@import './admin.css'; @import './admin.css';
@import './client.css'; @import './client.css';
@import './worker.css'; @import './worker.css';
@import './table.css';
+10
View File
@@ -0,0 +1,10 @@
/* 全项目表格统一规范:宽度百分比自适应,表头与内容全部居中。 */
.ant-table-wrapper .ant-table {
width: 100%;
table-layout: fixed;
}
.ant-table-wrapper .ant-table-thead > tr > th,
.ant-table-wrapper .ant-table-tbody > tr > td {
text-align: center !important;
}
@@ -0,0 +1,94 @@
import type { TableColumnsType } from 'antd'
type Column<RecordType extends object> = TableColumnsType<RecordType>[number]
type WidthContext<RecordType extends object> = {
leafPercent: WeakMap<Column<RecordType>, number>
}
/**
* 把业务列宽(px 数值)按相对权重归一化为百分比。
* rowSelection / expandable 等内置列由调用方传入需要预留的百分比。
*/
export function normalizePercentColumns<RecordType extends object>(
columns: TableColumnsType<RecordType>,
options: { reservedPercent?: number } = {},
): TableColumnsType<RecordType> {
const leaves: Column<RecordType>[] = []
collectLeaves(columns, leaves)
const explicitWeights = leaves
.map((column) => numericWidth(column.width))
.filter((width): width is number => width !== null)
const fallbackWeight =
explicitWeights.length > 0
? explicitWeights.reduce((sum, width) => sum + width, 0) / explicitWeights.length
: 100
const totalWeight = leaves.reduce(
(sum, column) => sum + (numericWidth(column.width) ?? fallbackWeight),
0,
)
const budgetPercent = Math.max(60, 100 - Math.max(0, options.reservedPercent ?? 0))
const leafPercent = new WeakMap<Column<RecordType>, number>()
for (const column of leaves) {
const weight = numericWidth(column.width) ?? fallbackWeight
leafPercent.set(column, (weight / totalWeight) * budgetPercent)
}
return applyPercentWidths(columns, { leafPercent })
}
function applyPercentWidths<RecordType extends object>(
columns: TableColumnsType<RecordType>,
context: WidthContext<RecordType>,
): TableColumnsType<RecordType> {
return columns.map((column) => {
const children = 'children' in column ? column.children : undefined
if (Array.isArray(children) && children.length > 0) {
const normalizedChildren = applyPercentWidths(children, context)
const width = normalizedChildren.reduce((sum, child) => sum + percentOf(child.width), 0)
return {
...column,
width: `${width.toFixed(4)}%`,
align: 'center',
children: normalizedChildren,
}
}
return {
...column,
width: `${(context.leafPercent.get(column) ?? 0).toFixed(4)}%`,
align: 'center',
}
})
}
function collectLeaves<RecordType extends object>(
columns: TableColumnsType<RecordType>,
leaves: Column<RecordType>[],
) {
for (const column of columns) {
const children = 'children' in column ? column.children : undefined
if (Array.isArray(children) && children.length > 0) {
collectLeaves(children, leaves)
} else {
leaves.push(column)
}
}
}
function numericWidth(width: Column<object>['width']) {
if (typeof width === 'number' && Number.isFinite(width) && width > 0) return width
if (typeof width === 'string') {
const parsed = Number.parseFloat(width)
if (Number.isFinite(parsed) && parsed > 0) return parsed
}
return null
}
function percentOf(width: Column<object>['width']) {
if (typeof width !== 'string' || !width.endsWith('%')) return 0
const parsed = Number.parseFloat(width)
return Number.isFinite(parsed) ? parsed : 0
}
@@ -0,0 +1,77 @@
import assert from 'node:assert/strict'
import fs from 'node:fs'
import path from 'node:path'
import test from 'node:test'
import type { TableColumnsType } from 'antd'
import { normalizePercentColumns } from '../src/utils/percent-table-layout.ts'
test('百分比表格:按原列宽权重归一化到 100%', () => {
const columns: TableColumnsType<Record<string, unknown>> = [
{ title: 'A', dataIndex: 'a', width: 100 },
{ title: 'B', dataIndex: 'b', width: 300 },
]
const result = normalizePercentColumns(columns)
assert.deepEqual(
result.map((column) => column.width),
['25.0000%', '75.0000%'],
)
assert.ok(result.every((column) => column.align === 'center'))
})
test('百分比表格:没有列宽时平均分配', () => {
const columns: TableColumnsType<Record<string, unknown>> = [
{ title: 'A', dataIndex: 'a' },
{ title: 'B', dataIndex: 'b' },
]
assert.deepEqual(
normalizePercentColumns(columns).map((column) => column.width),
['50.0000%', '50.0000%'],
)
})
test('百分比表格:选择列预留 4%', () => {
const columns: TableColumnsType<Record<string, unknown>> = [
{ title: 'A', dataIndex: 'a', width: 100 },
{ title: 'B', dataIndex: 'b', width: 100 },
]
const result = normalizePercentColumns(columns, { reservedPercent: 4 })
assert.deepEqual(
result.map((column) => column.width),
['48.0000%', '48.0000%'],
)
})
test('百分比表格:分组列宽等于子列之和', () => {
const columns: TableColumnsType<Record<string, unknown>> = [
{
title: '分组',
children: [
{ title: 'A', dataIndex: 'a', width: 100 },
{ title: 'B', dataIndex: 'b', width: 100 },
],
},
]
const result = normalizePercentColumns(columns)
assert.equal(result[0]?.width, '100.0000%')
})
test('全项目表格必须统一使用 PercentTable', () => {
const offenders: string[] = []
for (const file of listTsxFiles(path.join(process.cwd(), 'src'))) {
const source = fs.readFileSync(file, 'utf8')
if (/<Table\b/.test(source)) {
offenders.push(path.relative(process.cwd(), file))
}
}
assert.deepEqual(offenders, [], `仍有表格直接使用 AntD Table:${offenders.join(', ')}`)
})
function listTsxFiles(dir: string): string[] {
return fs.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
const fullPath = path.join(dir, entry.name)
if (entry.isDirectory()) return listTsxFiles(fullPath)
return entry.isFile() && entry.name.endsWith('.tsx') ? [fullPath] : []
})
}