Quellcode durchsuchen

新增两个拼图

任一存 vor 2 Jahren
Ursprung
Commit
8fc29df56b
82 geänderte Dateien mit 409 neuen und 160 gelöschten Zeilen
  1. 1 1
      package.json
  2. 10 0
      public/speech.json
  3. 70 1
      src/assets/images/jigsaw-game-3/compound.svg
  4. BIN
      src/assets/images/jigsaw-game-3/jigsaw-shade/1.基础.png
  5. BIN
      src/assets/images/jigsaw-game-3/jigsaw-shade/1.马路.png
  6. BIN
      src/assets/images/jigsaw-game-3/jigsaw-shade/2.河堤.png
  7. BIN
      src/assets/images/jigsaw-game-3/jigsaw-shade/2.立柱.png
  8. BIN
      src/assets/images/jigsaw-game-3/jigsaw-shade/3.桥体.png
  9. BIN
      src/assets/images/jigsaw-game-3/jigsaw-shade/3.椽(chuan).png
  10. BIN
      src/assets/images/jigsaw-game-3/jigsaw-shade/4.桥护栏.png
  11. BIN
      src/assets/images/jigsaw-game-3/jigsaw-shade/4.檩条.png
  12. BIN
      src/assets/images/jigsaw-game-3/jigsaw-shade/5.亭子基座.png
  13. BIN
      src/assets/images/jigsaw-game-3/jigsaw-shade/5.围墙.png
  14. BIN
      src/assets/images/jigsaw-game-3/jigsaw-shade/6.亭子立柱.png
  15. BIN
      src/assets/images/jigsaw-game-3/jigsaw-shade/6.屋顶.png
  16. BIN
      src/assets/images/jigsaw-game-3/jigsaw-shade/7.亭子顶.png
  17. BIN
      src/assets/images/jigsaw-game-3/jigsaw-shade/7.连廊.png
  18. BIN
      src/assets/images/jigsaw-game-3/jigsaw-shade/8.石碑.png
  19. BIN
      src/assets/images/jigsaw-game-3/jigsaw-shade/8.门.png
  20. BIN
      src/assets/images/jigsaw-game-3/jigsaw-shade/9.桃树.png
  21. BIN
      src/assets/images/jigsaw-game-3/jigsaw/1.基础.png
  22. BIN
      src/assets/images/jigsaw-game-3/jigsaw/1.马路.png
  23. BIN
      src/assets/images/jigsaw-game-3/jigsaw/2.河堤.png
  24. BIN
      src/assets/images/jigsaw-game-3/jigsaw/2.立柱.png
  25. BIN
      src/assets/images/jigsaw-game-3/jigsaw/3.桥体.png
  26. BIN
      src/assets/images/jigsaw-game-3/jigsaw/3.椽(chuan).png
  27. BIN
      src/assets/images/jigsaw-game-3/jigsaw/4.桥护栏.png
  28. BIN
      src/assets/images/jigsaw-game-3/jigsaw/4.檩条.png
  29. BIN
      src/assets/images/jigsaw-game-3/jigsaw/5.亭子基座.png
  30. BIN
      src/assets/images/jigsaw-game-3/jigsaw/5.围墙.png
  31. BIN
      src/assets/images/jigsaw-game-3/jigsaw/6.亭子立柱.png
  32. BIN
      src/assets/images/jigsaw-game-3/jigsaw/6.屋顶.png
  33. BIN
      src/assets/images/jigsaw-game-3/jigsaw/7.亭子顶.png
  34. BIN
      src/assets/images/jigsaw-game-3/jigsaw/7.连廊.png
  35. BIN
      src/assets/images/jigsaw-game-3/jigsaw/8.石碑.png
  36. BIN
      src/assets/images/jigsaw-game-3/jigsaw/8.门.png
  37. BIN
      src/assets/images/jigsaw-game-3/jigsaw/9.桃树.png
  38. 70 1
      src/assets/images/jigsaw-game-4/compound.svg
  39. BIN
      src/assets/images/jigsaw-game-4/jigsaw-shade/1.坐斗.png
  40. BIN
      src/assets/images/jigsaw-game-4/jigsaw-shade/1.马路.png
  41. BIN
      src/assets/images/jigsaw-game-4/jigsaw-shade/2.拱①.png
  42. BIN
      src/assets/images/jigsaw-game-4/jigsaw-shade/2.河堤.png
  43. BIN
      src/assets/images/jigsaw-game-4/jigsaw-shade/3.桥体.png
  44. BIN
      src/assets/images/jigsaw-game-4/jigsaw-shade/3.翘.png
  45. BIN
      src/assets/images/jigsaw-game-4/jigsaw-shade/4.斗①.png
  46. BIN
      src/assets/images/jigsaw-game-4/jigsaw-shade/4.桥护栏.png
  47. BIN
      src/assets/images/jigsaw-game-4/jigsaw-shade/5.亭子基座.png
  48. BIN
      src/assets/images/jigsaw-game-4/jigsaw-shade/5.拱②.png
  49. BIN
      src/assets/images/jigsaw-game-4/jigsaw-shade/6.亭子立柱.png
  50. BIN
      src/assets/images/jigsaw-game-4/jigsaw-shade/6.单昂.png
  51. BIN
      src/assets/images/jigsaw-game-4/jigsaw-shade/7.亭子顶.png
  52. BIN
      src/assets/images/jigsaw-game-4/jigsaw-shade/7.斗②.png
  53. BIN
      src/assets/images/jigsaw-game-4/jigsaw-shade/8.枋.png
  54. BIN
      src/assets/images/jigsaw-game-4/jigsaw-shade/8.石碑.png
  55. BIN
      src/assets/images/jigsaw-game-4/jigsaw-shade/9.桃树.png
  56. BIN
      src/assets/images/jigsaw-game-4/jigsaw/1.坐斗.png
  57. BIN
      src/assets/images/jigsaw-game-4/jigsaw/1.马路.png
  58. BIN
      src/assets/images/jigsaw-game-4/jigsaw/2.拱①.png
  59. BIN
      src/assets/images/jigsaw-game-4/jigsaw/2.河堤.png
  60. BIN
      src/assets/images/jigsaw-game-4/jigsaw/3.桥体.png
  61. BIN
      src/assets/images/jigsaw-game-4/jigsaw/3.翘.png
  62. BIN
      src/assets/images/jigsaw-game-4/jigsaw/4.斗①.png
  63. BIN
      src/assets/images/jigsaw-game-4/jigsaw/4.桥护栏.png
  64. BIN
      src/assets/images/jigsaw-game-4/jigsaw/5.亭子基座.png
  65. BIN
      src/assets/images/jigsaw-game-4/jigsaw/5.拱②.png
  66. BIN
      src/assets/images/jigsaw-game-4/jigsaw/6.亭子立柱.png
  67. BIN
      src/assets/images/jigsaw-game-4/jigsaw/6.单昂.png
  68. BIN
      src/assets/images/jigsaw-game-4/jigsaw/7.亭子顶.png
  69. BIN
      src/assets/images/jigsaw-game-4/jigsaw/7.斗②.png
  70. BIN
      src/assets/images/jigsaw-game-4/jigsaw/8.枋.png
  71. BIN
      src/assets/images/jigsaw-game-4/jigsaw/8.石碑.png
  72. BIN
      src/assets/images/jigsaw-game-4/jigsaw/9.桃树.png
  73. BIN
      src/assets/images/lion-female-idle.gif
  74. BIN
      src/assets/images/lion-male-idle.gif
  75. BIN
      src/assets/images/speach-text-wrapper.png
  76. 65 93
      src/config.js
  77. 16 8
      src/store/index.js
  78. 34 16
      src/views/Bag.vue
  79. 23 25
      src/views/JigsawGame.vue
  80. 19 0
      src/views/Learn.vue
  81. 83 15
      src/views/Level3.vue
  82. 18 0
      src/views/Watch.vue

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "my-app",
-  "version": "0.0.6",
+  "version": "0.0.7",
   "private": true,
   "scripts": {
     "serve": "vue-cli-service serve --mode dev",

+ 10 - 0
public/speech.json

@@ -0,0 +1,10 @@
+var speechInfo = {
+  "1-0": [
+    {
+      "start-time": "00:00:00",
+    },
+    {
+      "start-time": "00:00:10",
+    }
+  ]
+}

Datei-Diff unterdrückt, da er zu groß ist
+ 70 - 1
src/assets/images/jigsaw-game-3/compound.svg


BIN
src/assets/images/jigsaw-game-3/jigsaw-shade/1.基础.png


BIN
src/assets/images/jigsaw-game-3/jigsaw-shade/1.马路.png


BIN
src/assets/images/jigsaw-game-3/jigsaw-shade/2.河堤.png


BIN
src/assets/images/jigsaw-game-3/jigsaw-shade/2.立柱.png


BIN
src/assets/images/jigsaw-game-3/jigsaw-shade/3.桥体.png


BIN
src/assets/images/jigsaw-game-3/jigsaw-shade/3.椽(chuan).png


BIN
src/assets/images/jigsaw-game-3/jigsaw-shade/4.桥护栏.png


BIN
src/assets/images/jigsaw-game-3/jigsaw-shade/4.檩条.png


BIN
src/assets/images/jigsaw-game-3/jigsaw-shade/5.亭子基座.png


BIN
src/assets/images/jigsaw-game-3/jigsaw-shade/5.围墙.png


BIN
src/assets/images/jigsaw-game-3/jigsaw-shade/6.亭子立柱.png


BIN
src/assets/images/jigsaw-game-3/jigsaw-shade/6.屋顶.png


BIN
src/assets/images/jigsaw-game-3/jigsaw-shade/7.亭子顶.png


BIN
src/assets/images/jigsaw-game-3/jigsaw-shade/7.连廊.png


BIN
src/assets/images/jigsaw-game-3/jigsaw-shade/8.石碑.png


BIN
src/assets/images/jigsaw-game-3/jigsaw-shade/8.门.png


BIN
src/assets/images/jigsaw-game-3/jigsaw-shade/9.桃树.png


BIN
src/assets/images/jigsaw-game-3/jigsaw/1.基础.png


BIN
src/assets/images/jigsaw-game-3/jigsaw/1.马路.png


BIN
src/assets/images/jigsaw-game-3/jigsaw/2.河堤.png


BIN
src/assets/images/jigsaw-game-3/jigsaw/2.立柱.png


BIN
src/assets/images/jigsaw-game-3/jigsaw/3.桥体.png


BIN
src/assets/images/jigsaw-game-3/jigsaw/3.椽(chuan).png


BIN
src/assets/images/jigsaw-game-3/jigsaw/4.桥护栏.png


BIN
src/assets/images/jigsaw-game-3/jigsaw/4.檩条.png


BIN
src/assets/images/jigsaw-game-3/jigsaw/5.亭子基座.png


BIN
src/assets/images/jigsaw-game-3/jigsaw/5.围墙.png


BIN
src/assets/images/jigsaw-game-3/jigsaw/6.亭子立柱.png


BIN
src/assets/images/jigsaw-game-3/jigsaw/6.屋顶.png


BIN
src/assets/images/jigsaw-game-3/jigsaw/7.亭子顶.png


BIN
src/assets/images/jigsaw-game-3/jigsaw/7.连廊.png


BIN
src/assets/images/jigsaw-game-3/jigsaw/8.石碑.png


BIN
src/assets/images/jigsaw-game-3/jigsaw/8.门.png


BIN
src/assets/images/jigsaw-game-3/jigsaw/9.桃树.png


Datei-Diff unterdrückt, da er zu groß ist
+ 70 - 1
src/assets/images/jigsaw-game-4/compound.svg


BIN
src/assets/images/jigsaw-game-4/jigsaw-shade/1.坐斗.png


BIN
src/assets/images/jigsaw-game-4/jigsaw-shade/1.马路.png


BIN
src/assets/images/jigsaw-game-4/jigsaw-shade/2.拱①.png


BIN
src/assets/images/jigsaw-game-4/jigsaw-shade/2.河堤.png


BIN
src/assets/images/jigsaw-game-4/jigsaw-shade/3.桥体.png


BIN
src/assets/images/jigsaw-game-4/jigsaw-shade/3.翘.png


BIN
src/assets/images/jigsaw-game-4/jigsaw-shade/4.斗①.png


BIN
src/assets/images/jigsaw-game-4/jigsaw-shade/4.桥护栏.png


BIN
src/assets/images/jigsaw-game-4/jigsaw-shade/5.亭子基座.png


BIN
src/assets/images/jigsaw-game-4/jigsaw-shade/5.拱②.png


BIN
src/assets/images/jigsaw-game-4/jigsaw-shade/6.亭子立柱.png


BIN
src/assets/images/jigsaw-game-4/jigsaw-shade/6.单昂.png


BIN
src/assets/images/jigsaw-game-4/jigsaw-shade/7.亭子顶.png


BIN
src/assets/images/jigsaw-game-4/jigsaw-shade/7.斗②.png


BIN
src/assets/images/jigsaw-game-4/jigsaw-shade/8.枋.png


BIN
src/assets/images/jigsaw-game-4/jigsaw-shade/8.石碑.png


BIN
src/assets/images/jigsaw-game-4/jigsaw-shade/9.桃树.png


BIN
src/assets/images/jigsaw-game-4/jigsaw/1.坐斗.png


BIN
src/assets/images/jigsaw-game-4/jigsaw/1.马路.png


BIN
src/assets/images/jigsaw-game-4/jigsaw/2.拱①.png


BIN
src/assets/images/jigsaw-game-4/jigsaw/2.河堤.png


BIN
src/assets/images/jigsaw-game-4/jigsaw/3.桥体.png


BIN
src/assets/images/jigsaw-game-4/jigsaw/3.翘.png


BIN
src/assets/images/jigsaw-game-4/jigsaw/4.斗①.png


BIN
src/assets/images/jigsaw-game-4/jigsaw/4.桥护栏.png


BIN
src/assets/images/jigsaw-game-4/jigsaw/5.亭子基座.png


BIN
src/assets/images/jigsaw-game-4/jigsaw/5.拱②.png


BIN
src/assets/images/jigsaw-game-4/jigsaw/6.亭子立柱.png


BIN
src/assets/images/jigsaw-game-4/jigsaw/6.单昂.png


BIN
src/assets/images/jigsaw-game-4/jigsaw/7.亭子顶.png


BIN
src/assets/images/jigsaw-game-4/jigsaw/7.斗②.png


BIN
src/assets/images/jigsaw-game-4/jigsaw/8.枋.png


BIN
src/assets/images/jigsaw-game-4/jigsaw/8.石碑.png


BIN
src/assets/images/jigsaw-game-4/jigsaw/9.桃树.png


BIN
src/assets/images/lion-female-idle.gif


BIN
src/assets/images/lion-male-idle.gif


BIN
src/assets/images/speach-text-wrapper.png


+ 65 - 93
src/config.js

@@ -12,36 +12,29 @@ export default {
         width: '324',
         height: '378',
       },
+      jigsawList: [
+        '1.马路.png',
+        '2.河堤.png',
+        '3.桥体.png',
+        '4.桥护栏.png',
+        '5.亭子基座.png',
+        '6.亭子立柱.png',
+        '7.亭子顶.png',
+        '8.石碑.png',
+        '9.桃树.png',
+      ],
       children: [
         {
           name: '文化溯源',
           lionGender: 'female',
-          jigsawNumber: 3,
-          jigsawList: [
-            '1.马路.png',
-            '2.河堤.png',
-            '3.桥体.png',
-          ]
         },
         {
           name: '画里乡村',
           lionGender: 'female',
-          jigsawNumber: 3,
-          jigsawList: [
-            '4.桥护栏.png',
-            '5.亭子基座.png',
-            '6.亭子立柱.png',
-          ]
         },
         {
           name: '水口园林',
           lionGender: 'female',
-          jigsawNumber: 3,
-          jigsawList: [
-            '7.亭子顶.png',
-            '8.石碑.png',
-            '9.桃树.png',
-          ]
         },
       ]
     },
@@ -57,39 +50,29 @@ export default {
         width: '324',
         height: '378',
       },
+      jigsawList: [
+        '1.台基.png',
+        '2.基座.png',
+        '3.立柱.png',
+        '4.夹柱石.png',
+        '5.横梁.png',
+        '6.斗拱.png',
+        '7.雀替.png',
+        '8.龙凤榜.png',
+        '9.楼.png',
+      ],
       children: [
         {
           name: '认识牌坊',
           lionGender: 'male',
-          jigsawNumber: 3,
-          jigsawList: [
-            '1.台基.png',
-            '2.基座.png',
-            '3.立柱.png',
-
-          ],
-          lionSpeach: '当我们来到徽州,总能看见许许多多门洞形状的建筑物,它就是“徽州三绝”之一的牌坊。徽州因为拥有的牌坊数量众多,样式精美,也被誉为“牌坊之乡”。'
         },
         {
           name: '牌坊形制',
           lionGender: 'male',
-          jigsawNumber: 3,
-          jigsawList: [
-            '4.夹柱石.png',
-            '5.横梁.png',
-            '6.斗拱.png',
-
-          ],
         },
         {
           name: '牌坊构造',
           lionGender: 'male',
-          jigsawNumber: 3,
-          jigsawList: [
-            '7.雀替.png',
-            '8.龙凤榜.png',
-            '9.楼.png',
-          ],
         },
       ]
     },
@@ -105,36 +88,29 @@ export default {
         width: '454',
         height: '370',
       },
+      jigsawList: [
+        '1.台基.png',
+        '2.基座.png',
+        '3.立柱.png',
+        '4.椽(chuan).png',
+        '5.檩(lin)条.png',
+        '6.连廊.png',
+        '7.围墙.png',
+        '8.屋顶.png',
+        '9.五凤楼.png',
+      ],
       children: [
         {
           name: '认识祠堂',
           lionGender: 'female',
-          jigsawNumber: 3,
-          jigsawList: [
-            '1.台基.png',
-            '2.基座.png',
-            '3.立柱.png',
-          ]
         },
         {
           name: '祠堂的建筑艺术 ①',
           lionGender: 'female',
-          jigsawNumber: 3,
-          jigsawList: [
-            '4.椽(chuan).png',
-            '5.檩(lin)条.png',
-            '6.连廊.png',
-          ]
         },
         {
           name: '祠堂的建筑艺术 ②',
           lionGender: 'female',
-          jigsawNumber: 3,
-          jigsawList: [
-            '7.围墙.png',
-            '8.屋顶.png',
-            '9.五凤楼.png',
-          ]
         },
       ]
     },
@@ -150,30 +126,29 @@ export default {
         width: '358',
         height: '378',
       },
+      jigsawList: [
+        '1.基础.png',
+        '2.立柱.png',
+        '3.椽(chuan).png',
+        '4.檩条.png',
+        '5.围墙.png',
+        '6.屋顶.png',
+        '7.连廊.png',
+        '8.门.png',
+
+      ],
       children: [
         {
           name: '认识民居',
           lionGender: 'male',
-          jigsawNumber: 3,
-          jigsawList: [
-
-          ],
         },
         {
           name: '民居的营造 ①',
           lionGender: 'male',
-          jigsawNumber: 3,
-          jigsawList: [
-
-          ],
         },
         {
           name: '民居的营造 ②',
           lionGender: 'male',
-          jigsawNumber: 3,
-          jigsawList: [
-
-          ],
         },
       ]
     }, {
@@ -188,30 +163,28 @@ export default {
         width: '324',
         height: '378',
       },
+      jigsawList: [
+        '1.坐斗.png',
+        '2.拱①.png',
+        '3.翘.png',
+        '4.斗①.png',
+        '5.拱②.png',
+        '6.单昂.png',
+        '7.斗②.png',
+        '8.枋.png',
+      ],
       children: [
         {
           name: '榫卯技艺',
           lionGender: 'female',
-          jigsawNumber: 3,
-          jigsawList: [
-
-          ],
         },
         {
           name: '雕刻艺术 ①',
           lionGender: 'female',
-          jigsawNumber: 3,
-          jigsawList: [
-
-          ],
         },
         {
           name: '雕刻艺术 ②',
           lionGender: 'female',
-          jigsawNumber: 3,
-          jigsawList: [
-
-          ],
         },
       ]
     }, {
@@ -226,22 +199,21 @@ export default {
         width: '438',
         height: '174',
       },
+      jigsawList: [
+        '1.道路.png',
+        '2.水池.png',
+        '3.月洞门.png',
+        '4.八角亭.png',
+        '5.凉亭.png',
+        '6.建筑地基.png',
+        '7.书斋.png',
+        '8.厅堂.png',
+        '9.树.png',
+      ],
       children: [
         {
           name: '其他建筑类型鉴赏',
           lionGender: 'male',
-          jigsawNumber: 9,
-          jigsawList: [
-            '1.道路.png',
-            '2.水池.png',
-            '3.月洞门.png',
-            '4.八角亭.png',
-            '5.凉亭.png',
-            '6.建筑地基.png',
-            '7.书斋.png',
-            '8.厅堂.png',
-            '9.树.png',
-          ],
         },
       ]
     },

+ 16 - 8
src/store/index.js

@@ -5,14 +5,14 @@ function resetGameProgress() {
     jigsawProgress: config.sceneTree.map((item) => {
       return {
         name: item.name,
-        isJigsawDone: false,
+        isJigsawDone: false, // 是否已完成拼图游戏
+        jigsawList: [...item.jigsawList], // 拼图碎片名称列表
         children: item.children.map((innerItem) => {
-          console.log(innerItem)
+          // console.log(innerItem)
           return {
             name: innerItem.name,
-            hasGotJigsaw: true,
-            jigsawNumber: innerItem.jigsawNumber,
-            jigsawList: [...innerItem.jigsawList],
+            watchVideoProgress: [true, true, true, true, true, true, true, true, true, true, ],
+            learnVideoProgress: [true, true, true, true, true, true, true, true, true, true, ],
           }
         })
       }
@@ -42,10 +42,18 @@ export default createStore({
     recordLionSpoke(state) {
       state.hasLionSpoke = true
     },
-    // 获得拼图碎片
-    recordJigsawGot(state, sceneL2Id, sceneL3Id) {
+    recordWatchProgress(state, { sceneL2Id, sceneL3Id, timeIdx }) {
       try {
-        state.gameProgress.jigsawProgress[sceneL2Id].children[sceneL3Id].hasGotJigsaw = true
+        state.gameProgress.jigsawProgress[sceneL2Id].children[sceneL3Id].watchVideoProgress[timeIdx] = true
+        localStorage.setItem(`HuiZhouGuJianZhuProgress-v${process.env.VUE_APP_VERSION}`, JSON.stringify(state.gameProgress))
+      } catch (error) {
+        console.error(error)
+        state.gameProgress = resetGameProgress()
+      }
+    },
+    recordLearnProgress(state, { sceneL2Id, sceneL3Id, timeIdx }) {
+      try {
+        state.gameProgress.jigsawProgress[sceneL2Id].children[sceneL3Id].learnVideoProgress[timeIdx] = true
         localStorage.setItem(`HuiZhouGuJianZhuProgress-v${process.env.VUE_APP_VERSION}`, JSON.stringify(state.gameProgress))
       } catch (error) {
         console.error(error)

+ 34 - 16
src/views/Bag.vue

@@ -8,7 +8,7 @@
         :key="idx"
         v-click-audio
         class="scene"
-        :class="gameProgress.jigsawProgress[item.idxInConfig].isJigsawDone ? 'unlock' : 'lock'"
+        :class="isJigsawUnlock(item) ? 'unlock' : 'lock'"
         :style="{
           width: `calc(${item.width} / 1080 * 100vh)`,
           height: `calc(${item.height} / 1080 * 100vh)`,
@@ -28,15 +28,19 @@
           <div class="bottom-right">
             <img
               class="fraction"
-              :src="require(`@/assets/images/jigsaw-shade-${gameProgress.jigsawProgress[item.idxInConfig].isJigsawDone ? 'unlock' : 'lock'}.png`)"
+              :src="require(`@/assets/images/jigsaw-shade-${isJigsawUnlock(item) ? 'unlock' : 'lock'}.png`)"
               alt=""
               draggable="false"
             >
-            &ensp;× {{ sceneTree[item.idxInConfig].children.reduce((a, b) => {
-              return {
-                jigsawNumber: a.jigsawNumber + b.jigsawNumber
-              }
-            }).jigsawNumber }}
+            &ensp;× {{
+              gameProgress.jigsawProgress[item.idxInConfig].children.map((item) => {
+                const score1 = item.watchVideoProgress.includes(false) ? 0 : 1
+                const score2 = item.learnVideoProgress.includes(false) ? 0 : 1
+                return score1 + score2
+              }).reduce((a, b) => {
+                return a + b
+              })
+            }}
           </div>
         </div>
       </div>
@@ -64,7 +68,7 @@
 </template>
 
 <script>
-import { ElMessage } from 'element-plus'
+import { ElMessage, ElMessageBox } from 'element-plus'
 
 export default {
   name: 'BagView',
@@ -85,7 +89,7 @@ export default {
           height: 360,
           top: 50,
           left: 637,
-          isOpen: false,
+          isOpen: true,
         },
         {
           idxInConfig: 5,
@@ -101,7 +105,7 @@ export default {
           height: 186,
           top: 634,
           left: 40,
-          isOpen: false,
+          isOpen: true,
         },
         {
           idxInConfig: 1,
@@ -151,14 +155,28 @@ export default {
         utils.animateCSS(e.currentTarget, 'headShake')
       }
     },
+    isJigsawUnlock(itemInSceneList) {
+      return !this.gameProgress.jigsawProgress[itemInSceneList.idxInConfig].children.find((itemInSceneList) => {
+        return itemInSceneList.watchVideoProgress.includes(false) || itemInSceneList.learnVideoProgress.includes(false)
+      })
+    },
     onClickSceneEntry(item) {
       if (item.isOpen) {
-        this.$router.push({
-          name: 'JigsawGame',
-          query: {
-            sceneL2Idx: item.idxInConfig,
-          }
-        })
+        if (this.isJigsawUnlock(item)) {
+          this.$router.push({
+            name: 'JigsawGame',
+            query: {
+              sceneL2Idx: item.idxInConfig,
+            }
+          })
+        } else {
+          ElMessageBox.alert('同学您好,您还未学完该章节所有课程,无法解锁游戏环节,请继续学习!', '', {
+            confirmButtonText: '确定',
+            callback: (action) => {
+              console.log(action)
+            },
+          })
+        }
       } else {
         ElMessage({
           message: '敬请期待',

+ 23 - 25
src/views/JigsawGame.vue

@@ -41,17 +41,17 @@
         >
       </h1>
       <li
-        v-for="(jigsawItem, idx) in jigsawItemsFlatten"
+        v-for="(jigsawItem, idx) in jigsawItems"
         :key="idx"
       >
         <img
           class=""
           :style="{
-            cursor: !jigsawProgressSceneL2.isJigsawDone && jigsawItem.hasGot && !jigsawItem.hasPut ? 'grab' : 'default',
+            cursor: !jigsawProgressSceneL2.isJigsawDone && !jigsawItem.hasPut ? 'grab' : 'default',
           }"
-          :src="require(`@/assets/images/jigsaw-game-${$route.query.sceneL2Idx}/jigsaw${jigsawItem.hasGot ? '' : '-shade'}/${jigsawItem.name}`)"
+          :src="require(`@/assets/images/jigsaw-game-${$route.query.sceneL2Idx}/jigsaw/${jigsawItem.name}`)"
           alt=""
-          :draggable="!jigsawProgressSceneL2.isJigsawDone && jigsawItem.hasGot && !jigsawItem.hasPut ? true : false"
+          :draggable="!jigsawProgressSceneL2.isJigsawDone && !jigsawItem.hasPut ? true : false"
           @dragstart="(e) => {
             onDragStart(e, jigsawItem.name, idx)
           }"
@@ -85,7 +85,7 @@ export default {
   },
   data() {
     return {
-      jigsawItemsFlatten: [],
+      jigsawItems: [],
       leftForDrop: 0,
       topForDrop: 0,
       widthForDrop: 0,
@@ -102,22 +102,7 @@ export default {
     },
   },
   mounted() {
-    for (const jigsawProgressSceneL3 of this.jigsawProgressSceneL2.children) {
-      for (const jigsawItem of jigsawProgressSceneL3.jigsawList) {
-        this.jigsawItemsFlatten.push({
-          name: jigsawItem,
-          hasGot: jigsawProgressSceneL3.hasGotJigsaw,
-          hasPut: false,
-        })
-      }
-      this.jigsawItemsFlatten = shuffle(this.jigsawItemsFlatten)
-    }
-    setTimeout(() => {
-      console.log('进入timeout!')
-      if (!this.jigsawProgressSceneL2.isJigsawDone) {
-        this.hideAllInSvg()
-      }
-    }, 300)
+    this.resetStatus()
   },
   unmounted() {
   },
@@ -126,6 +111,19 @@ export default {
       'recordJigsawDone',
       'replayJigsaw',
     ]),
+    resetStatus() {
+      this.jigsawItems = shuffle(config.sceneTree[Number(this.$route.query.sceneL2Idx)].jigsawList.map((item) => {
+        return {
+          name: item,
+          hasPut: false,
+        }
+      }))
+      setTimeout(() => {
+        if (!this.jigsawProgressSceneL2.isJigsawDone) {
+          this.hideAllInSvg()
+        }
+      }, 300)
+    },
     hideAllInSvg() {
       const objectDocument = this.$refs.svgContainer.contentDocument
       const gList = objectDocument.getElementsByTagName('g')
@@ -236,9 +234,9 @@ export default {
       objectDocument.getElementById(id).setAttribute('visibility', 'show')
 
       const idx = Number(e.dataTransfer.getData('text/html'))
-      this.jigsawItemsFlatten[idx].hasPut = true
+      this.jigsawItems[idx].hasPut = true
 
-      if (!this.jigsawItemsFlatten.find((item) => {
+      if (!this.jigsawItems.find((item) => {
         return !item.hasPut
       })) {
         ElMessageBox.alert('', '拼图完成!', {
@@ -254,10 +252,10 @@ export default {
       e.preventDefault()
     },
     onClickReplay() {
-      this.jigsawItemsFlatten.forEach(element => {
+      this.jigsawItems.forEach(element => {
         element.hasPut = false
       })
-      this.hideAllInSvg()
+      this.resetStatus()
       this.replayJigsaw(Number(this.$route.query.sceneL2Idx))
     }
   },

+ 19 - 0
src/views/Learn.vue

@@ -21,6 +21,7 @@
         width: videoWidth + 'px',
         height: videoHeight + 'px',
       }"
+      @timeupdate="onTimeUpdate"
     />
   </div>
 </template>
@@ -28,6 +29,8 @@
 <script>
 import { onMounted, onUnmounted, watch, ref, reactive, computed } from "vue"
 import GameRule from "@/components/GameRule.vue"
+import { useStore } from "vuex"
+import { useRoute, useRouter } from "vue-router"
 
 export default {
   name: 'HomeView',
@@ -35,6 +38,10 @@ export default {
     GameRule,
   },
   setup() {
+    const store = useStore()
+    const route = useRoute()
+    const router = useRouter()
+
     const videoLeft = ref(0)
     const videoTop = ref(0)
     const videoWidth = ref(0)
@@ -63,11 +70,23 @@ export default {
       window.removeEventListener('resize', computeVideoPos)
     })
 
+    const video = ref(null)
+    const onTimeUpdate = utils.throttle((e) => {
+      store.commit('recordLearnProgress', {
+        sceneL2Id: Number(route.query.sceneIdxLevel2),
+        sceneL3Id: Number(route.query.sceneIdxLevel3),
+        timeIdx: Math.floor(video.value.currentTime / ( video.value.duration / 10)),
+      })
+    }, 1000)
+
     return {
       videoLeft,
       videoTop,
       videoWidth,
       videoHeight,
+
+      onTimeUpdate,
+      video,
     }
   },
   data() {

+ 83 - 15
src/views/Level3.vue

@@ -46,7 +46,7 @@
         query: $route.query,
       })"
     />
-    <transition name="fade-in">
+    <transition name="fade-in-out">
       <div
         v-show="isShowLion"
         class="lion-wrapper"
@@ -54,27 +54,38 @@
         <img
           v-click-audio
           class="lion"
-          :src="require(`@/assets/images/lion-${sceneInfo.lionGender}-speaking.gif`)"
+          :src="require(`@/assets/images/lion-${sceneInfo.lionGender}-${isLionSpeeking ? 'speaking' : 'idle'}.gif`)"
           alt=""
           draggable="false"
           @click="onClickLion"
         >
-        <transition name="fade-in">
+        <transition name="fade-in-out">
           <div
             v-show="isLionSpeeking"
             class="speach-text-wrapper"
           >
-            <div class="speach-text">
-              {{ lionSpeachText }}
+            <div
+              class="speach-text"
+            >
+              {{ lionSpeachTextList[currentSpeachTextIdx]?.content }}
+              <div
+                v-show="isSpeachTextChanging"
+                class="mask"
+                :class="{
+                  active: isSpeachTextChanging,
+                }"
+              />
             </div>
           </div>
         </transition>
       </div>
     </transition>
     <audio
-      v-if="lionSpeachText"
-      ref="lionSpeachEl"
+      v-if="lionSpeachTextList"
+      ref="lionSpeachAudio"
       :src="require(`@/assets/audios/lionSpeach-${$route.query.sceneIdxLevel2}-${$route.query.sceneIdxLevel3}.mp3`)"
+      @ended="onAudioEnd"
+      @timeupdate="onAudioTimeUpdate"
     />
   </div>
 </template>
@@ -85,6 +96,7 @@ import {
   onBeforeUnmount,
   onMounted,
   onUnmounted,
+  reactive,
   ref,
   watch,
 } from 'vue'
@@ -125,26 +137,61 @@ export default {
       }
     }
 
-    const lionSpeachEl = ref(null)
+    const lionSpeachAudio = ref(null)
     watch(isLionSpeeking, (vNew) => {
       if (vNew) {
-        lionSpeachEl.value && lionSpeachEl.value.play()
+        lionSpeachAudio.value && lionSpeachAudio.value.play()
       }
     })
     onBeforeUnmount(() => {
-      lionSpeachEl.value && lionSpeachEl.value.pause()
+      lionSpeachAudio.value && lionSpeachAudio.value.pause()
     })
 
-    const lionSpeachText = config.sceneTree[route.query.sceneIdxLevel2].children[route.query.sceneIdxLevel3].lionSpeach
+    const lionSpeachTextList = reactive([
+      {
+        startTime: 0,
+        endTime: 9,
+        content: '当我们来到徽州,总能看见许许多多门洞形状的建筑物,它就是“徽州三绝”之一的牌坊。',
+      },
+      {
+        startTime: 9,
+        endTime: Infinity,
+        content: '徽州因为拥有的牌坊数量众多,样式精美,也被誉为“牌坊之乡”。',
+      },
+    ])
+    const currentSpeachTextIdx = ref(null)
+    function onAudioEnd() {
+      isLionSpeeking.value = false
+    }
+    const isSpeachTextChanging = ref(false)
+    watch(currentSpeachTextIdx, (vNew) => {
+      isSpeachTextChanging.value = true
+      setTimeout(() => {
+        isSpeachTextChanging.value = false
+      }, 3000, { immediate: true })
+    })
+    const onAudioTimeUpdate = utils.throttle(() => {
+      console.log(lionSpeachAudio.value.currentTime)
+      for (let index = 0; index < lionSpeachTextList.length; index++) {
+        const lionSpeachTextItem = lionSpeachTextList[index]
+        if (lionSpeachTextItem.startTime <= lionSpeachAudio.value.currentTime && lionSpeachTextItem.endTime >= lionSpeachAudio.value.currentTime) {
+          currentSpeachTextIdx.value = index
+        }
+      }
+    }, 1000)
 
     return {
       isLionSpeeking,
       isShowLion,
-      lionSpeachEl,
-      lionSpeachText,
+      lionSpeachAudio,
+      lionSpeachTextList,
       onClickLion,
       unit,
       windowSizeWhenDesign,
+      onAudioEnd,
+      onAudioTimeUpdate,
+      currentSpeachTextIdx,
+      isSpeachTextChanging,
     }
   },
   data() {
@@ -304,15 +351,36 @@ export default {
       padding-bottom: calc(210 / v-bind('windowSizeWhenDesign') * v-bind('unit'));
       >.speach-text {
         height: 100%;
-        font-size: calc(16 / v-bind('windowSizeWhenDesign') * v-bind('unit'));
+        font-size: calc(20 / v-bind('windowSizeWhenDesign') * v-bind('unit'));
         line-height: 1.3;
         font-family: Source Han Sans CN-Regular, Source Han Sans CN;
         font-weight: 400;
         color: #2D241D;
-        overflow: auto;
+        overflow-y: auto;
         padding-right: calc(8 / v-bind('windowSizeWhenDesign') * v-bind('unit'));
+        position: relative;
+        overflow-x: hidden;
+        >.mask{
+          position: absolute;
+          left: -100%;
+          top: 0;
+          width: 200%;
+          height: 100%;
+          background: linear-gradient(90deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1) 30%);
+          &.active {
+            animation: changeSpeachText 2s linear forwards;
+          }
+        }
       }
     }
   }
 }
+@keyframes changeSpeachText {
+  0% {
+    left: -100%;
+  }
+  100% {
+    left: 100%;
+  }
+}
 </style>

+ 18 - 0
src/views/Watch.vue

@@ -21,6 +21,7 @@
         width: videoWidth + 'px',
         height: videoHeight + 'px',
       }"
+      @timeupdate="onTimeUpdate"
     />
     <!-- <div
       v-show="hasPlayedGameRule"
@@ -55,6 +56,8 @@
 <script>
 import { onMounted, onUnmounted, watch, ref, reactive, computed } from "vue"
 import GameRule from "@/components/GameRule.vue"
+import { useStore } from "vuex"
+import { useRoute, useRouter } from "vue-router"
 
 export default {
   name: 'HomeView',
@@ -62,6 +65,10 @@ export default {
     GameRule,
   },
   setup() {
+    const store = useStore()
+    const route = useRoute()
+    const router = useRouter()
+
     const videoLeft = ref(0)
     const videoTop = ref(0)
     const videoWidth = ref(0)
@@ -117,6 +124,14 @@ export default {
     // onUnmounted(() => {
     //   window.removeEventListener('resize', computeBagPos)
     // })
+    const video = ref(null)
+    const onTimeUpdate = utils.throttle((e) => {
+      store.commit('recordWatchProgress', {
+        sceneL2Id: Number(route.query.sceneIdxLevel2),
+        sceneL3Id: Number(route.query.sceneIdxLevel3),
+        timeIdx: Math.floor(video.value.currentTime / ( video.value.duration / 10)),
+      })
+    }, 1000)
 
     return {
       videoLeft,
@@ -128,6 +143,9 @@ export default {
       // BagTop,
       // BagWidth,
       // BagHeight,
+
+      onTimeUpdate,
+      video,
     }
   },
   data() {