feat: 高级列表

This commit is contained in:
2025-09-13 17:56:13 +08:00
parent e42e1c01fb
commit 9d5a289929
18 changed files with 1301 additions and 6739 deletions

View File

@@ -0,0 +1,294 @@
// components/EnhancedProTable/EnhancedProTable.tsx
import React, { useRef, useState, useCallback, useMemo } from "react";
import {
ProTable,
ProColumns,
ActionType,
TableDropdown,
ParamsType,
} from "@ant-design/pro-components";
import { Button, Space } from "antd";
import {
EnhancedProTableProps,
BaseRecord,
TableAction,
ToolbarAction,
} from "./types";
import {
buildTableDropdownMenuItems,
handleTableDropdownSelect,
formatPaginationTotal,
} from "@/utils/antd/tableHelpers";
function EnhancedProTable<T extends BaseRecord, U extends ParamsType = any>(
props: EnhancedProTableProps<T, U>
) {
const {
columns: originalColumns,
request,
actions = [],
toolbarActions = [],
permissions = [],
checkPermission = () => true,
showIndex = true,
showSelection = true,
showActions = true,
maxActionCount = 2,
onAdd,
onEdit,
onDelete,
onView,
onExport,
customToolbarRender,
customActionRender,
...restProps
} = props;
const actionRef = useRef<ActionType>(null);
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const [selectedRows, setSelectedRows] = useState<T[]>([]);
// 权限检查
const hasPermission = useCallback(
(permission?: string) => {
if (!permission) return true;
return checkPermission(permission);
},
[checkPermission]
);
// 过滤有权限的操作
const filteredActions = useMemo(() => {
return actions.filter((action) => hasPermission(action.permission));
}, [actions, hasPermission]);
const filteredToolbarActions = useMemo(() => {
return toolbarActions.filter((action) => hasPermission(action.permission));
}, [toolbarActions, hasPermission]);
// 构建操作列
const buildActionColumn = useCallback((): ProColumns<T> => {
if (!showActions || filteredActions.length === 0) {
return {} as ProColumns<T>;
}
return {
title: "操作",
valueType: "option",
key: "actions",
fixed: "right",
width: Math.min(filteredActions.length * 60 + 50, 200),
render: (_, record, index, action) => {
// 过滤可见的操作
const visibleActions = filteredActions.filter(
(actionItem) => !actionItem.visible || actionItem.visible(record)
);
if (visibleActions.length === 0) return null;
// 显示的操作按钮
const displayActions = visibleActions.slice(0, maxActionCount);
// 更多操作
const moreActions = visibleActions.slice(maxActionCount);
const actionElements: React.ReactNode[] = displayActions.map(
(actionItem) => (
<a
key={actionItem.key}
onClick={() => actionItem.onClick(record, action)}
style={{
color: actionItem.danger ? "#ff4d4f" : undefined,
}}
>
{actionItem.icon} {actionItem.label}
</a>
)
);
// 如果有更多操作,添加下拉菜单
if (moreActions.length > 0) {
const menuItems = buildTableDropdownMenuItems(
moreActions.map((actionItem) => ({
key: actionItem.key,
label: actionItem.label,
icon: actionItem.icon,
danger: actionItem.danger,
disabled: actionItem.disabled?.(record) || false,
}))
);
actionElements.push(
<TableDropdown
key="more"
onSelect={(key) => {
handleTableDropdownSelect(key, moreActions, record, action);
action?.reload();
}}
menus={menuItems}
/>
);
}
// 自定义操作渲染
if (customActionRender) {
return customActionRender(record, actionElements);
}
return actionElements;
},
};
}, [showActions, filteredActions, maxActionCount, customActionRender]);
// 构建列配置
const enhancedColumns = useMemo(() => {
const columns: ProColumns<T>[] = [];
// 添加序号列
if (showIndex) {
columns.push({
title: "序号",
dataIndex: "index",
valueType: "indexBorder",
width: 48,
fixed: "left",
});
}
// 添加原始列
columns.push(...originalColumns);
// 添加操作列
const actionColumn = buildActionColumn();
if (actionColumn.title) {
columns.push(actionColumn);
}
return columns;
}, [originalColumns, showIndex, buildActionColumn]);
// 工具栏渲染
const toolBarRender = useCallback(() => {
const defaultActions = filteredToolbarActions.map((action) => (
<Button
key={action.key}
type={action.type}
danger={action.danger}
icon={action.icon}
disabled={
action.disabled ||
(action.needSelection && selectedRowKeys.length === 0)
}
onClick={() =>
action.onClick(selectedRowKeys as number[], selectedRows)
}
>
{action.label}
</Button>
));
if (customToolbarRender) {
return customToolbarRender(defaultActions);
}
return defaultActions;
}, [
filteredToolbarActions,
selectedRowKeys,
selectedRows,
customToolbarRender,
]);
// 行选择配置
const rowSelection = useMemo(() => {
if (!showSelection) return undefined;
return {
selectedRowKeys,
onChange: (keys: React.Key[], rows: T[]) => {
setSelectedRowKeys(keys);
setSelectedRows(rows);
},
getCheckboxProps: (record: T) => ({
name: record.id?.toString(),
}),
};
}, [showSelection, selectedRowKeys]);
// 表格提醒渲染
const tableAlertRender = useCallback(
({ selectedRowKeys, onCleanSelected }: any) => {
if (!showSelection || selectedRowKeys.length === 0) return false;
return (
<Space size={24}>
<span>
{selectedRowKeys.length}
<a style={{ marginLeft: 8 }} onClick={onCleanSelected}>
</a>
</span>
</Space>
);
},
[showSelection]
);
// 表格提醒操作渲染
const tableAlertOptionRender = useCallback(() => {
if (!showSelection || selectedRowKeys.length === 0) return false;
const batchActions = filteredToolbarActions.filter(
(action) => action.needSelection
);
if (batchActions.length === 0) return false;
return (
<Space size={16}>
{batchActions.map((action) => (
<a
key={action.key}
onClick={() =>
action.onClick(selectedRowKeys as number[], selectedRows)
}
>
{action.label}
</a>
))}
</Space>
);
}, [showSelection, selectedRowKeys, selectedRows, filteredToolbarActions]);
return (
<ProTable<T, U>
{...restProps}
columns={enhancedColumns}
actionRef={actionRef}
request={request}
rowKey="id"
rowSelection={rowSelection}
toolBarRender={toolBarRender}
tableAlertRender={tableAlertRender}
tableAlertOptionRender={tableAlertOptionRender}
search={{
labelWidth: "auto",
...restProps.search,
}}
options={{
fullScreen: true,
reload: true,
setting: true,
density: true,
...restProps.options,
}}
pagination={{
showSizeChanger: true,
showQuickJumper: true,
showTotal: formatPaginationTotal,
...restProps.pagination,
}}
/>
);
}
export default EnhancedProTable;