1- import { Dropdown , Popconfirm , Button , Space } from "antd" ;
1+ import { Dropdown , Button , Space } from "antd" ;
22import { EllipsisOutlined } from "@ant-design/icons" ;
33import { useState } from "react" ;
44import { useTranslation } from "react-i18next" ;
5+ import DeleteConfirmModal from "./DeleteConfirmModal" ;
56
67interface ActionItem {
78 key : string ;
89 label : string ;
910 icon ?: React . ReactNode ;
1011 danger ?: boolean ;
12+ disabled ?: boolean ;
1113 confirm ?: {
12- title : string ;
13- description ?: string ;
14+ title ?: string ;
15+ message ?: string ;
16+ itemName ?: string | ( ( item : any ) => string ) ;
1417 okText ?: string ;
1518 cancelText ?: string ;
19+ okType ?: "default" | "primary" | "danger" ;
1620 } ;
21+ onClick ?: ( item ?: any ) => void | Promise < void > ;
1722}
1823
1924interface ActionDropdownProps {
2025 actions ?: ActionItem [ ] ;
21- onAction ?: ( key : string , action : ActionItem ) => void ;
26+ onAction ?: ( key : string , action : ActionItem , item ?: any ) => void ;
27+ item ?: any ;
2228 placement ?:
2329 | "bottomRight"
2430 | "topLeft"
@@ -33,86 +39,106 @@ interface ActionDropdownProps {
3339const ActionDropdown = ( {
3440 actions = [ ] ,
3541 onAction,
42+ item,
3643 placement = "bottomRight" ,
3744} : ActionDropdownProps ) => {
3845 const { t } = useTranslation ( ) ;
3946 const [ open , setOpen ] = useState ( false ) ;
40- const handleActionClick = ( action : ActionItem ) => {
47+ const [ deleteConfirm , setDeleteConfirm ] = useState < {
48+ visible : boolean ;
49+ action : ActionItem | null ;
50+ } > ( {
51+ visible : false ,
52+ action : null ,
53+ } ) ;
54+
55+ const handleActionClick = ( action : ActionItem , e : React . MouseEvent ) => {
56+ e ?. stopPropagation ( ) ;
57+
4158 if ( action . confirm ) {
42- // 如果有确认框,不立即执行,等待确认
59+ // 显示删除确认弹窗
60+ setDeleteConfirm ( {
61+ visible : true ,
62+ action,
63+ } ) ;
64+ setOpen ( false ) ;
4365 return ;
4466 }
67+
4568 // 执行操作
46- onAction ?.( action . key , action ) ;
47- // 如果没有确认框,则立即关闭 Dropdown
69+ if ( action . onClick ) {
70+ action . onClick ( item ) ;
71+ }
72+ onAction ?.( action . key , action , item ) ;
4873 setOpen ( false ) ;
4974 } ;
5075
76+ const handleConfirmDelete = async ( ) => {
77+ if ( deleteConfirm . action ?. onClick ) {
78+ await deleteConfirm . action . onClick ( item ) ;
79+ }
80+ if ( deleteConfirm . action ) {
81+ onAction ?.( deleteConfirm . action . key , deleteConfirm . action , item ) ;
82+ }
83+ setDeleteConfirm ( { visible : false , action : null } ) ;
84+ } ;
85+
86+ const handleCancelDelete = ( ) => {
87+ setDeleteConfirm ( { visible : false , action : null } ) ;
88+ } ;
89+
5190 const dropdownContent = (
5291 < div className = "bg-white p-2 rounded shadow-md" >
5392 < Space direction = "vertical" className = "w-full" >
54- { actions . map ( ( action ) => {
55- if ( action . confirm ) {
56- return (
57- < Popconfirm
58- key = { action . key }
59- title = { action . confirm . title }
60- description = { action . confirm . description }
61- onConfirm = { ( ) => {
62- onAction ?.( action . key , action ) ;
63- setOpen ( false ) ;
64- } }
65- okText = { action . confirm . okText || t ( 'components.actionDropdown.confirm' ) }
66- cancelText = { action . confirm . cancelText || t ( 'components.actionDropdown.cancel' ) }
67- okType = { action . danger ? "danger" : "primary" }
68- styles = { { root : { zIndex : 9999 } } }
69- >
70- < Button
71- type = "text"
72- size = "small"
73- disabled = { action . disabled || false }
74- className = "w-full text-left"
75- danger = { action . danger }
76- icon = { action . icon }
77- >
78- { action . label }
79- </ Button >
80- </ Popconfirm >
81- ) ;
82- }
83-
84- return (
85- < Button
86- key = { action . key }
87- className = "w-full"
88- size = "small"
89- type = "text"
90- disabled = { action . disabled || false }
91- danger = { action . danger }
92- icon = { action . icon }
93- onClick = { ( ) => handleActionClick ( action ) }
94- >
95- { action . label }
96- </ Button >
97- ) ;
98- } ) }
93+ { actions . map ( ( action ) => (
94+ < Button
95+ key = { action . key }
96+ className = "w-full"
97+ size = "small"
98+ type = "text"
99+ disabled = { action . disabled || false }
100+ danger = { action . danger }
101+ icon = { action . icon }
102+ onClick = { ( e ) => handleActionClick ( action , e ) }
103+ >
104+ { action . label }
105+ </ Button >
106+ ) ) }
99107 </ Space >
100108 </ div >
101109 ) ;
102110
103111 return (
104- < Dropdown
105- overlay = { dropdownContent }
106- trigger = { [ "click" ] }
107- placement = { placement }
108- open = { open }
109- onOpenChange = { setOpen }
110- >
111- < Button
112- type = "text"
113- icon = { < EllipsisOutlined style = { { fontSize : 24 } } /> }
114- />
115- </ Dropdown >
112+ < >
113+ < Dropdown
114+ menu = { { items : [ ] } }
115+ dropdownRender = { ( ) => dropdownContent }
116+ trigger = { [ "click" ] }
117+ placement = { placement }
118+ open = { open }
119+ onOpenChange = { setOpen }
120+ >
121+ < Button
122+ type = "text"
123+ icon = { < EllipsisOutlined style = { { fontSize : 24 } } /> }
124+ />
125+ </ Dropdown >
126+
127+ { deleteConfirm . action ?. confirm && (
128+ < DeleteConfirmModal
129+ visible = { deleteConfirm . visible }
130+ title = { deleteConfirm . action . confirm . title }
131+ message = { deleteConfirm . action . confirm . message }
132+ itemName = {
133+ typeof deleteConfirm . action . confirm . itemName === 'function'
134+ ? deleteConfirm . action . confirm . itemName ( item )
135+ : deleteConfirm . action . confirm . itemName
136+ }
137+ onConfirm = { handleConfirmDelete }
138+ onCancel = { handleCancelDelete }
139+ />
140+ ) }
141+ </ >
116142 ) ;
117143} ;
118144
0 commit comments