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