@@ -11,17 +11,24 @@ import {
1111 Table ,
1212 Checkbox ,
1313 Input ,
14- Tag
14+ Tag ,
15+ Dropdown ,
16+ MenuProps
1517} from 'antd'
1618import {
1719 DownloadOutlined ,
1820 UploadOutlined ,
1921 DeleteOutlined ,
2022 ExclamationCircleOutlined ,
21- SelectOutlined
23+ SelectOutlined ,
24+ SettingOutlined ,
25+ MessageOutlined ,
26+ StarOutlined ,
27+ MoreOutlined
2228} from '@ant-design/icons'
2329import { useSettingsStore } from '../../stores/settingsStore'
2430import { usePagesStore } from '../../stores/pagesStore'
31+ import { useFavoritesStore } from '../../stores/favoritesStore'
2532import { clearAllStores } from '../../stores/useAppStores'
2633import { clearStoreState } from '../../stores/persistence/storeConfig'
2734import { useMessagesStore } from '../../stores/messagesStore'
@@ -38,7 +45,8 @@ const { Text, Paragraph } = Typography
3845
3946export default function DataManagement ( ) {
4047 const { importSettings, exportSettings } = useSettingsStore ( )
41- const { pages, folders, importPages, importFolders, clearAllPages } = usePagesStore ( )
48+ const { pages, folders, importPages, importFolders, clearAllPages, clearChatPages } = usePagesStore ( )
49+ const { items : favoriteItems , folders : favoriteFolders , importFavorites, importFavoriteFolders, clearAllFavorites } = useFavoritesStore ( )
4250 const [ importing , setImporting ] = useState ( false )
4351 const [ selectiveImportModal , setSelectiveImportModal ] = useState ( false )
4452 const [ selectableChatItems , setSelectableChatItems ] = useState < SelectableChatItem [ ] > ( [ ] )
@@ -61,6 +69,10 @@ export default function DataManagement() {
6169 settings,
6270 pages,
6371 folders,
72+ favorites : {
73+ items : favoriteItems ,
74+ folders : favoriteFolders
75+ } ,
6476 version : '1.0.0' ,
6577 exportTime : Date . now ( )
6678 }
@@ -129,6 +141,31 @@ export default function DataManagement() {
129141 }
130142 }
131143
144+ // 单独导出收藏
145+ const handleExportFavorites = ( ) => {
146+ try {
147+ const favoritesData = {
148+ type : 'favorites-only' ,
149+ items : favoriteItems ,
150+ folders : favoriteFolders ,
151+ version : '1.0.0' ,
152+ exportTime : Date . now ( )
153+ }
154+ const blob = new Blob ( [ JSON . stringify ( favoritesData , null , 2 ) ] , { type : 'application/json' } )
155+ const url = URL . createObjectURL ( blob )
156+ const link = document . createElement ( 'a' )
157+
158+ link . href = url
159+ link . download = `ai-chat-favorites-${ getTimestamp ( ) } .json`
160+ document . body . appendChild ( link )
161+ link . click ( )
162+ document . body . removeChild ( link )
163+ URL . revokeObjectURL ( url )
164+ } catch ( error ) {
165+ message . error ( '收藏导出失败' )
166+ }
167+ }
168+
132169 const handleImport = ( file : File ) => {
133170 setImporting ( true )
134171
@@ -151,7 +188,17 @@ export default function DataManagement() {
151188 importFolders ( parsedData . folders )
152189 }
153190
154- message . success ( '所有数据导入成功(包含设置和聊天历史)' )
191+ // 导入收藏数据
192+ if ( parsedData . favorites ) {
193+ if ( parsedData . favorites . items && parsedData . favorites . items . length > 0 ) {
194+ importFavorites ( parsedData . favorites . items )
195+ }
196+ if ( parsedData . favorites . folders && parsedData . favorites . folders . length > 0 ) {
197+ importFavoriteFolders ( parsedData . favorites . folders )
198+ }
199+ }
200+
201+ message . success ( '所有数据导入成功(包含设置、聊天历史和收藏)' )
155202 } else if ( parsedData . type === 'settings-only' ) {
156203 // 只有设置数据
157204 importSettings ( parsedData . settings )
@@ -167,6 +214,16 @@ export default function DataManagement() {
167214 }
168215
169216 message . success ( '聊天记录导入成功' )
217+ } else if ( parsedData . type === 'favorites-only' ) {
218+ // 只有收藏数据
219+ if ( parsedData . items && parsedData . items . length > 0 ) {
220+ importFavorites ( parsedData . items )
221+ }
222+ if ( parsedData . folders && parsedData . folders . length > 0 ) {
223+ importFavoriteFolders ( parsedData . folders )
224+ }
225+
226+ message . success ( '收藏数据导入成功' )
170227 } else if (
171228 parsedData . settings &&
172229 parsedData . pages !== undefined &&
@@ -352,7 +409,10 @@ export default function DataManagement() {
352409 // 第二步:清除 messagesStore 中的流式消息状态
353410 useMessagesStore . setState ( { streamingMessages : { } } )
354411
355- // 第三步:清除 IndexedDB 中的所有持久化数据
412+ // 第三步:清除收藏数据
413+ clearAllFavorites ( )
414+
415+ // 第四步:清除 IndexedDB 中的所有持久化数据
356416 await Promise . all ( [
357417 clearStoreState ( 'settings-store' ) ,
358418 clearStoreState ( 'messages-store' ) ,
@@ -361,7 +421,8 @@ export default function DataManagement() {
361421 clearStoreState ( 'ui-store' ) ,
362422 clearStoreState ( 'object-store' ) ,
363423 clearStoreState ( 'crosstab-store' ) ,
364- clearStoreState ( 'ai-tasks-store' )
424+ clearStoreState ( 'ai-tasks-store' ) ,
425+ clearStoreState ( 'favorites-store' )
365426 // pages 和 folders 已经在 clearAllPages() 中处理了
366427 ] )
367428
@@ -385,15 +446,14 @@ export default function DataManagement() {
385446 cancelText : '取消' ,
386447 onOk : async ( ) => {
387448 try {
388- // 清除聊天相关的存储
389- clearAllPages ( )
449+ // 清除聊天相关的存储(保留settings页面)
450+ clearChatPages ( )
390451
391- // 清除相关的持久化数据
452+ // 清除相关的持久化数据(仅清除与聊天记录直接相关的存储)
392453 await Promise . all ( [
393454 clearStoreState ( 'messages-store' ) ,
394- clearStoreState ( 'search-store' ) ,
395- clearStoreState ( 'tabs-store' ) ,
396- clearStoreState ( 'ui-store' )
455+ clearStoreState ( 'search-store' )
456+ // 注意:不清除 tabs-store 和 ui-store,因为它们包含settings页面状态
397457 ] )
398458
399459 // 重置消息存储的流式消息状态
@@ -436,6 +496,79 @@ export default function DataManagement() {
436496 } )
437497 }
438498
499+ // 单独清空收藏
500+ const handleResetFavorites = ( ) => {
501+ modal . confirm ( {
502+ title : '确认清空收藏' ,
503+ icon : < ExclamationCircleOutlined /> ,
504+ content : '这将清除所有收藏项和收藏文件夹,但保留您的设置和聊天记录。此操作不可恢复,确定要继续吗?' ,
505+ okText : '确定清空' ,
506+ okType : 'danger' ,
507+ cancelText : '取消' ,
508+ onOk : async ( ) => {
509+ try {
510+ // 清除收藏数据
511+ clearAllFavorites ( )
512+
513+ // 清除收藏相关的持久化数据
514+ await clearStoreState ( 'favorites-store' )
515+
516+ message . success ( '收藏已清空' )
517+ } catch ( error ) {
518+ console . error ( '清空收藏失败:' , error )
519+ message . error ( '清空收藏失败' )
520+ }
521+ }
522+ } )
523+ }
524+
525+ // 导出下拉菜单项(仅包含部分导出选项)
526+ const exportMenuItems : MenuProps [ 'items' ] = [
527+ {
528+ key : 'settings' ,
529+ label : '仅导出设置' ,
530+ icon : < SettingOutlined /> ,
531+ onClick : handleExportSettings
532+ } ,
533+ {
534+ key : 'chats' ,
535+ label : '仅导出聊天记录' ,
536+ icon : < MessageOutlined /> ,
537+ onClick : handleExportChats
538+ } ,
539+ {
540+ key : 'favorites' ,
541+ label : '仅导出收藏' ,
542+ icon : < StarOutlined /> ,
543+ onClick : handleExportFavorites
544+ }
545+ ]
546+
547+ // 重置下拉菜单项(仅包含部分重置选项)
548+ const resetMenuItems : MenuProps [ 'items' ] = [
549+ {
550+ key : 'settings' ,
551+ label : '仅清空设置' ,
552+ icon : < SettingOutlined /> ,
553+ onClick : handleResetSettings ,
554+ danger : true
555+ } ,
556+ {
557+ key : 'chats' ,
558+ label : '仅清空聊天记录' ,
559+ icon : < MessageOutlined /> ,
560+ onClick : handleResetChats ,
561+ danger : true
562+ } ,
563+ {
564+ key : 'favorites' ,
565+ label : '仅清空收藏' ,
566+ icon : < StarOutlined /> ,
567+ onClick : handleResetFavorites ,
568+ danger : true
569+ }
570+ ]
571+
439572 const getCurrentDataSize = ( ) => {
440573 try {
441574 const settings = exportSettings ( )
@@ -444,6 +577,10 @@ export default function DataManagement() {
444577 settings,
445578 pages,
446579 folders,
580+ favorites : {
581+ items : favoriteItems ,
582+ folders : favoriteFolders
583+ } ,
447584 version : '1.0.0' ,
448585 exportTime : Date . now ( )
449586 }
@@ -453,9 +590,17 @@ export default function DataManagement() {
453590 const chatsSize = (
454591 JSON . stringify ( { type : 'chats-only' , pages, folders, version : '1.0.0' } ) . length / 1024
455592 ) . toFixed ( 2 )
593+ const favoritesSize = (
594+ JSON . stringify ( {
595+ type : 'favorites-only' ,
596+ items : favoriteItems ,
597+ folders : favoriteFolders ,
598+ version : '1.0.0'
599+ } ) . length / 1024
600+ ) . toFixed ( 2 )
456601 const totalSize = ( JSON . stringify ( allData ) . length / 1024 ) . toFixed ( 2 )
457602
458- return `总计: ${ totalSize } KB (设置: ${ settingsSize } KB, 聊天: ${ chatsSize } KB)`
603+ return `总计: ${ totalSize } KB (设置: ${ settingsSize } KB, 聊天: ${ chatsSize } KB, 收藏: ${ favoritesSize } KB )`
459604 } catch {
460605 return '计算中...'
461606 }
@@ -483,16 +628,13 @@ export default function DataManagement() {
483628 < Button icon = { < DownloadOutlined /> } onClick = { handleExportAll } type = "primary" ghost >
484629 导出所有数据
485630 </ Button >
486- < Button icon = { < DownloadOutlined /> } onClick = { handleExportSettings } type = "default" >
487- 仅导出设置
488- </ Button >
489- < Button icon = { < DownloadOutlined /> } onClick = { handleExportChats } type = "default" >
490- 仅导出聊天记录
491- </ Button >
631+ < Dropdown menu = { { items : exportMenuItems } } placement = "bottomLeft" >
632+ < Button icon = { < MoreOutlined /> } type = "default" style = { { padding : '4px 8px' } } />
633+ </ Dropdown >
492634 </ Space >
493635 < div >
494636 < Text type = "secondary" style = { { fontSize : '12px' } } >
495- 您可以选择导出所有数据,或者分别导出设置和聊天记录
637+ 您可以选择导出所有数据,或者分别导出设置、聊天记录和收藏
496638 </ Text >
497639 </ div >
498640 </ div >
@@ -520,7 +662,7 @@ export default function DataManagement() {
520662 </ Upload >
521663 < div >
522664 < Text type = "secondary" style = { { fontSize : '12px' } } >
523- 支持导入完整数据文件、设置文件或聊天记录文件 ,系统会自动识别文件类型进行相应处理
665+ 支持导入完整数据文件、设置文件、聊天记录文件或收藏文件 ,系统会自动识别文件类型进行相应处理
524666 </ Text >
525667 </ div >
526668 </ div >
@@ -552,19 +694,16 @@ export default function DataManagement() {
552694 < Text strong > 重置数据</ Text >
553695 </ div >
554696 < Space direction = "horizontal" size = "small" wrap style = { { marginBottom : '4px' } } >
555- < Button icon = { < DeleteOutlined /> } danger type = "default" onClick = { handleResetAll } >
697+ < Button icon = { < DeleteOutlined /> } onClick = { handleResetAll } danger type = "default" >
556698 重置所有数据
557699 </ Button >
558- < Button icon = { < DeleteOutlined /> } danger type = "default" onClick = { handleResetSettings } >
559- 仅清空设置
560- </ Button >
561- < Button icon = { < DeleteOutlined /> } danger type = "default" onClick = { handleResetChats } >
562- 仅清空聊天记录
563- </ Button >
700+ < Dropdown menu = { { items : resetMenuItems } } placement = "bottomLeft" >
701+ < Button icon = { < MoreOutlined /> } danger type = "default" style = { { padding : '4px 8px' } } />
702+ </ Dropdown >
564703 </ Space >
565704 < div >
566705 < Text type = "secondary" style = { { fontSize : '12px' } } >
567- 您可以选择重置所有数据,或者分别清空聊天记录、重置设置配置
706+ 您可以选择重置所有数据,或者分别清空聊天记录、收藏或重置设置配置
568707 </ Text >
569708 </ div >
570709 </ div >
0 commit comments