feat: menu

This commit is contained in:
2025-09-17 10:41:00 +08:00
parent 9d5a289929
commit aada97ed22
27 changed files with 973 additions and 527 deletions

View File

@@ -1,5 +1,12 @@
// components/EnhancedProTable/EnhancedProTable.tsx
import React, { useRef, useState, useCallback, useMemo } from "react";
import React, {
useRef,
useState,
useCallback,
useMemo,
act,
forwardRef,
} from "react";
import {
ProTable,
ProColumns,
@@ -19,17 +26,19 @@ import {
handleTableDropdownSelect,
formatPaginationTotal,
} from "@/utils/antd/tableHelpers";
import { PlusOutlined } from "@ant-design/icons";
function EnhancedProTable<T extends BaseRecord, U extends ParamsType = any>(
props: EnhancedProTableProps<T, U>
props: EnhancedProTableProps<T, U>,
ref: React.Ref<ActionType | undefined> | undefined
) {
const {
columns: originalColumns,
columns,
request,
actions = [],
toolbarActions = [],
permissions = [],
checkPermission = () => true,
toolbarActions,
showIndex = true,
showSelection = true,
showActions = true,
@@ -44,160 +53,8 @@ function EnhancedProTable<T extends BaseRecord, U extends ParamsType = any>(
...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;
@@ -233,45 +90,60 @@ function EnhancedProTable<T extends BaseRecord, U extends ParamsType = any>(
[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]);
const toolBarRender = useCallback(
(
action: ActionType | undefined,
rows: {
selectedRowKeys?: (string | number)[] | undefined;
selectedRows?: T[] | undefined;
}
) => {
const toolbarElements =
toolbarActions?.map((action) => {
return (
<Button
key={action.key}
type={action.type}
danger={action.danger}
disabled={action.disabled}
icon={<PlusOutlined />}
onClick={() => action.onClick(selectedRowKeys, selectedRows)}
>
{action.label}
</Button>
);
}) || [];
// return [
// <Button
// key="button"
// icon={<PlusOutlined />}
// onClick={}
// type="primary"
// >
// 新建
// </Button>,
// ];
return toolbarElements;
},
[toolbarActions]
);
return (
<ProTable<T, U>
{...restProps}
columns={enhancedColumns}
actionRef={actionRef}
columns={columns}
actionRef={ref}
request={request}
rowKey="id"
rowSelection={rowSelection}
toolBarRender={toolBarRender}
manualRequest={false}
showSorterTooltip
tableAlertRender={tableAlertRender}
tableAlertOptionRender={tableAlertOptionRender}
// tableAlertOptionRender={tableAlertOptionRender}
scroll={{ x: "max-content" }}
search={{
labelWidth: "auto",
defaultCollapsed: false,
...restProps.search,
}}
options={{
@@ -291,4 +163,9 @@ function EnhancedProTable<T extends BaseRecord, U extends ParamsType = any>(
);
}
export default EnhancedProTable;
export default forwardRef(EnhancedProTable) as <
T extends BaseRecord,
U extends ParamsType = any
>(
props: EnhancedProTableProps<T, U> & { ref?: React.Ref<ActionType> }
) => React.ReactElement;