@@ -38,8 +38,16 @@ export default function Sidebar({
3838 deleteMultiplePages
3939 } = usePagesStore ( )
4040 const { openTab } = useTabsStore ( )
41- const { selectedNodeType, selectedNodeId, checkedNodeIds, setSelectedNode, clearCheckedNodes } =
42- useUIStore ( )
41+ const {
42+ selectedNodeType,
43+ selectedNodeId,
44+ checkedNodeIds,
45+ isMultiSelectMode,
46+ setSelectedNode,
47+ clearCheckedNodes,
48+ enterMultiSelectMode,
49+ exitMultiSelectMode
50+ } = useUIStore ( )
4351 const { filterFolderId } = useSearchStore ( )
4452 const { modal } = App . useApp ( )
4553
@@ -106,8 +114,68 @@ export default function Sidebar({
106114
107115 // 批量删除选中的聊天
108116 const handleBatchDelete = useCallback ( ( ) => {
109- // TODO
110- } , [ checkedNodeIds , clearCheckedNodes , deleteMultiplePages ] )
117+ if ( checkedNodeIds . length === 0 ) return
118+
119+ // 解析选中的节点,分离聊天和文件夹
120+ const chatIds : string [ ] = [ ]
121+ const folderIds : string [ ] = [ ]
122+
123+ checkedNodeIds . forEach ( ( nodeKey ) => {
124+ if ( nodeKey . startsWith ( 'chat-' ) ) {
125+ chatIds . push ( nodeKey . replace ( 'chat-' , '' ) )
126+ } else if ( nodeKey . startsWith ( 'folder-' ) ) {
127+ folderIds . push ( nodeKey . replace ( 'folder-' , '' ) )
128+ }
129+ } )
130+
131+ const totalCount = chatIds . length + folderIds . length
132+ const description =
133+ folderIds . length > 0
134+ ? `确定要删除选中的 ${ totalCount } 项吗?包含 ${ chatIds . length } 个聊天和 ${ folderIds . length } 个文件夹。文件夹中的所有内容也将被删除。此操作无法撤销。`
135+ : `确定要删除选中的 ${ chatIds . length } 个聊天吗?此操作无法撤销。`
136+
137+ modal . confirm ( {
138+ title : '批量删除' ,
139+ content : description ,
140+ okText : '确定删除' ,
141+ cancelText : '取消' ,
142+ okType : 'danger' ,
143+ onOk ( ) {
144+ const { deleteFolder, deletePage } = usePagesStore . getState ( )
145+
146+ // 递归删除文件夹及其内容
147+ const deleteRecursive = ( folderId : string ) => {
148+ const currentState = usePagesStore . getState ( )
149+ // 删除该文件夹下的所有聊天
150+ const chatsToDelete = currentState . pages . filter (
151+ ( p ) => p . folderId === folderId && p . type !== 'settings'
152+ )
153+ chatsToDelete . forEach ( ( chat ) => deletePage ( chat . id ) )
154+
155+ // 递归删除子文件夹
156+ const subFolders = currentState . folders . filter ( ( f ) => f . parentId === folderId )
157+ subFolders . forEach ( ( subFolder ) => {
158+ deleteRecursive ( subFolder . id )
159+ deleteFolder ( subFolder . id )
160+ } )
161+ }
162+
163+ // 先删除文件夹(包含递归删除内容)
164+ folderIds . forEach ( ( folderId ) => {
165+ deleteRecursive ( folderId )
166+ deleteFolder ( folderId )
167+ } )
168+
169+ // 再删除独立的聊天
170+ if ( chatIds . length > 0 ) {
171+ deleteMultiplePages ( chatIds )
172+ }
173+
174+ // 清空选中状态并退出多选模式
175+ exitMultiSelectMode ( )
176+ }
177+ } )
178+ } , [ checkedNodeIds , deleteMultiplePages , exitMultiSelectMode , modal ] )
111179
112180 // 检查是否有选中的项目
113181 const hasCheckedItems = checkedNodeIds . length > 0
@@ -127,16 +195,21 @@ export default function Sidebar({
127195 < SidebarActions
128196 collapsed = { false }
129197 hasCheckedItems = { hasCheckedItems }
198+ isMultiSelectMode = { isMultiSelectMode }
130199 onCreateChat = { handleCreateChat }
131200 onCreateCrosstabChat = { handleCreateCrosstabChat }
132201 onCreateObjectChat = { handleCreateObjectChat }
133202 onCreateFolder = { handleCreateFolder }
134203 onBatchDelete = { handleBatchDelete }
204+ onEnterMultiSelectMode = { enterMultiSelectMode }
205+ onExitMultiSelectMode = { exitMultiSelectMode }
135206 />
136207 </ div >
137208 < div className = "sidebar-content" >
138- { hasCheckedItems && (
139- < div className = "multi-select-indicator" > 已选中 { checkedNodeIds . length } 项</ div >
209+ { isMultiSelectMode && (
210+ < div className = "multi-select-indicator" >
211+ { hasCheckedItems ? `已选中 ${ checkedNodeIds . length } 项` : '请勾选要操作的项目' }
212+ </ div >
140213 ) }
141214 < ChatHistoryTree onChatClick = { handleChatClick } onFindInFolder = { onFindInFolder } />
142215 </ div >
0 commit comments