@@ -2,72 +2,9 @@ import { getDifficultyBasedSteps, getSubmissionResult, isSubmissionSuccess, isSu
22import { getAllProblems , createOrUpdateProblem , getCurrentProblemInfoFromLeetCodeByHref , getCurrentProblemInfoFromLeetCodeByUrl , syncProblems } from "../service/problemService" ;
33import { Problem } from "../entity/problem" ;
44import { updateProblemWithFSRS } from "../util/fsrs" ;
5- /*
6- monitorSubmissionResult will repeateadly check for the submission result.
7- */
8- const monitorSubmissionResult = ( ) => {
95
10- let submissionResult ;
11- let maxRetry = 10 ;
12- const retryInterval = 1000 ;
136
14- const functionId = setInterval ( async ( ) => {
157
16- if ( maxRetry <= 0 ) {
17- clearInterval ( functionId ) ;
18- return ;
19- }
20-
21- submissionResult = getSubmissionResult ( ) ;
22-
23- if ( submissionResult === undefined || submissionResult . length === 0 ) {
24- maxRetry -- ;
25- return ;
26- }
27-
28- clearInterval ( functionId ) ;
29- let isSuccess = isSubmissionSuccess ( submissionResult ) ;
30-
31- if ( ! isSuccess ) return ;
32-
33- const { problemIndex, problemName, problemLevel, problemUrl } = await getCurrentProblemInfoFromLeetCodeByHref ( ) ;
34- await syncProblems ( ) ; // prior to fetch local problem data, sync local problem data with cloud
35- const problems = await getAllProblems ( ) ;
36- let problem = problems [ problemIndex ] ;
37-
38- if ( problem && problem . isDeleted !== true ) {
39- const reviewNeeded = needReview ( problem ) ;
40- if ( reviewNeeded ) {
41- await createOrUpdateProblem ( updateProblemUponSuccessSubmission ( problem ) ) ;
42- }
43- } else {
44- problem = new Problem ( problemIndex , problemName , problemLevel , problemUrl , Date . now ( ) , getDifficultyBasedSteps ( problemLevel ) [ 0 ] , Date . now ( ) ) ;
45- await createOrUpdateProblem ( problem ) ;
46- }
47- await syncProblems ( ) ; // after problem updated, sync to cloud
48-
49- console . log ( "Submission successfully tracked!" ) ;
50-
51- } , retryInterval )
52- } ;
53-
54- export const submissionListener = ( event ) => {
55-
56- const element = event . target ;
57-
58- const filterConditions = [
59- isSubmitButton ( element ) ,
60- element . parentElement && isSubmitButton ( element . parentElement ) ,
61- element . parentElement && element . parentElement . parentElement && isSubmitButton ( element . parentElement . parentElement ) ,
62- ]
63-
64- const isSubmission = filterConditions . reduce ( ( prev , curr ) => prev || curr ) ;
65-
66- if ( isSubmission ) {
67- monitorSubmissionResult ( ) ;
68- }
69-
70- } ;
718
729
7310
@@ -258,26 +195,45 @@ export async function handleFeedbackSubmission(problem = null) {
258195 return null ;
259196 }
260197
261- // 如果没有传入 problem,说明是新提交 ,需要获取题目信息
198+ // 如果没有传入 problem,说明是页面提交 ,需要获取题目信息
262199 if ( ! problem ) {
263200 await syncProblems ( ) ; // 同步云端数据
264201 const { problemIndex, problemName, problemLevel, problemUrl } = await getCurrentProblemInfoFromLeetCodeByHref ( ) ;
265202 const problems = await getAllProblems ( ) ;
266203 problem = problems [ problemIndex ] ;
267204
268- if ( problem && problem . isDeleted !== true ) {
269- problem = updateProblemWithFSRS ( problem , feedback ) ;
270- await createOrUpdateProblem ( updateProblemUponSuccessSubmission ( problem ) ) ;
271- } else {
205+ if ( ! problem || problem . isDeleted == true ) {
272206 problem = new Problem ( problemIndex , problemName , problemLevel , problemUrl , Date . now ( ) , getDifficultyBasedSteps ( problemLevel ) [ 0 ] , Date . now ( ) ) ;
273- problem = updateProblemWithFSRS ( problem , feedback ) ;
274- await createOrUpdateProblem ( problem ) ;
275207 }
276- } else {
277- // 如果传入了 problem,说明是复习
278- problem = updateProblemWithFSRS ( problem , feedback ) ;
279- await createOrUpdateProblem ( problem ) ;
280208 }
209+
210+ // 检查上次复习时间是否是今天,如果是则不允许再次复习
211+ if ( problem . fsrsState && problem . fsrsState . lastReview ) {
212+ const lastReviewDate = new Date ( problem . fsrsState . lastReview ) ;
213+ const today = new Date ( ) ;
214+
215+ // 比较年、月、日是否相同(考虑时区影响)
216+ if ( lastReviewDate . getFullYear ( ) === today . getFullYear ( ) &&
217+ lastReviewDate . getMonth ( ) === today . getMonth ( ) &&
218+ lastReviewDate . getDate ( ) === today . getDate ( ) ) {
219+
220+ // 显示双语警告提示
221+ showToast ( "今天已经复习过这道题了,请明天再来!\nYou've already reviewed this problem today. Please come back tomorrow!" , "warning" ) ;
222+ return null ;
223+ }
224+ }
225+
226+ problem = updateProblemWithFSRS ( problem , feedback ) ;
227+ await createOrUpdateProblem ( problem ) ;
228+
229+ // 计算下次复习时间与今天的天数差
230+ const nextReviewDate = new Date ( problem . fsrsState . nextReview ) ;
231+ const today = new Date ( ) ;
232+ const diffTime = nextReviewDate . getTime ( ) - today . getTime ( ) ;
233+ const diffDays = Math . ceil ( diffTime / ( 1000 * 60 * 60 * 24 ) ) ;
234+
235+ // 显示复习成功提示,包含下次复习时间
236+ showToast ( `复习成功!下次复习时间:${ nextReviewDate . toLocaleDateString ( ) } (${ diffDays } 天后)\nReview successful! Next review: ${ nextReviewDate . toLocaleDateString ( ) } (in ${ diffDays } days)` , "success" ) ;
281237
282238 await syncProblems ( ) ; // 同步到云端
283239 console . log ( "提交成功!" ) ;
@@ -288,7 +244,109 @@ export async function handleFeedbackSubmission(problem = null) {
288244 }
289245}
290246
291-
247+ // 添加一个更醒目的提示框函数,支持不同类型的提示
248+ function showToast ( message , type = "info" , duration = 5000 ) {
249+ // 检查是否已存在toast样式
250+ if ( ! document . getElementById ( 'lms-toast-style' ) ) {
251+ const style = document . createElement ( 'style' ) ;
252+ style . id = 'lms-toast-style' ;
253+ style . textContent = `
254+ .lms-toast {
255+ position: fixed;
256+ top: 20px;
257+ left: 50%;
258+ transform: translateX(-50%);
259+ padding: 12px 24px;
260+ border-radius: 4px;
261+ z-index: 10000;
262+ font-size: 14px;
263+ box-shadow: 0 4px 12px rgba(0,0,0,0.15);
264+ animation: lms-toast-in 0.3s ease;
265+ max-width: 80%;
266+ text-align: center;
267+ white-space: pre-line;
268+ font-weight: 500;
269+ }
270+
271+ .lms-toast-info {
272+ background-color: #1890ff;
273+ color: white;
274+ border-left: 4px solid #096dd9;
275+ }
276+
277+ .lms-toast-success {
278+ background-color: #52c41a;
279+ color: white;
280+ border-left: 4px solid #389e0d;
281+ }
282+
283+ .lms-toast-warning {
284+ background-color: #ffd666;
285+ color: #874d00;
286+ border-left: 4px solid #faad14;
287+ font-weight: bold;
288+ }
289+
290+ .lms-toast-error {
291+ background-color: #ff4d4f;
292+ color: white;
293+ border-left: 4px solid #cf1322;
294+ font-weight: bold;
295+ }
296+
297+ @keyframes lms-toast-in {
298+ from {
299+ opacity: 0;
300+ transform: translate(-50%, -20px);
301+ }
302+ to {
303+ opacity: 1;
304+ transform: translate(-50%, 0);
305+ }
306+ }
307+
308+ .lms-toast-icon {
309+ margin-right: 8px;
310+ font-weight: bold;
311+ }
312+ ` ;
313+ document . head . appendChild ( style ) ;
314+ }
315+
316+ // 移除可能存在的旧提示
317+ const existingToast = document . querySelector ( '.lms-toast' ) ;
318+ if ( existingToast ) {
319+ existingToast . remove ( ) ;
320+ }
321+
322+ const toast = document . createElement ( 'div' ) ;
323+ toast . className = `lms-toast lms-toast-${ type } ` ;
324+
325+ // 添加图标
326+ let icon = '' ;
327+ switch ( type ) {
328+ case 'info' : icon = 'ℹ️' ; break ;
329+ case 'success' : icon = '✅' ; break ;
330+ case 'warning' : icon = '⚠️' ; break ;
331+ case 'error' : icon = '❌' ; break ;
332+ }
333+
334+ toast . innerHTML = `<span class="lms-toast-icon">${ icon } </span>${ message } ` ;
335+ document . body . appendChild ( toast ) ;
336+
337+ // 添加点击关闭功能
338+ toast . addEventListener ( 'click' , ( ) => {
339+ toast . style . opacity = '0' ;
340+ toast . style . transition = 'opacity 0.3s ease' ;
341+ setTimeout ( ( ) => toast . remove ( ) , 300 ) ;
342+ } ) ;
343+
344+ setTimeout ( ( ) => {
345+ toast . style . opacity = '0' ;
346+ toast . style . transition = 'opacity 0.3s ease' ;
347+ setTimeout ( ( ) => toast . remove ( ) , 300 ) ;
348+ } , duration ) ;
349+ }
292350
293351// 6. 显示评分对话框
294352const showDifficultyFeedbackDialog = ( ) => {
0 commit comments