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,116 +0,0 @@
// hooks/useEnhancedTable.ts
import { useRef, useState, useCallback } from "react";
import { ActionType } from "@ant-design/pro-components";
import { message } from "antd";
import {
UseEnhancedTableOptions,
UseEnhancedTableReturn,
} from "@/components/EnhancedProTable/types";
export function useEnhancedTable<T>(
options: UseEnhancedTableOptions<T> = {}
): UseEnhancedTableReturn<T> {
const actionRef = useRef<ActionType>(undefined);
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const [selectedRows, setSelectedRows] = useState<T[]>([]);
const [loading, setLoading] = useState(false);
const { onAdd, onEdit, onDelete, onView, onExport, onBatchDelete } = options;
// 刷新表格
const reload = useCallback(() => {
actionRef.current?.reload();
}, []);
// 重置表格
const reset = useCallback(() => {
actionRef.current?.reset?.();
setSelectedRowKeys([]);
setSelectedRows([]);
}, []);
// 清空选择
const clearSelection = useCallback(() => {
setSelectedRowKeys([]);
setSelectedRows([]);
}, []);
// 处理删除
const handleDelete = useCallback(
async (record: T) => {
if (!onDelete) return;
setLoading(true);
try {
const success = await onDelete(record);
if (success) {
message.success("删除成功");
reload();
}
} finally {
setLoading(false);
}
},
[onDelete, reload]
);
// 处理批量删除
const handleBatchDelete = useCallback(
async (keys: React.Key[]) => {
if (!onBatchDelete || keys.length === 0) return;
setLoading(true);
try {
const success = await onBatchDelete(keys);
if (success) {
message.success("批量删除成功");
clearSelection();
reload();
}
} catch (error) {
message.error("批量删除失败");
} finally {
setLoading(false);
}
},
[onBatchDelete, clearSelection, reload]
);
// 处理导出
const handleExport = useCallback(
(rows: T[]) => {
if (!onExport) return;
if (rows.length === 0) {
message.warning("请选择要导出的数据");
return;
}
onExport(rows);
},
[onExport]
);
return {
actionRef,
selectedRowKeys,
selectedRows,
loading,
setSelectedRowKeys,
setSelectedRows,
reload,
reset,
clearSelection,
handleDelete,
handleBatchDelete,
handleExport,
actions: {
add: onAdd,
edit: onEdit,
delete: handleDelete,
view: onView,
export: handleExport,
batchDelete: handleBatchDelete,
},
};
}
export type { UseEnhancedTableOptions, UseEnhancedTableReturn };

131
src/hooks/antd/useModal.ts Normal file
View File

@@ -0,0 +1,131 @@
import { App } from "antd";
import { useCallback } from "react";
export interface ConfirmOptions {
title: string;
content?: string;
okText?: string;
cancelText?: string;
onOk?: () => Promise<void> | void;
onCancel?: () => void;
type?: "confirm" | "info" | "success" | "error" | "warning";
}
export const useModal = () => {
const { modal, message } = App.useApp();
// 通用确认对话框
const showConfirm = useCallback(
(options: ConfirmOptions) => {
const {
title,
content,
okText = "确定",
cancelText = "取消",
onOk,
onCancel,
type = "confirm",
} = options;
const modalMethod = modal[type];
return modalMethod({
title,
content,
okText,
cancelText,
onOk,
onCancel,
});
},
[modal]
);
// 删除确认对话框
const showDeleteConfirm = useCallback(
(
onConfirm: () => Promise<void> | void,
title: string = "删除确认",
content: string = "确定要删除吗?此操作不可恢复。"
) => {
return modal.confirm({
title,
content,
okText: "删除",
cancelText: "取消",
okType: "danger",
onOk: async () => {
try {
await onConfirm();
message.success("删除成功");
} catch (error) {
message.error("删除失败");
throw error;
}
},
});
},
[modal, message]
);
// 编辑确认对话框
const showEditConfirm = useCallback(
(
onConfirm: () => Promise<void> | void,
title: string = "编辑确认",
content: string = "确定要保存修改吗?"
) => {
return modal.confirm({
title,
content,
okText: "保存",
cancelText: "取消",
onOk: async () => {
try {
await onConfirm();
message.success("保存成功");
} catch (error) {
message.error("保存失败");
throw error;
}
},
});
},
[modal, message]
);
// 状态切换确认对话框
const showStatusConfirm = useCallback(
(
onConfirm: () => Promise<void> | void,
action: string,
itemName: string = "该项"
) => {
return modal.confirm({
title: `${action}确认`,
content: `确定要${action}${itemName}吗?`,
okText: action,
cancelText: "取消",
onOk: async () => {
try {
await onConfirm();
message.success(`${action}成功`);
} catch (error) {
message.error(`${action}失败`);
throw error;
}
},
});
},
[modal, message]
);
return {
modal,
message,
showConfirm,
showDeleteConfirm,
showEditConfirm,
showStatusConfirm,
};
};

View File

@@ -0,0 +1,51 @@
// hooks/useRequest.ts
import { useState, useCallback } from "react";
import { message } from "antd";
export interface UseRequestOptions<T> {
onSuccess?: (data: T) => void;
onError?: (error: any) => void;
showErrorMessage?: boolean;
}
export function useRequest<T = any, P = any>(
requestFn: (params: P) => Promise<T>,
options: UseRequestOptions<T> = {}
) {
const [loading, setLoading] = useState(false);
const [data, setData] = useState<T | null>(null);
const [error, setError] = useState<any>(null);
const { onSuccess, onError, showErrorMessage = true } = options;
const run = useCallback(
async (params: P) => {
setLoading(true);
setError(null);
try {
const result = await requestFn(params);
setData(result);
onSuccess?.(result);
return result;
} catch (err) {
setError(err);
onError?.(err);
if (showErrorMessage) {
message.error("请求失败");
}
throw err;
} finally {
setLoading(false);
}
},
[requestFn, onSuccess, onError, showErrorMessage]
);
return {
loading,
data,
error,
run,
};
}