GenericDataTable
是一个基于 Ant Design Table 的通用数据表格组件,支持泛型数据类型、列配置、列宽调整、行交互等功能。
src/components/GenericDataTable.tsx
src/pages/patient/OutputList.tsx
- 传输队列表格src/pages/patient/worklist.tsx
- 工作列表表格(待改造)columnConfigService
集成import { GenericDataTable, ColumnDefinition } from '@/components/GenericDataTable';
interface MyData {
id: string;
name: string;
status: string;
}
const columns: ColumnDefinition<MyData>[] = [
{
title: '名称',
dataIndex: 'name',
width: 150,
},
{
title: '状态',
dataIndex: 'status',
width: 100,
},
];
function MyTable() {
const [selectedIds, setSelectedIds] = useState<string[]>([]);
const data: MyData[] = [
{ id: '1', name: '张三', status: '正常' },
{ id: '2', name: '李四', status: '异常' },
];
return (
<GenericDataTable<MyData>
dataSource={data}
rowKey="id"
columnDefinitions={columns}
selectedIds={selectedIds}
onRowClick={(record) => setSelectedIds([record.id])}
/>
);
}
import { FormattedMessage } from 'react-intl';
const columns: ColumnDefinition<SendJob>[] = [
{
title: (
<FormattedMessage
id="outputTable.name"
defaultMessage="Patient Name"
/>
),
dataIndex: 'patient_name',
width: 150,
},
{
title: (
<FormattedMessage
id="outputTable.status"
defaultMessage="Status"
/>
),
dataIndex: 'status',
width: 120,
},
];
const columns: ColumnDefinition<SendJob>[] = [
{
title: '重试次数',
dataIndex: 'retry_count',
width: 100,
render: (value) => value ?? 0, // 显示 0 而不是 undefined
},
{
title: '状态',
dataIndex: 'status',
width: 100,
render: (value) => {
const statusMap = {
'ARRIVED': '已到达',
'SENDING': '发送中',
'FAILED': '失败',
'SUCCESS': '成功',
};
return statusMap[value] || value;
},
},
];
import { columnConfigService } from '@/config/tableColumns';
import { ColumnConfig } from '@/config/tableColumns/types/columnConfig';
function MyTable() {
const [columnConfig, setColumnConfig] = useState<ColumnConfig[]>([]);
// 加载列配置
useEffect(() => {
columnConfigService
.getColumnConfig('output')
.then((config) => setColumnConfig(config.columns))
.catch((error) => {
console.error('Failed to load column config:', error);
setColumnConfig([]);
});
}, []);
return (
<GenericDataTable<SendJob>
dataSource={data}
rowKey="task_id"
columnDefinitions={columns}
columnConfig={columnConfig} // 传入列配置
selectedIds={selectedIds}
onRowClick={handleRowClick}
/>
);
}
import React, { useState, useEffect } from 'react';
import { GenericDataTable, ColumnDefinition } from '@/components/GenericDataTable';
import GenericPagination from '@/components/GenericPagination';
import { useAppDispatch, useAppSelector } from '@/states/store';
import {
fetchSendQueueThunk,
sendJobSelectionSlice,
sendJobPaginationSlice,
} from '@/states/output/sendJob/slices/sendJobSlice';
import { SendJob } from '@/domain/output/sendJob';
import { FormattedMessage } from 'react-intl';
// 定义列
const sendJobColumns: ColumnDefinition<SendJob>[] = [
{
title: <FormattedMessage id="outputTable.name" defaultMessage="Patient Name" />,
dataIndex: 'patient_name',
width: 150,
},
{
title: <FormattedMessage id="outputTable.status" defaultMessage="Status" />,
dataIndex: 'status',
width: 120,
},
];
function OutputList() {
const dispatch = useAppDispatch();
const { data: sendJobs } = useAppSelector((state) => state.sendJobEntities);
const { loading } = useAppSelector((state) => state.sendJobUI);
const { page, pageSize } = useAppSelector((state) => state.sendJobPagination);
const selectedIds = useAppSelector((state) => state.sendJobSelection.selectedIds);
// 加载数据
useEffect(() => {
dispatch(fetchSendQueueThunk({ page, pageSize, filters: {} }));
}, [dispatch, page, pageSize]);
// 行点击
const handleRowClick = (record: SendJob) => {
dispatch(sendJobSelectionSlice.actions.setSelectedIds([record.task_id]));
};
return (
<div className="h-full flex flex-col">
<div className="flex-1 overflow-auto">
<GenericDataTable<SendJob>
dataSource={sendJobs}
rowKey="task_id"
columnDefinitions={sendJobColumns}
selectedIds={selectedIds}
onRowClick={handleRowClick}
loading={loading}
className="px-4"
/>
</div>
<GenericPagination
paginationSelector={(state) => state.sendJobPagination}
entitiesSelector={(state) => state.sendJobEntities}
paginationActions={sendJobPaginationSlice.actions}
className="border-t"
/>
</div>
);
}
属性 | 类型 | 必填 | 默认值 | 描述 |
---|---|---|---|---|
dataSource | T[] | ✅ | - | 数据源 |
rowKey | keyof T | ((record: T) => string) | ✅ | - | 行键,用于唯一标识每一行 |
columnDefinitions | ColumnDefinition[] | ✅ | - | 列定义数组 |
columnConfig | ColumnConfig[] | ❌ | [] | 列配置(显示/隐藏、排序等) |
selectedIds | string[] | ✅ | - | 选中的行 ID 列表 |
onRowClick | (record: T) => void | ❌ | - | 行点击事件 |
onRowDoubleClick | (record: T) => void | ❌ | - | 行双击事件 |
className | string | ❌ | '' | 自定义类名 |
loading | boolean | ❌ | false | 加载状态 |
属性 | 类型 | 必填 | 默认值 | 描述 |
---|---|---|---|---|
title | React.ReactNode | ✅ | - | 列标题 |
dataIndex | keyof T | ✅ | - | 数据索引 |
width | number | ❌ | 150 | 默认宽度(px) |
render | (value: any, record: T, index: number) => React.ReactNode | ❌ | - | 自定义渲染函数 |
<GenericDataTable<MyData>
dataSource={data}
rowKey={(record) => `${record.type}_${record.id}`} // 组合键
// ...
/>
const columns: ColumnDefinition<SendJob>[] = [
{
title: '状态',
dataIndex: 'status',
render: (value, record) => {
if (value === 'FAILED') {
return <span className="text-red-500">失败</span>;
}
if (value === 'SUCCESS') {
return <span className="text-green-500">成功</span>;
}
return value;
},
},
];
const [selectedIds, setSelectedIds] = useState<string[]>([]);
const handleRowClick = (record: MyData) => {
setSelectedIds((prev) => {
if (prev.includes(record.id)) {
// 取消选择
return prev.filter((id) => id !== record.id);
} else {
// 添加选择
return [...prev, record.id];
}
});
};
<GenericDataTable<MyData>
// ...
selectedIds={selectedIds}
onRowClick={handleRowClick}
/>
数据类型 T
必须是对象类型:
T extends Record<string, any>
// ✅ 正确
rowKey="id" // 确保 id 唯一
// ✅ 正确
rowKey={(record) => record.task_id}
// ❌ 错误 - 可能重复
rowKey={(record) => record.status}
如果提供了 columnConfig
,则:
visible: true
的列order
排序width
覆盖默认宽度如果没有 columnConfig
,显示所有列。
对于大数据集,考虑:
<GenericDataTable
className="my-custom-table"
// ...
/>
当前使用 bg-yellow-500
和 hover:bg-yellow-800
,可以通过修改组件源码自定义:
// 在 GenericDataTable.tsx 中
rowClassName={(record) => {
const rowId = getRowKey(record);
return selectedIds.includes(rowId)
? 'bg-blue-500 hover:bg-blue-700' // 自定义颜色
: '';
}}
特性 | WorklistTable | GenericDataTable |
---|---|---|
数据类型 | 固定 Task | 泛型 T |
列定义 | 硬编码 | 传入参数 |
复用性 | 低 | 高 |
类型安全 | Task 类型 | 完全类型安全 |
列配置 | 支持 | 支持 |
列宽调整 | 支持 | 支持 |
行交互 | 支持 | 支持 |
暂无