@@ -490,8 +490,8 @@ class QAController {
490490 if ( this . optionsContainer ) {
491491 Array . from ( this . optionsContainer . children ) . forEach ( child => {
492492 if ( child . dataset . id === question . answer ) {
493+ // 正确答案
493494 child . style . backgroundColor = '#e0ffe0' ;
494- // 添加正确图标
495495 const rightIcon = document . createElement ( 'img' ) ;
496496 rightIcon . src = '../assets/images/WenTianPavilion/right.svg' ;
497497 rightIcon . alt = 'correct' ;
@@ -500,9 +500,9 @@ class QAController {
500500 rightIcon . style . marginLeft = '1rem' ;
501501 rightIcon . style . verticalAlign = 'middle' ;
502502 child . appendChild ( rightIcon ) ;
503- } else if ( child . classList . contains ( 'selected' ) && ! correct ) {
503+ } else if ( child . classList . contains ( 'selected' ) ) {
504+ // 用户选择的错误答案
504505 child . style . backgroundColor = '#ffe0e0' ;
505- // 添加错误图标
506506 const errorIcon = document . createElement ( 'img' ) ;
507507 errorIcon . src = '../assets/images/WenTianPavilion/error.svg' ;
508508 errorIcon . alt = 'error' ;
@@ -511,6 +511,10 @@ class QAController {
511511 errorIcon . style . marginLeft = '1rem' ;
512512 errorIcon . style . verticalAlign = 'middle' ;
513513 child . appendChild ( errorIcon ) ;
514+ } else {
515+ // 其他未选择的选项,设置为灰色背景表示未选择
516+ child . style . backgroundColor = 'rgba(128, 128, 128, 0.2)' ;
517+ child . style . opacity = '0.6' ;
514518 }
515519 } ) ;
516520 }
@@ -656,8 +660,16 @@ class QAController {
656660 piece . classList . add ( 'puzzle-piece' ) ;
657661 piece . setAttribute ( 'draggable' , 'true' ) ;
658662 piece . dataset . index = originalIndex ; // 使用原始索引作为正确位置
659- piece . style . width = '8rem' ;
660- piece . style . height = '8rem' ;
663+ piece . style . cssText = `
664+ width: 8rem;
665+ height: 8rem;
666+ object-fit: cover;
667+ border-radius: 0.5rem;
668+ border: 0.2rem solid rgba(122, 147, 255, 0.3);
669+ cursor: move;
670+ transition: all 0.3s ease;
671+ background-color: rgba(0, 0, 0, 0.2);
672+ ` ;
661673 piece . title = `碎片 ${ originalIndex + 1 } ` ;
662674 piecesContainer . appendChild ( piece ) ;
663675
@@ -670,11 +682,22 @@ class QAController {
670682 const target = document . createElement ( 'div' ) ;
671683 target . classList . add ( 'puzzle-target' ) ;
672684 target . dataset . index = index ;
673- target . style . width = '8rem' ;
674- target . style . height = '8rem' ;
685+ target . style . cssText = `
686+ width: 8rem;
687+ height: 8rem;
688+ border: 0.2rem dashed rgba(122, 147, 255, 0.3);
689+ border-radius: 0.5rem;
690+ display: flex;
691+ align-items: center;
692+ justify-content: center;
693+ background-color: rgba(122, 147, 255, 0.05);
694+ transition: all 0.3s ease;
695+ position: relative;
696+ font-size: 1.4rem;
697+ color: rgba(122, 147, 255, 0.7);
698+ font-family: 'fys', sans-serif;
699+ ` ;
675700 target . textContent = `位置 ${ index + 1 } ` ;
676- target . style . fontSize = '1.4rem' ;
677- target . style . color = 'rgba(122, 147, 255, 0.7)' ;
678701 targetsContainer . appendChild ( target ) ;
679702
680703 // 添加拖拽事件
@@ -688,6 +711,7 @@ class QAController {
688711 handleDragStart ( e ) {
689712 e . dataTransfer . setData ( 'text/plain' , e . target . dataset . index ) ;
690713 e . target . style . opacity = '0.5' ;
714+ e . target . style . transform = 'scale(0.95)' ;
691715 }
692716
693717 handleDragOver ( e ) {
@@ -713,8 +737,9 @@ class QAController {
713737
714738 if ( ! piece ) return ;
715739
716- // 恢复透明度
740+ // 恢复透明度和缩放
717741 piece . style . opacity = '1' ;
742+ piece . style . transform = 'scale(1)' ;
718743
719744 // 检查是否已有碎片在目标位置
720745 const existingPiece = e . target . querySelector ( '.puzzle-piece' ) ;
@@ -726,16 +751,30 @@ class QAController {
726751
727752 if ( pieceIndex === targetIndex ) {
728753 // 正确放置
754+ e . target . innerHTML = '' ; // 清空内容
729755 e . target . appendChild ( piece ) ;
730- e . target . textContent = '' ; // 清除位置提示文字
731756 e . target . classList . add ( 'puzzle-completed' ) ;
757+
758+ // 调整碎片在目标位置的样式
759+ piece . style . width = '100%' ;
760+ piece . style . height = '100%' ;
761+ piece . style . objectFit = 'cover' ;
762+ piece . style . borderRadius = '0.5rem' ;
763+
732764 this . checkPuzzleCompletion ( ) ;
733765 } else {
734- // 错误放置,直接移回碎片容器
766+ // 错误放置,显示错误动画后移回碎片容器
767+ e . target . innerHTML = '' ; // 清空内容
735768 e . target . appendChild ( piece ) ;
736- e . target . textContent = '' ; // 清除位置提示文字
769+
770+ // 错误动画
771+ piece . style . filter = 'sepia(1) hue-rotate(-50deg) saturate(2)' ;
737772 setTimeout ( ( ) => {
738773 const piecesContainer = document . querySelector ( '.puzzle-pieces' ) ;
774+ piece . style . width = '8rem' ;
775+ piece . style . height = '8rem' ;
776+ piece . style . objectFit = 'cover' ;
777+ piece . style . filter = 'none' ;
739778 piecesContainer . appendChild ( piece ) ;
740779 e . target . textContent = `位置 ${ parseInt ( targetIndex ) + 1 } ` ;
741780 e . target . classList . remove ( 'puzzle-completed' ) ;
@@ -763,7 +802,7 @@ class QAController {
763802 if ( correctCount === totalCount ) {
764803 // 拼图完成
765804 setTimeout ( ( ) => {
766- alert ( '🎉 恭喜!拼图完成!\n\n你已经成功解开了宇宙的奥秘,收集了所有的知识碎片!' ) ;
805+ this . showCompletionModal ( ) ;
767806 // 可以添加完成后的效果
768807 const puzzleContainer = document . querySelector ( '.puzzle-targets' ) ;
769808 if ( puzzleContainer ) {
@@ -789,6 +828,178 @@ class QAController {
789828 }
790829 }
791830
831+ showCompletionModal ( ) {
832+ // 创建弹窗覆盖层
833+ const modalOverlay = document . createElement ( 'div' ) ;
834+ modalOverlay . className = 'completion-modal-overlay' ;
835+ modalOverlay . style . cssText = `
836+ position: fixed;
837+ top: 0;
838+ left: 0;
839+ width: 100vw;
840+ height: 100vh;
841+ background: rgba(0, 0, 0, 0.3);
842+ display: flex;
843+ align-items: center;
844+ justify-content: center;
845+ z-index: 10000;
846+ backdrop-filter: blur(1rem);
847+ ` ;
848+
849+ // 创建弹窗内容
850+ const modalContent = document . createElement ( 'div' ) ;
851+ modalContent . className = 'completion-modal-content' ;
852+ modalContent . style . cssText = `
853+ background: linear-gradient(135deg, rgba(30, 0, 50, 0.95), rgba(70, 20, 100, 0.95));
854+ border-radius: 2rem;
855+ padding: 4rem;
856+ text-align: center;
857+ max-width: 60rem;
858+ position: relative;
859+ transform: scale(0.8);
860+ transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
861+ box-shadow: 0 2rem 4rem rgba(122, 147, 255, 0.3);
862+ ` ;
863+
864+ // 创建标题
865+ const title = document . createElement ( 'h2' ) ;
866+ title . textContent = '恭喜!拼图完成!' ;
867+ title . style . cssText = `
868+ font-size: 4rem;
869+ font-family: 'fys', sans-serif;
870+ background: linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(191, 151, 202, 1), rgba(127, 48, 150, 1));
871+ background-clip: text;
872+ color: transparent;
873+ margin-bottom: 2rem;
874+ ` ;
875+
876+ // 创建图片容器
877+ const imageContainer = document . createElement ( 'div' ) ;
878+ imageContainer . style . cssText = `
879+ margin: 3rem 0;
880+ perspective: 150rem;
881+ display: flex;
882+ justify-content: center;
883+ align-items: center;
884+ ` ;
885+
886+ // 创建奖杯图片
887+ const trophyImage = document . createElement ( 'img' ) ;
888+ trophyImage . src = '../assets/images/WenTianPavilion/all.webp' ;
889+ trophyImage . alt = 'completion trophy' ;
890+ trophyImage . style . cssText = `
891+ width: 20rem;
892+ height: 20rem;
893+ object-fit: contain;
894+ transition: transform 0.2s ease-out;
895+ transform-style: preserve-3d;
896+ cursor: pointer;
897+ filter: drop-shadow(0 1rem 2rem rgba(122, 147, 255, 0.4));
898+ ` ;
899+
900+ // 添加3D旋转交互
901+ imageContainer . addEventListener ( 'mousemove' , ( e ) => {
902+ const rect = imageContainer . getBoundingClientRect ( ) ;
903+ const centerX = rect . left + rect . width / 2 ;
904+ const centerY = rect . top + rect . height / 2 ;
905+
906+ // 计算鼠标相对于容器中心的位置(-1到1之间)
907+ const mouseX = ( e . clientX - centerX ) / ( rect . width / 2 ) ;
908+ const mouseY = ( e . clientY - centerY ) / ( rect . height / 2 ) ;
909+
910+ // 计算旋转角度,限制在合理范围内
911+ const rotateY = mouseX * 15 ; // 左右旋转最大15度
912+ const rotateX = - mouseY * 10 ; // 上下旋转最大10度
913+
914+ trophyImage . style . transform = `
915+ perspective(150rem)
916+ rotateX(${ rotateX } deg)
917+ rotateY(${ rotateY } deg)
918+ scale(1.05)
919+ translateZ(2rem)
920+ ` ;
921+ } ) ;
922+
923+ imageContainer . addEventListener ( 'mouseleave' , ( ) => {
924+ trophyImage . style . transform = `
925+ perspective(150rem)
926+ rotateX(0deg)
927+ rotateY(0deg)
928+ scale(1)
929+ translateZ(0rem)
930+ ` ;
931+ } ) ;
932+
933+ // 创建描述文字
934+ const description = document . createElement ( 'p' ) ;
935+ description . textContent = '你已经成功解开了宇宙的奥秘,收集了所有的知识碎片!' ;
936+ description . style . cssText = `
937+ font-size: 2.4rem;
938+ font-family: 'fys', sans-serif;
939+ color: rgba(255, 255, 255, 0.9);
940+ margin: 2rem 0;
941+ line-height: 1.5;
942+ ` ;
943+
944+ // 创建关闭按钮
945+ const closeButton = document . createElement ( 'button' ) ;
946+ closeButton . textContent = '完成' ;
947+ closeButton . style . cssText = `
948+ background: linear-gradient(135deg, rgba(122, 147, 255, 1), rgba(127, 48, 150, 1));
949+ border: none;
950+ border-radius: 1rem;
951+ color: white;
952+ font-size: 2.4rem;
953+ font-family: 'fys', sans-serif;
954+ padding: 1rem 2rem;
955+ cursor: pointer;
956+ transition: all 0.3s ease;
957+ margin-top: 2rem;
958+ ` ;
959+
960+ closeButton . addEventListener ( 'mouseover' , ( ) => {
961+ closeButton . style . transform = 'scale(1.05)' ;
962+ closeButton . style . boxShadow = '0 1rem 2rem rgba(122, 147, 255, 0.4)' ;
963+ } ) ;
964+
965+ closeButton . addEventListener ( 'mouseout' , ( ) => {
966+ closeButton . style . transform = 'scale(1)' ;
967+ closeButton . style . boxShadow = 'none' ;
968+ } ) ;
969+
970+ closeButton . addEventListener ( 'click' , ( ) => {
971+ modalOverlay . style . opacity = '0' ;
972+ modalContent . style . transform = 'scale(0.8)' ;
973+ setTimeout ( ( ) => {
974+ document . body . removeChild ( modalOverlay ) ;
975+ } , 300 ) ;
976+ } ) ;
977+
978+ // 组装弹窗
979+ imageContainer . appendChild ( trophyImage ) ;
980+ modalContent . appendChild ( title ) ;
981+ modalContent . appendChild ( imageContainer ) ;
982+ modalContent . appendChild ( description ) ;
983+ modalContent . appendChild ( closeButton ) ;
984+ modalOverlay . appendChild ( modalContent ) ;
985+
986+ // 添加到页面并显示动画
987+ document . body . appendChild ( modalOverlay ) ;
988+
989+ // 触发进入动画
990+ setTimeout ( ( ) => {
991+ modalOverlay . style . opacity = '1' ;
992+ modalContent . style . transform = 'scale(1)' ;
993+ } , 50 ) ;
994+
995+ // 点击背景关闭弹窗
996+ modalOverlay . addEventListener ( 'click' , ( e ) => {
997+ if ( e . target === modalOverlay ) {
998+ closeButton . click ( ) ;
999+ }
1000+ } ) ;
1001+ }
1002+
7921003 showHideController ( hiddenControllers , showControllers ) {
7931004 // 立即隐藏不需要的元素
7941005 hiddenControllers . forEach ( controller => {
0 commit comments