1+ import { getLocalStorageData , setLocalStorageData } from "../delegate/localStorageDelegate" ;
2+ import { getAllProblems } from "../service/problemService" ;
3+ import { renderScheduledTableContent } from "../view/view" ;
4+ import { store } from "../store" ;
5+
6+ // 获取所有笔记
7+ const getAllNotes = async ( ) => {
8+ try {
9+ const notes = await getLocalStorageData ( "notes" ) ;
10+ return notes || { } ;
11+ } catch ( e ) {
12+ console . error ( "获取笔记数据失败" , e ) ;
13+ return { } ; // 返回空对象而不是抛出错误
14+ }
15+ } ;
16+
17+ // 同步笔记到存储
18+ const syncNotes = async ( notes ) => {
19+ if ( ! notes ) {
20+ notes = await getAllNotes ( ) ;
21+ }
22+ await setLocalStorageData ( "notes" , notes ) ;
23+ return notes ;
24+ } ;
25+
26+ // 注册笔记相关事件处理
27+ export const setNoteHandlers = ( ) => {
28+ console . log ( "注册笔记处理程序" ) ;
29+
30+ // 使用事件委托来处理笔记按钮点击
31+ document . removeEventListener ( 'click' , handleNoteButtonClick ) ; // 先移除之前的监听器,避免重复
32+ document . addEventListener ( 'click' , handleNoteButtonClick ) ;
33+
34+ // 注册保存笔记按钮事件
35+ const saveNoteBtn = document . getElementById ( 'saveNoteBtn' ) ;
36+ if ( saveNoteBtn ) {
37+ console . log ( "找到保存按钮" ) ;
38+ saveNoteBtn . addEventListener ( 'click' , saveNote ) ;
39+ } else {
40+ console . error ( "找不到保存按钮" ) ;
41+ }
42+
43+ // 注册取消按钮事件
44+ const cancelBtns = document . querySelectorAll ( '[data-bs-dismiss="modal"]' ) ;
45+ if ( cancelBtns . length > 0 ) {
46+ console . log ( "找到取消按钮" ) ;
47+ cancelBtns . forEach ( btn => {
48+ btn . addEventListener ( 'click' , ( ) => {
49+ // 关闭模态框
50+ const noteModal = document . getElementById ( 'noteModal' ) ;
51+ if ( noteModal ) {
52+ noteModal . style . display = 'none' ;
53+ noteModal . classList . remove ( 'show' ) ;
54+ }
55+ } ) ;
56+ } ) ;
57+ } else {
58+ console . error ( "找不到取消按钮" ) ;
59+ }
60+
61+ // 注册导出笔记按钮事件
62+ const exportNotesBtn = document . getElementById ( 'exportNotesBtn' ) ;
63+ if ( exportNotesBtn ) {
64+ console . log ( "找到导出按钮" ) ;
65+ exportNotesBtn . addEventListener ( 'click' , exportAllNotes ) ;
66+ } else {
67+ console . error ( "找不到导出按钮" ) ;
68+ }
69+
70+ // 初始化工具提示
71+ const tooltipTriggerList = [ ] . slice . call ( document . querySelectorAll ( '[data-bs-toggle="tooltip"]' ) ) ;
72+ tooltipTriggerList . map ( function ( tooltipTriggerEl ) {
73+ return new bootstrap . Tooltip ( tooltipTriggerEl ) ;
74+ } ) ;
75+ }
76+
77+ // 单独定义处理函数,便于移除
78+ const handleNoteButtonClick = ( e ) => {
79+ const noteButton = e . target . closest ( '.note-btn-mark' ) ;
80+ if ( noteButton ) {
81+ console . log ( "点击了笔记按钮" , noteButton ) ;
82+ console . log ( "按钮元素:" , noteButton ) ;
83+ console . log ( "data-id属性:" , noteButton . getAttribute ( 'data-id' ) ) ;
84+
85+ const problemIndex = noteButton . getAttribute ( 'data-id' ) ;
86+ if ( problemIndex ) {
87+ openNoteModal ( problemIndex ) ;
88+ } else {
89+ console . error ( "笔记按钮没有 data-id 属性" ) ;
90+ }
91+ }
92+ } ;
93+
94+ // 打开笔记模态框
95+ const openNoteModal = async ( problemIndex ) => {
96+ try {
97+ console . log ( "打开笔记模态框,问题索引:" , problemIndex ) ;
98+
99+ // 使用 getAllProblems 获取问题数据
100+ const problems = await getAllProblems ( ) ;
101+ const problem = problems [ problemIndex ] ;
102+
103+ // 如果没有找到问题数据
104+ if ( ! problem ) {
105+ console . error ( "找不到问题数据:" , problemIndex ) ;
106+ return ;
107+ }
108+
109+ // 获取笔记数据
110+ const notes = await getAllNotes ( ) ;
111+ const noteData = notes [ problemIndex ] ;
112+
113+ console . log ( "问题数据:" , problem ) ;
114+
115+ // 使用自定义方式打开模态框
116+ const noteModal = document . getElementById ( 'noteModal' ) ;
117+ if ( ! noteModal ) {
118+ console . error ( "找不到模态框元素" ) ;
119+ return ;
120+ }
121+
122+ // 显示模态框
123+ noteModal . style . display = 'block' ;
124+ noteModal . classList . add ( 'show' ) ;
125+
126+ // 设置问题索引到隐藏字段
127+ const problemIndexInput = document . getElementById ( 'problemIndex' ) ;
128+ if ( problemIndexInput ) {
129+ problemIndexInput . value = problemIndex ;
130+ } else {
131+ console . error ( "找不到问题索引输入框" ) ;
132+ }
133+
134+ // 设置问题名称 - 使用 innerHTML 直接设置
135+ const problemNameContainer = document . querySelector ( '.modal-body .mb-3:first-of-type' ) ;
136+ if ( problemNameContainer ) {
137+ // 如果有自定义名称,优先使用自定义名称
138+ const customName = noteData && typeof noteData === 'object' ? noteData . customName : undefined ;
139+ const problemName = customName || problem . name || "未知问题" ;
140+
141+ problemNameContainer . innerHTML = `
142+ <label for="noteProblemName" class="form-label">问题名称 (Problem Name)</label>
143+ <input type="text" class="form-control" id="noteProblemName" value="${ problemName } " placeholder="${ problem . name || '未知问题' } " style="color: #000 !important; background-color: #fff !important;">
144+ ` ;
145+ console . log ( "重新创建了问题名称输入框,值为:" , problemName ) ;
146+ } else {
147+ console . error ( "找不到问题名称容器" ) ;
148+ }
149+
150+ // 设置笔记内容
151+ const noteContentTextarea = document . getElementById ( 'noteContent' ) ;
152+ if ( noteContentTextarea ) {
153+ noteContentTextarea . value = noteData ? ( typeof noteData === 'object' ? noteData . content : noteData ) : '' ;
154+ } else {
155+ console . error ( "找不到笔记内容文本框" ) ;
156+ }
157+
158+ // 设置焦点到文本区域
159+ setTimeout ( ( ) => {
160+ if ( document . getElementById ( 'noteContent' ) ) {
161+ document . getElementById ( 'noteContent' ) . focus ( ) ;
162+ }
163+ } , 100 ) ;
164+ } catch ( e ) {
165+ console . error ( "打开笔记模态框失败" , e ) ;
166+ alert ( "打开笔记失败,请查看控制台获取详细错误信息" ) ;
167+ }
168+ }
169+
170+ // 保存笔记
171+ const saveNote = async ( ) => {
172+ try {
173+ const problemIndex = document . getElementById ( 'problemIndex' ) . value ;
174+ const problemNameInput = document . getElementById ( 'noteProblemName' ) ;
175+ const noteContent = document . getElementById ( 'noteContent' ) . value ;
176+
177+ // 获取用户输入的问题名称,如果输入框为空则使用占位符
178+ let problemName = "" ;
179+ if ( problemNameInput ) {
180+ problemName = problemNameInput . value . trim ( ) || problemNameInput . getAttribute ( 'placeholder' ) || "" ;
181+ }
182+
183+ console . log ( "保存笔记,问题索引:" , problemIndex ) ;
184+ console . log ( "保存笔记,问题名称:" , problemName ) ;
185+
186+ const notes = await getAllNotes ( ) ;
187+
188+ // 使用 getAllProblems 获取问题数据
189+ const problems = await getAllProblems ( ) ;
190+ const problem = problems [ problemIndex ] ;
191+
192+ if ( ! problem ) {
193+ console . error ( "找不到问题数据:" , problemIndex ) ;
194+ return ;
195+ }
196+
197+ console . log ( "原问题名称:" , problem . name ) ;
198+
199+ // 如果笔记为空,则删除该条目
200+ if ( noteContent . trim ( ) === '' ) {
201+ delete notes [ problemIndex ] ;
202+ } else {
203+ // 保存笔记内容和用户输入的问题名称
204+ notes [ problemIndex ] = {
205+ content : noteContent ,
206+ customName : problemName !== problem . name ? problemName : undefined
207+ } ;
208+ }
209+
210+ // 保存到本地存储
211+ await syncNotes ( notes ) ;
212+
213+ // 清除焦点
214+ document . activeElement ?. blur ( ) ;
215+
216+ // 关闭模态框
217+ const noteModal = document . getElementById ( 'noteModal' ) ;
218+ noteModal . style . display = 'none' ;
219+ noteModal . classList . remove ( 'show' ) ;
220+
221+ // 获取最新的问题数据
222+ const allProblems = await getAllProblems ( ) ;
223+
224+ // 先销毁所有现有的工具提示
225+ const existingTooltips = document . querySelectorAll ( '[data-bs-toggle="tooltip"]' ) ;
226+ existingTooltips . forEach ( el => {
227+ const tooltip = bootstrap . Tooltip . getInstance ( el ) ;
228+ if ( tooltip ) {
229+ tooltip . dispose ( ) ;
230+ }
231+ } ) ;
232+
233+ // 刷新表格以更新笔记图标和问题名称
234+ await renderScheduledTableContent ( store . reviewScheduledProblems , store . scheduledPage ) ;
235+
236+ // 重新初始化工具提示
237+ setTimeout ( ( ) => {
238+ // 确保先销毁所有可能存在的工具提示实例
239+ const tooltipTriggerList = document . querySelectorAll ( '[data-bs-toggle="tooltip"]' ) ;
240+ tooltipTriggerList . forEach ( el => {
241+ // 创建新的工具提示实例
242+ new bootstrap . Tooltip ( el , {
243+ trigger : 'hover' , // 只在悬停时显示
244+ container : 'body' , // 将工具提示附加到 body
245+ boundary : 'window' // 确保工具提示不会超出窗口边界
246+ } ) ;
247+ } ) ;
248+
249+ // 重新注册事件监听器
250+ setNoteHandlers ( ) ;
251+ } , 200 ) ; // 增加延迟时间确保 DOM 完全更新
252+
253+ console . log ( "笔记已保存" ) ;
254+ } catch ( e ) {
255+ console . error ( "保存笔记失败" , e ) ;
256+ alert ( "保存笔记失败,请查看控制台获取详细错误信息" ) ;
257+ }
258+ }
259+
260+ // 导出所有笔记
261+ const exportAllNotes = async ( ) => {
262+ try {
263+ // 使用 getAllProblems 获取问题数据
264+ const problems = await getAllProblems ( ) ;
265+ const notes = await getAllNotes ( ) ;
266+ let notesContent = "# LeetCode Mastery Scheduler notes\n\n" ;
267+ notesContent += "开源仓库链接/repo url: https://github.com/xiaohajiayou/Leetcode-Mastery-Scheduler" + "\n\n" ;
268+
269+ // 筛选有笔记的问题
270+ const problemIndicesWithNotes = Object . keys ( notes ) . filter ( index =>
271+ problems [ index ] && ! problems [ index ] . isDeleted &&
272+ ( typeof notes [ index ] === 'string' ? notes [ index ] . trim ( ) . length > 0 :
273+ ( notes [ index ] . content && notes [ index ] . content . trim ( ) . length > 0 ) )
274+ ) ;
275+
276+ if ( problemIndicesWithNotes . length === 0 ) {
277+ alert ( "没有找到任何笔记!" ) ;
278+ return ;
279+ }
280+
281+ // 按问题名称排序
282+ problemIndicesWithNotes . sort ( ( a , b ) =>
283+ ( problems [ a ] . name || "" ) . localeCompare ( problems [ b ] . name || "" )
284+ ) ;
285+
286+ // 生成markdown格式的笔记内容
287+ problemIndicesWithNotes . forEach ( index => {
288+ const problem = problems [ index ] ;
289+ const noteData = notes [ index ] ;
290+ const noteContent = typeof noteData === 'string' ? noteData : noteData . content ;
291+ const problemName = ( typeof noteData === 'object' && noteData . customName ) || problem . name || "未命名问题" ;
292+
293+ notesContent += `## ${ problemName } \n\n` ;
294+ notesContent += `- 难度: ${ problem . level || '未知' } \n` ;
295+ notesContent += `- 链接: ${ problem . url || '#' } \n\n` ;
296+ notesContent += `### 笔记\n\n${ noteContent } \n\n---\n\n` ;
297+ } ) ;
298+
299+ // 创建下载链接
300+ const blob = new Blob ( [ notesContent ] , { type : 'text/markdown' } ) ;
301+ const url = URL . createObjectURL ( blob ) ;
302+ const a = document . createElement ( 'a' ) ;
303+ a . href = url ;
304+ a . download = `leetcode_notes_${ new Date ( ) . toISOString ( ) . slice ( 0 , 10 ) } .md` ;
305+ document . body . appendChild ( a ) ;
306+ a . click ( ) ;
307+ document . body . removeChild ( a ) ;
308+ URL . revokeObjectURL ( url ) ;
309+
310+ console . log ( "笔记已导出" ) ;
311+ } catch ( e ) {
312+ console . error ( "导出笔记失败" , e ) ;
313+ alert ( "导出笔记失败,请查看控制台获取详细错误信息" ) ;
314+ }
315+ }
0 commit comments