@@ -67,7 +67,7 @@ const startNewIdiom = () => {
6767 answer .value = customMode .currentIdiom .value ! ;
6868 guesses .value = result ?.guesses || [];
6969 gameWon .value = result ?.won || false ;
70- gameFailed .value = result ?.completed && ! result .won ;
70+ gameFailed .value = ( result ?.completed && ! result .won ) || false ;
7171 elapsedTime .value = result ?.time || 0 ;
7272 if (result ?.time ) {
7373 const minutes = Math .floor (result .time / 60 );
@@ -80,7 +80,7 @@ const startNewIdiom = () => {
8080 startTime .value = 0 ;
8181 return ;
8282 }
83-
83+
8484 if (! customMode .nextIdiom ()) {
8585 showCongrats .value = true ;
8686 return ;
@@ -136,12 +136,12 @@ const handleJumpTo = (index: number) => {
136136 if (customMode .isActive .value && customMode .viewIndex .value === customMode .currentIndex .value && guesses .value .length > 0 && ! gameWon .value && ! gameFailed .value ) {
137137 customMode .saveCurrentProgress (guesses .value );
138138 }
139-
139+
140140 customMode .jumpToIdiom (index );
141141 const result = customMode .results .value [index ];
142142 answer .value = customMode .currentIdiom .value ! ;
143143 guesses .value = result ?.guesses || [];
144-
144+
145145 // 正确判断游戏状态
146146 if (result ?.completed ) {
147147 gameWon .value = result .won ;
@@ -150,7 +150,7 @@ const handleJumpTo = (index: number) => {
150150 gameWon .value = false ;
151151 gameFailed .value = false ;
152152 }
153-
153+
154154 elapsedTime .value = result ?.time || 0 ;
155155 if (result ?.time ) {
156156 const minutes = Math .floor (result .time / 60 );
@@ -191,13 +191,13 @@ const initGame = async () => {
191191 const hex = b .toString (16 );
192192 return hex .length === 1 ? ' 0' + hex : hex ;
193193 }).join (' ' ).slice (0 , 16 );
194-
194+
195195 await customMode .init (idiomsList , quizId );
196196 const currentResult = customMode .results .value [customMode .currentIndex .value ];
197197 answer .value = customMode .currentIdiom .value ! ;
198198 guesses .value = currentResult ?.guesses || [];
199199 gameWon .value = currentResult ?.won || false ;
200- gameFailed .value = currentResult ?.completed && ! currentResult .won ;
200+ gameFailed .value = ( currentResult ?.completed && ! currentResult .won ) || false ;
201201 elapsedTime .value = currentResult ?.time || 0 ;
202202 if (currentResult ?.time ) {
203203 const minutes = Math .floor (currentResult .time / 60 );
@@ -343,7 +343,7 @@ const handleSubmit = () => {
343343 }
344344
345345 guesses .value .push (currentInput .value );
346-
346+
347347 // 自定义模式下每次提交都保存进度(不改变完成状态)
348348 if (customMode .isActive .value ) {
349349 customMode .saveCurrentProgress (guesses .value );
@@ -414,6 +414,22 @@ const closeCreateQuiz = () => {
414414 showCreateQuiz .value = false ;
415415};
416416
417+ const isAllCompleted = computed (() => {
418+ if (! customMode .isActive .value ) return false ;
419+ return customMode .results .value .every (r => r .completed );
420+ });
421+
422+ const totalStats = computed (() => {
423+ if (! customMode .isActive .value ) return { totalAttempts: 0 , totalTime: 0 };
424+ const totalAttempts = customMode .results .value .reduce ((sum , r ) => sum + r .guesses .length , 0 );
425+ const totalTime = customMode .results .value .reduce ((sum , r ) => sum + r .time , 0 );
426+ return { totalAttempts , totalTime };
427+ });
428+
429+ const showCompletionDialog = () => {
430+ showCongrats .value = true ;
431+ };
432+
417433 </script >
418434
419435<template >
@@ -432,7 +448,8 @@ const closeCreateQuiz = () => {
432448 <div v-else-if =" guessedList.length > 0" class =" progress" >(你已完成 {{ guessedList.length }} 题)</div >
433449
434450 <ProgressNav v-if =" customMode .isActive .value " :results =" customMode .results .value "
435- :currentIndex =" customMode .currentIndex .value " :viewIndex =" customMode .viewIndex .value " @jumpTo =" handleJumpTo " />
451+ :currentIndex =" customMode .currentIndex .value " :viewIndex =" customMode .viewIndex .value "
452+ @jumpTo =" handleJumpTo " />
436453
437454 <div class =" guesses" >
438455 <div v-for =" (guess, guessIndex) in guessesWithPinyin" :key =" guessIndex" class =" guess-row" >
@@ -453,25 +470,54 @@ const closeCreateQuiz = () => {
453470 <div class =" congrats-icon" >🎉</div >
454471 <h2 v-if =" customMode.isActive.value" >恭喜完成所有自定义题目!</h2 >
455472 <h2 v-else >恭喜你完成了所有挑战!</h2 >
473+
474+ <div v-if =" customMode.isActive.value" class =" results-summary" >
475+ <div v-for =" (result, index) in customMode.results.value" :key =" index" class =" result-item" >
476+ <div class =" result-header" >
477+ <span class =" result-number" >第{{ index + 1 }}题</span >
478+ <span class =" result-idiom" >{{ result.idiom }}</span >
479+ <span :class =" ['result-status', result.won ? 'success' : 'failed']" >
480+ {{ result.won ? '✅' : '❌' }}
481+ </span >
482+ </div >
483+ <div class =" result-details" >
484+ <span >尝试次数:{{ result.guesses.length }}</span >
485+ <span >用时:{{ Math.floor(result.time / 60) > 0 ? `${Math.floor(result.time /
486+ 60)}分${result.time % 60}秒` : `${result.time}秒` }}</span >
487+ </div >
488+ </div >
489+ <div class =" total-stats" >
490+ <div >总尝试次数:{{ totalStats.totalAttempts }}</div >
491+ <div >总用时:{{ Math.floor(totalStats.totalTime / 60) > 0 ? `${Math.floor(totalStats.totalTime /
492+ 60)}分${totalStats.totalTime % 60}秒` : `${totalStats.totalTime}秒` }}</div >
493+ </div >
494+ </div >
495+
456496 <p v-if =" customMode.isActive.value" >是否退出自定义模式?</p >
457497 <p v-else >是否重新开始?</p >
458498 <div class =" congrats-buttons" >
459499 <button v-if =" customMode.isActive.value" @click =" exitCustomMode" >退出</button >
460500 <button v-else @click =" resetAll" >重新开始</button >
501+ <button v-if =" customMode.isActive.value" @click =" showCongrats = false"
502+ class =" cancel-btn" >取消</button >
461503 </div >
462504 </div >
463505 </div >
464506
465507 <div v-if =" gameFailed" class =" message failed" >
466508 😔 很遗憾,没有猜对!
467- <button v-if =" !customMode.isActive.value || customMode.viewIndex.value === customMode.currentIndex.value" @click =" startNewIdiom" >下一题</button >
509+ <button v-if =" !customMode.isActive.value || customMode.viewIndex.value === customMode.currentIndex.value"
510+ @click =" isAllCompleted ? showCompletionDialog() : startNewIdiom()" >{{ isAllCompleted ? '完成' : '下一题'
511+ }}</button >
468512 </div >
469513
470514 <div v-if =" gameWon" class =" message" >
471515 🎉 恭喜你猜对了!
472516 <div >用时:{{ elapsedTimeStr }}<span v-if =" elapsedTime === 0" >(你一定开挂了!)</span ></div >
473- <div v-if =" !customMode.isActive.value || customMode.viewIndex.value === customMode.currentIndex.value" class =" action-buttons" >
474- <button @click =" startNewIdiom" >下一题</button >
517+ <div v-if =" !customMode.isActive.value || customMode.viewIndex.value === customMode.currentIndex.value"
518+ class =" action-buttons" >
519+ <button @click =" isAllCompleted ? showCompletionDialog() : startNewIdiom()" >{{ isAllCompleted ? '完成' :
520+ '下一题' }}</button >
475521 <button v-if =" !customMode.isActive.value" @click =" shareCurrent" class =" share-question-btn"
476522 title =" 分享当前题目" >📤 分享题目</button >
477523 </div >
@@ -657,7 +703,9 @@ button:hover {
657703 padding : 40px ;
658704 border-radius : 20px ;
659705 text-align : center ;
660- max-width : 400px ;
706+ max-width : 500px ;
707+ max-height : 80vh ;
708+ overflow-y : auto ;
661709 animation : scaleIn 0.5s cubic-bezier (0.68 , -0.55 , 0.265 , 1.55 );
662710 box-shadow : 0 20px 60px rgba (0 , 0 , 0 , 0.3 );
663711}
@@ -685,6 +733,76 @@ button:hover {
685733 justify-content : center ;
686734}
687735
736+ .cancel-btn {
737+ background : #9e9e9e ;
738+ }
739+
740+ .cancel-btn :hover {
741+ background : #757575 ;
742+ }
743+
744+ .results-summary {
745+ margin : 20px 0 ;
746+ text-align : left ;
747+ }
748+
749+ .result-item {
750+ background : #f5f5f5 ;
751+ padding : 12px ;
752+ margin-bottom : 10px ;
753+ border-radius : 8px ;
754+ }
755+
756+ .result-header {
757+ display : flex ;
758+ align-items : center ;
759+ gap : 10px ;
760+ margin-bottom : 8px ;
761+ }
762+
763+ .result-number {
764+ font-weight : bold ;
765+ color : #666 ;
766+ }
767+
768+ .result-idiom {
769+ font-size : 18px ;
770+ font-weight : bold ;
771+ color : #333 ;
772+ flex : 1 ;
773+ }
774+
775+ .result-status {
776+ font-size : 20px ;
777+ }
778+
779+ .result-status.success {
780+ color : #4caf50 ;
781+ }
782+
783+ .result-status.failed {
784+ color : #f44336 ;
785+ }
786+
787+ .result-details {
788+ display : flex ;
789+ gap : 15px ;
790+ font-size : 14px ;
791+ color : #666 ;
792+ }
793+
794+ .total-stats {
795+ margin-top : 15px ;
796+ padding : 15px ;
797+ background : #e3f2fd ;
798+ border-radius : 8px ;
799+ font-weight : bold ;
800+ color : #1976d2 ;
801+ display : flex ;
802+ justify-content : space-around ;
803+ font-size : 16px ;
804+ }
805+
688806@keyframes fadeIn {
689807 from {
690808 opacity : 0 ;
0 commit comments