@@ -4,27 +4,29 @@ import FileUpload from './FileUpload';
44import CopyButton from './CopyButton' ;
55import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter' ;
66import { materialLight } from 'react-syntax-highlighter/dist/esm/styles/prism' ;
7- import { Box , Dialog , DialogContent , DialogTitle , IconButton , TextField , Typography } from '@mui/material' ;
7+ import { Box , Dialog , DialogContent , DialogTitle , IconButton , TextField , Typography , Button , Tooltip } from '@mui/material' ;
88import CloseIcon from '@mui/icons-material/Close' ;
99import DeleteIcon from '@mui/icons-material/Delete' ;
1010import DeleteForever from '@mui/icons-material/DeleteForever' ;
11+ import HistoryIcon from '@mui/icons-material/History' ;
12+ import FilterListIcon from '@mui/icons-material/FilterList' ;
13+ import SaveIcon from '@mui/icons-material/Save' ;
1114import './styles.css' ;
12-
13- interface FileInfo {
14- name : string ;
15- path : string ;
16- size : number ;
17- extension : string ;
18- content : string ;
19- }
15+ import { FileInfo } from '../types/types' ;
16+ import { HistoryRecord , FileFilter , DEFAULT_FILE_FILTER } from '../types/history' ;
17+ import { historyDB } from '../utils/indexedDB' ;
18+ import { applyFileFilter , getFilterStats } from '../utils/fileFilter' ;
19+ import HistoryPanel from '../components/HistoryPanel' ;
20+ import FileFilterComponent from '../components/FileFilter' ;
2021
2122interface MarkdownEditorProps {
2223 ruleContent : string ;
2324 roleContent : string ;
2425 outputContent : string ;
26+ onLoadFromHistory ?: ( record : HistoryRecord ) => void ;
2527}
2628
27- const MarkdownEditor : React . FC < MarkdownEditorProps > = ( { ruleContent, roleContent, outputContent} ) => {
29+ const MarkdownEditor : React . FC < MarkdownEditorProps > = ( { ruleContent, roleContent, outputContent, onLoadFromHistory } ) => {
2830 const [ markdownContent , setMarkdownContent ] = useState ( ( ) => {
2931 const saved = localStorage . getItem ( 'markdownContent' ) ;
3032 return saved || '' ;
@@ -37,6 +39,29 @@ const MarkdownEditor: React.FC<MarkdownEditorProps> = ({ruleContent, roleContent
3739 const [ isDialogOpen , setIsDialogOpen ] = useState ( false ) ;
3840 const previewContentRef = useRef < HTMLDivElement > ( null ) ;
3941
42+ // 新增状态
43+ const [ historyPanelOpen , setHistoryPanelOpen ] = useState ( false ) ;
44+ const [ fileFilterOpen , setFileFilterOpen ] = useState ( false ) ;
45+ const [ fileFilter , setFileFilter ] = useState < FileFilter > ( ( ) => {
46+ const saved = localStorage . getItem ( 'fileFilter' ) ;
47+ return saved ? JSON . parse ( saved ) : DEFAULT_FILE_FILTER ;
48+ } ) ;
49+ const [ originalFiles , setOriginalFiles ] = useState < FileInfo [ ] > ( [ ] ) ;
50+ const [ isDBInitialized , setIsDBInitialized ] = useState ( false ) ;
51+
52+ // 初始化IndexedDB
53+ useEffect ( ( ) => {
54+ const initDB = async ( ) => {
55+ try {
56+ await historyDB . init ( ) ;
57+ setIsDBInitialized ( true ) ;
58+ } catch ( error ) {
59+ console . error ( 'Failed to initialize IndexedDB:' , error ) ;
60+ }
61+ } ;
62+ initDB ( ) ;
63+ } , [ ] ) ;
64+
4065 // 持久化markdown内容
4166 useEffect ( ( ) => {
4267 const timer = setTimeout ( ( ) => {
@@ -64,9 +89,20 @@ const MarkdownEditor: React.FC<MarkdownEditorProps> = ({ruleContent, roleContent
6489 }
6590 } , [ previewFile ] ) ;
6691
92+ // 持久化文件过滤器设置
93+ useEffect ( ( ) => {
94+ localStorage . setItem ( 'fileFilter' , JSON . stringify ( fileFilter ) ) ;
95+ } , [ fileFilter ] ) ;
96+
6797 const handleFilesUploaded = ( newFiles : FileInfo [ ] ) => {
98+ // 保存原始文件
99+ setOriginalFiles ( newFiles ) ;
100+
101+ // 应用过滤器
102+ const filteredFiles = applyFileFilter ( newFiles , fileFilter ) ;
103+
68104 setFiles ( prev => {
69- const updatedFiles = [ ...prev , ...newFiles ] ;
105+ const updatedFiles = [ ...prev , ...filteredFiles ] ;
70106 // 去重逻辑
71107 const uniqueFiles = updatedFiles . reduce ( ( acc , current ) => {
72108 if ( ! acc . some ( file => file . path === current . path ) ) {
@@ -78,6 +114,52 @@ const MarkdownEditor: React.FC<MarkdownEditorProps> = ({ruleContent, roleContent
78114 } ) ;
79115 } ;
80116
117+ // 保存当前状态为历史记录
118+ const saveToHistory = async ( ) => {
119+ if ( ! isDBInitialized ) return ;
120+
121+ try {
122+ const record : HistoryRecord = {
123+ id : `history_${ Date . now ( ) } _${ Math . random ( ) . toString ( 36 ) . substr ( 2 , 9 ) } ` ,
124+ timestamp : Date . now ( ) ,
125+ title : `构造记录 ${ new Date ( ) . toLocaleString ( 'zh-CN' ) } ` ,
126+ description : '' ,
127+ roleContent,
128+ ruleContent,
129+ taskContent : markdownContent ,
130+ outputContent,
131+ files,
132+ tags : [ ] ,
133+ version : 1
134+ } ;
135+
136+ await historyDB . saveRecord ( record ) ;
137+ console . log ( 'History record saved successfully' ) ;
138+ } catch ( error ) {
139+ console . error ( 'Failed to save history record:' , error ) ;
140+ }
141+ } ;
142+
143+ // 从历史记录加载
144+ const loadFromHistory = ( record : HistoryRecord ) => {
145+ setMarkdownContent ( record . taskContent ) ;
146+ setFiles ( record . files ) ;
147+ // 通知父组件更新其他内容
148+ if ( onLoadFromHistory ) {
149+ onLoadFromHistory ( record ) ;
150+ }
151+ console . log ( 'Loaded from history:' , record . title ) ;
152+ } ;
153+
154+ // 应用文件过滤器
155+ const applyFilter = ( newFilter : FileFilter ) => {
156+ setFileFilter ( newFilter ) ;
157+ if ( originalFiles . length > 0 ) {
158+ const filteredFiles = applyFileFilter ( originalFiles , newFilter ) ;
159+ setFiles ( filteredFiles ) ;
160+ }
161+ } ;
162+
81163 const formatFileSize = ( bytes : number ) => {
82164 const units = [ 'B' , 'KB' , 'MB' , 'GB' ] ;
83165 let size = bytes ;
@@ -121,6 +203,49 @@ const MarkdownEditor: React.FC<MarkdownEditorProps> = ({ruleContent, roleContent
121203 < div className = "editor-container" >
122204 < FileUpload onFilesUploaded = { handleFilesUploaded } />
123205
206+ { /* 工具栏 */ }
207+ < Box display = "flex" gap = { 1 } mb = { 2 } flexWrap = "wrap" >
208+ < Tooltip title = "查看构造历史" >
209+ < Button
210+ startIcon = { < HistoryIcon /> }
211+ onClick = { ( ) => setHistoryPanelOpen ( true ) }
212+ variant = "outlined"
213+ size = "small"
214+ >
215+ 历史记录
216+ </ Button >
217+ </ Tooltip >
218+
219+ < Tooltip title = "设置文件过滤条件" >
220+ < Button
221+ startIcon = { < FilterListIcon /> }
222+ onClick = { ( ) => setFileFilterOpen ( true ) }
223+ variant = "outlined"
224+ size = "small"
225+ >
226+ 文件过滤
227+ </ Button >
228+ </ Tooltip >
229+
230+ < Tooltip title = "保存当前构造到历史记录" >
231+ < Button
232+ startIcon = { < SaveIcon /> }
233+ onClick = { saveToHistory }
234+ variant = "outlined"
235+ size = "small"
236+ disabled = { ! isDBInitialized }
237+ >
238+ 保存历史
239+ </ Button >
240+ </ Tooltip >
241+
242+ { originalFiles . length > 0 && originalFiles . length !== files . length && (
243+ < Typography variant = "caption" color = "text.secondary" sx = { { alignSelf : 'center' , ml : 1 } } >
244+ 已过滤 { originalFiles . length - files . length } 个文件
245+ </ Typography >
246+ ) }
247+ </ Box >
248+
124249 { files . length > 0 && (
125250 < div className = "file-list" >
126251 < Box display = "flex" justifyContent = "space-between" alignItems = "center" mb = { 1 } >
@@ -231,6 +356,21 @@ const MarkdownEditor: React.FC<MarkdownEditorProps> = ({ruleContent, roleContent
231356 files = { files }
232357 />
233358 </ div >
359+
360+ { /* 历史记录面板 */ }
361+ < HistoryPanel
362+ open = { historyPanelOpen }
363+ onClose = { ( ) => setHistoryPanelOpen ( false ) }
364+ onLoadRecord = { loadFromHistory }
365+ />
366+
367+ { /* 文件过滤对话框 */ }
368+ < FileFilterComponent
369+ open = { fileFilterOpen }
370+ onClose = { ( ) => setFileFilterOpen ( false ) }
371+ filter = { fileFilter }
372+ onFilterChange = { applyFilter }
373+ />
234374 </ div >
235375 ) ;
236376} ;
0 commit comments