Преглед изворни кода

Merge remote-tracking branch 'origin/iteration-beat-one' into fix-tianyong

TIANYONG пре 1 година
родитељ
комит
a1d038b16b
96 измењених фајлова са 3068 додато и 445 уклоњено
  1. 0 0
      dist/assets/colexiu-18824128.js
  2. 0 0
      dist/assets/colexiu-legacy-0693bbb6.js
  3. 1 1
      dist/assets/index-051a2696.js
  4. 1 1
      dist/assets/index-334864c1.js
  5. 0 0
      dist/assets/index-56035035.js
  6. 0 0
      dist/assets/index-63b74402.js
  7. 0 0
      dist/assets/index-6dd30b57.js
  8. 0 0
      dist/assets/index-7969f8d1.js
  9. 0 0
      dist/assets/index-8d0c5318.js
  10. 0 0
      dist/assets/index-9786dc5b.js
  11. 0 0
      dist/assets/index-dc164a6b.js
  12. 0 0
      dist/assets/index-legacy-0c1cc0b7.js
  13. 0 0
      dist/assets/index-legacy-1c0667ff.js
  14. 0 0
      dist/assets/index-legacy-24d3f120.js
  15. 0 0
      dist/assets/index-legacy-2ed585d3.js
  16. 1 1
      dist/assets/index-legacy-5559ad07.js
  17. 1 1
      dist/assets/index-legacy-6f5f556a.js
  18. 0 0
      dist/assets/index-legacy-8caa9b53.js
  19. 0 0
      dist/assets/index-legacy-9e1b2595.js
  20. 0 0
      dist/assets/index-legacy-ec1acfaf.js
  21. 0 0
      dist/assets/instrument-24439d7a.js
  22. 0 0
      dist/assets/instrument-legacy-f8f6acb9.js
  23. 0 0
      dist/assets/instruments-f1fe233a.js
  24. 0 0
      dist/assets/instruments-legacy-f1e5a529.js
  25. 0 0
      dist/assets/orchestra-14d8628e.js
  26. 0 0
      dist/assets/orchestra-legacy-36154a95.js
  27. 0 0
      dist/assets/report-share-fec82787.js
  28. 0 0
      dist/assets/report-share-legacy-db5c1da8.js
  29. 0 0
      dist/assets/vue3-lottie.es-0041314e.js
  30. 0 0
      dist/assets/vue3-lottie.es-legacy-87cfe209.js
  31. 6 6
      dist/colexiu.html
  32. 7 7
      dist/index.html
  33. 7 7
      dist/instrument.html
  34. 8 8
      dist/orchestra.html
  35. 3 3
      dist/report-share.html
  36. BIN
      images/full1.png
  37. 1 0
      images/index.json
  38. 25 15
      src/page-instrument/api.ts
  39. 37 34
      src/page-instrument/router.ts
  40. 19 0
      src/page-instrument/view-figner-listen/guide/detail-guide.tsx
  41. 107 0
      src/page-instrument/view-figner-listen/guide/finger-guide.tsx
  42. 69 0
      src/page-instrument/view-figner-listen/guide/guide-index.tsx
  43. BIN
      src/page-instrument/view-figner-listen/guide/image/icon_detail.png
  44. 1 0
      src/page-instrument/view-figner-listen/guide/image/icons.json
  45. 135 0
      src/page-instrument/view-figner-listen/guide/index.module.less
  46. BIN
      src/page-instrument/view-figner-listen/image/icon_action_cancel.png
  47. BIN
      src/page-instrument/view-figner-listen/image/icon_action_confirm.png
  48. BIN
      src/page-instrument/view-figner-listen/image/icon_bg_t.png
  49. BIN
      src/page-instrument/view-figner-listen/image/icon_bg_v.png
  50. BIN
      src/page-instrument/view-figner-listen/image/icon_btn_1.png
  51. BIN
      src/page-instrument/view-figner-listen/image/icon_btn_2.png
  52. BIN
      src/page-instrument/view-figner-listen/image/icon_btn_3.png
  53. BIN
      src/page-instrument/view-figner-listen/image/icon_btn_4.png
  54. BIN
      src/page-instrument/view-figner-listen/image/icon_btn_green_sub.png
  55. BIN
      src/page-instrument/view-figner-listen/image/icon_btn_red_sub.png
  56. BIN
      src/page-instrument/view-figner-listen/image/icon_loading_head.png
  57. BIN
      src/page-instrument/view-figner-listen/image/icon_loading_img.png
  58. BIN
      src/page-instrument/view-figner-listen/image/icon_popup_book.png
  59. BIN
      src/page-instrument/view-figner-listen/image/icon_popup_book_h.png
  60. BIN
      src/page-instrument/view-figner-listen/image/icon_popup_book_v.png
  61. BIN
      src/page-instrument/view-figner-listen/image/icon_popup_top.png
  62. BIN
      src/page-instrument/view-figner-listen/image/icon_shadow_left.png
  63. BIN
      src/page-instrument/view-figner-listen/image/icon_shadow_r.png
  64. BIN
      src/page-instrument/view-figner-listen/image/icon_shuo_h.png
  65. BIN
      src/page-instrument/view-figner-listen/image/icon_shuo_v.png
  66. BIN
      src/page-instrument/view-figner-listen/image/icon_trans_bg.png
  67. BIN
      src/page-instrument/view-figner-listen/image/icon_trans_bg_hu.png
  68. 3 0
      src/page-instrument/view-figner-listen/image/icons.json
  69. 1037 0
      src/page-instrument/view-figner-listen/index.module.less
  70. 1060 0
      src/page-instrument/view-figner-listen/index.tsx
  71. BIN
      src/page-instrument/view-figner-listen/lsy.ttf
  72. BIN
      src/page-instrument/view-figner/image/icon_btn_1.png
  73. BIN
      src/page-instrument/view-figner/image/icon_btn_2.png
  74. BIN
      src/page-instrument/view-figner/image/icon_btn_3.png
  75. BIN
      src/page-instrument/view-figner/image/icon_btn_4.png
  76. BIN
      src/page-instrument/view-figner/image/icon_btn_green_sub.png
  77. BIN
      src/page-instrument/view-figner/image/icon_btn_red_sub.png
  78. 0 0
      src/page-instrument/view-figner/image/icons.json
  79. BIN
      src/page-instrument/view-figner/image/tips1.png
  80. BIN
      src/page-instrument/view-figner/image/tips2.png
  81. BIN
      src/page-instrument/view-figner/image/tips3.png
  82. BIN
      src/page-instrument/view-figner/image/tips4.png
  83. 181 17
      src/page-instrument/view-figner/index.module.less
  84. 40 39
      src/store.ts
  85. 3 0
      src/view/figner-preview/index.ts
  86. 313 305
      src/view/fingering/fingering-config.ts
  87. 0 0
      src/view/fingering/fingering-img/hulusi-flute/index.json
  88. 0 0
      src/view/fingering/fingering-img/hulusi-flute1/index.json
  89. 0 0
      src/view/fingering/fingering-img/melodica/index.json
  90. 1 0
      src/view/fingering/fingering-img/melodica1/index.json
  91. 0 0
      src/view/fingering/fingering-img/ocarina1/index.json
  92. 0 0
      src/view/fingering/fingering-img/pan-flute/index.json
  93. 0 0
      src/view/fingering/fingering-img/pan-flute1/index.json
  94. 1 0
      src/view/fingering/fingering-img/pan-flute3/index.json
  95. 0 0
      src/view/fingering/fingering-img/piccolo/index.json
  96. 0 0
      src/view/fingering/fingering-img/piccolo1/index.json

Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/colexiu-18824128.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/colexiu-legacy-0693bbb6.js


+ 1 - 1
dist/assets/index-35c5f154.js → dist/assets/index-051a2696.js

@@ -1 +1 @@
-import{d,l as i,n as p,m as e,w as o,J as a,f as r}from"./index-0dbc5171.js";const c=d({name:"measureSpeed",setup(){const s=i(!1),t=p({speed:e.speed,originSpeed:e.originSpeed});return o(()=>e.section.length,()=>{if(e.modeType==="practise"){if(!s.value&&e.section.length===2){s.value=!0,t.speed=e.speed;const n=e.section[0].beatSpeed;e.originSpeed=n,a(n)}s.value&&e.section.length===0&&(s.value=!1,e.originSpeed=t.originSpeed,a(t.speed))}}),()=>r("div",null,null)}});export{c as M};
+import{d,l as i,n as p,m as e,w as o,J as a,f as r}from"./index-56035035.js";const c=d({name:"measureSpeed",setup(){const s=i(!1),t=p({speed:e.speed,originSpeed:e.originSpeed});return o(()=>e.section.length,()=>{if(e.modeType==="practise"){if(!s.value&&e.section.length===2){s.value=!0,t.speed=e.speed;const n=e.section[0].beatSpeed;e.originSpeed=n,a(n)}s.value&&e.section.length===0&&(s.value=!1,e.originSpeed=t.originSpeed,a(t.speed))}}),()=>r("div",null,null)}});export{c as M};

+ 1 - 1
dist/assets/index-2b0159b2.js → dist/assets/index-334864c1.js

@@ -1 +1 @@
-import{d as i,g as l,n as d,bb as e,c,m as r,f as s,aj as u}from"./index-0dbc5171.js";const f="_skeleton_vtlsh_1",m="_detail_vtlsh_12",p="_container_vtlsh_20",a={skeleton:f,detail:m,container:p},y=i({name:"music-list",setup(){const n=l(),t=d({isLoading:!0,isProductLoading:!1,product:[{state:!1,name:"五线谱",type:e.staff,base64:""},{state:!1,name:"首调",type:e.firstTone,base64:""},{state:!1,name:"固定调",type:e.fixedTone,base64:""}]});c(()=>{window.appName="colexiu",r.xmlUrl=n.xmlUrl,t.isLoading=!1});const o=async()=>{console.log("渲染完成")};return()=>s("div",{class:a.detail},[s("div",{id:"scrollContainer",class:[a.container,"hideCursor"]},[!t.isLoading&&s(u,{onRendered:o},null)])])}});export{y as default};
+import{d as i,g as l,n as d,bb as e,c,m as r,f as s,aj as u}from"./index-56035035.js";const f="_skeleton_vtlsh_1",m="_detail_vtlsh_12",p="_container_vtlsh_20",a={skeleton:f,detail:m,container:p},y=i({name:"music-list",setup(){const n=l(),t=d({isLoading:!0,isProductLoading:!1,product:[{state:!1,name:"五线谱",type:e.staff,base64:""},{state:!1,name:"首调",type:e.firstTone,base64:""},{state:!1,name:"固定调",type:e.fixedTone,base64:""}]});c(()=>{window.appName="colexiu",r.xmlUrl=n.xmlUrl,t.isLoading=!1});const o=async()=>{console.log("渲染完成")};return()=>s("div",{class:a.detail},[s("div",{id:"scrollContainer",class:[a.container,"hideCursor"]},[!t.isLoading&&s(u,{onRendered:o},null)])])}});export{y as default};

Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/index-56035035.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/index-63b74402.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/index-6dd30b57.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/index-7969f8d1.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/index-8d0c5318.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/index-9786dc5b.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/index-dc164a6b.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/index-legacy-0c1cc0b7.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/index-legacy-1c0667ff.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/index-legacy-24d3f120.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/index-legacy-2ed585d3.js


+ 1 - 1
dist/assets/index-legacy-b8f7e45b.js → dist/assets/index-legacy-5559ad07.js

@@ -1 +1 @@
-System.register(["./index-legacy-c08dba1e.js"],(function(e,n){"use strict";var i,t,s,d,r,p,o;return{setters:[e=>{i=e.d,t=e.l,s=e.n,d=e.m,r=e.w,p=e.J,o=e.f}],execute:function(){e("M",i({name:"measureSpeed",setup(){const e=t(!1),n=s({speed:d.speed,originSpeed:d.originSpeed});return r((()=>d.section.length),(()=>{if("practise"===d.modeType){if(!e.value&&2===d.section.length){e.value=!0,n.speed=d.speed;const i=d.section[0].beatSpeed;d.originSpeed=i,p(i)}e.value&&0===d.section.length&&(e.value=!1,d.originSpeed=n.originSpeed,p(n.speed))}})),()=>o("div",null,null)}}))}}}));
+System.register(["./index-legacy-8caa9b53.js"],(function(e,n){"use strict";var i,t,s,d,r,p,o;return{setters:[e=>{i=e.d,t=e.l,s=e.n,d=e.m,r=e.w,p=e.J,o=e.f}],execute:function(){e("M",i({name:"measureSpeed",setup(){const e=t(!1),n=s({speed:d.speed,originSpeed:d.originSpeed});return r((()=>d.section.length),(()=>{if("practise"===d.modeType){if(!e.value&&2===d.section.length){e.value=!0,n.speed=d.speed;const i=d.section[0].beatSpeed;d.originSpeed=i,p(i)}e.value&&0===d.section.length&&(e.value=!1,d.originSpeed=n.originSpeed,p(n.speed))}})),()=>o("div",null,null)}}))}}}));

+ 1 - 1
dist/assets/index-legacy-1e25738e.js → dist/assets/index-legacy-6f5f556a.js

@@ -1 +1 @@
-System.register(["./index-legacy-c08dba1e.js"],(function(e,t){"use strict";var i,n,a,o,r,s,d,l;return{setters:[e=>{i=e.d,n=e.g,a=e.n,o=e.bb,r=e.c,s=e.m,d=e.f,l=e.aj}],execute:function(){var t=document.createElement("style");t.textContent="._skeleton_vtlsh_1{position:fixed;left:0;top:0;width:100vw;height:100vh;padding:.53333rem .8rem;background-color:#fff;z-index:1000;--van-skeleton-paragraph-height: .8rem}._detail_vtlsh_12{width:100vw;height:100vh;overflow:hidden;overflow-y:auto;--header-height: 1.65333rem;background:var(--container-background)}._detail_vtlsh_12 ._container_vtlsh_20{margin:0 .26667rem;border-radius:.26667rem}._detail_vtlsh_12 #musicAndSelection{overflow:initial!important;height:initial!important;max-height:initial!important}\n",document.head.appendChild(t);const c="_detail_vtlsh_12",h="_container_vtlsh_20";e("default",i({name:"music-list",setup(){const e=n(),t=a({isLoading:!0,isProductLoading:!1,product:[{state:!1,name:"五线谱",type:o.staff,base64:""},{state:!1,name:"首调",type:o.firstTone,base64:""},{state:!1,name:"固定调",type:o.fixedTone,base64:""}]});r((()=>{window.appName="colexiu",s.xmlUrl=e.xmlUrl,t.isLoading=!1}));const i=async()=>{console.log("渲染完成")};return()=>d("div",{class:c},[d("div",{id:"scrollContainer",class:[h,"hideCursor"]},[!t.isLoading&&d(l,{onRendered:i},null)])])}}))}}}));
+System.register(["./index-legacy-8caa9b53.js"],(function(e,t){"use strict";var i,n,a,o,r,s,d,l;return{setters:[e=>{i=e.d,n=e.g,a=e.n,o=e.bb,r=e.c,s=e.m,d=e.f,l=e.aj}],execute:function(){var t=document.createElement("style");t.textContent="._skeleton_vtlsh_1{position:fixed;left:0;top:0;width:100vw;height:100vh;padding:.53333rem .8rem;background-color:#fff;z-index:1000;--van-skeleton-paragraph-height: .8rem}._detail_vtlsh_12{width:100vw;height:100vh;overflow:hidden;overflow-y:auto;--header-height: 1.65333rem;background:var(--container-background)}._detail_vtlsh_12 ._container_vtlsh_20{margin:0 .26667rem;border-radius:.26667rem}._detail_vtlsh_12 #musicAndSelection{overflow:initial!important;height:initial!important;max-height:initial!important}\n",document.head.appendChild(t);const c="_detail_vtlsh_12",h="_container_vtlsh_20";e("default",i({name:"music-list",setup(){const e=n(),t=a({isLoading:!0,isProductLoading:!1,product:[{state:!1,name:"五线谱",type:o.staff,base64:""},{state:!1,name:"首调",type:o.firstTone,base64:""},{state:!1,name:"固定调",type:o.fixedTone,base64:""}]});r((()=>{window.appName="colexiu",s.xmlUrl=e.xmlUrl,t.isLoading=!1}));const i=async()=>{console.log("渲染完成")};return()=>d("div",{class:c},[d("div",{id:"scrollContainer",class:[h,"hideCursor"]},[!t.isLoading&&d(l,{onRendered:i},null)])])}}))}}}));

Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/index-legacy-8caa9b53.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/index-legacy-9e1b2595.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/index-legacy-ec1acfaf.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/instrument-24439d7a.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/instrument-legacy-f8f6acb9.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/instruments-f1fe233a.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/instruments-legacy-f1e5a529.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/orchestra-14d8628e.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/orchestra-legacy-36154a95.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/report-share-fec82787.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/report-share-legacy-db5c1da8.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/vue3-lottie.es-0041314e.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/assets/vue3-lottie.es-legacy-87cfe209.js


+ 6 - 6
dist/colexiu.html

@@ -40,11 +40,11 @@
       },
     })
   </script>
-  <script type="module" crossorigin src="./assets/colexiu-8a261766.js"></script>
-  <link rel="modulepreload" crossorigin href="./assets/index-0dbc5171.js">
-  <link rel="modulepreload" crossorigin href="./assets/index-67f9671e.js">
-  <link rel="modulepreload" crossorigin href="./assets/vue3-lottie.es-e8dd1803.js">
-  <link rel="modulepreload" crossorigin href="./assets/index-35c5f154.js">
+  <script type="module" crossorigin src="./assets/colexiu-18824128.js"></script>
+  <link rel="modulepreload" crossorigin href="./assets/index-56035035.js">
+  <link rel="modulepreload" crossorigin href="./assets/index-63b74402.js">
+  <link rel="modulepreload" crossorigin href="./assets/vue3-lottie.es-0041314e.js">
+  <link rel="modulepreload" crossorigin href="./assets/index-051a2696.js">
   <link rel="stylesheet" href="./assets/index-50691166.css">
   <link rel="stylesheet" href="./assets/index-cc0254c0.css">
   <link rel="stylesheet" href="./assets/colexiu-4a62fa3a.css">
@@ -58,7 +58,7 @@
   
   <script nomodule>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
   <script nomodule crossorigin id="vite-legacy-polyfill" src="./assets/polyfills-legacy-23f2ea46.js"></script>
-  <script nomodule crossorigin id="vite-legacy-entry" data-src="./assets/colexiu-legacy-d145bb2c.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
+  <script nomodule crossorigin id="vite-legacy-entry" data-src="./assets/colexiu-legacy-0693bbb6.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
 </body>
 
 </html>

+ 7 - 7
dist/index.html

@@ -75,12 +75,12 @@
       }
     })
   </script>
-  <script type="module" crossorigin src="./assets/index-b9e226a1.js"></script>
-  <link rel="modulepreload" crossorigin href="./assets/index-0dbc5171.js">
-  <link rel="modulepreload" crossorigin href="./assets/index-67f9671e.js">
-  <link rel="modulepreload" crossorigin href="./assets/instruments-a3925dcf.js">
-  <link rel="modulepreload" crossorigin href="./assets/index-a67667d8.js">
-  <link rel="modulepreload" crossorigin href="./assets/index-35c5f154.js">
+  <script type="module" crossorigin src="./assets/index-dc164a6b.js"></script>
+  <link rel="modulepreload" crossorigin href="./assets/index-56035035.js">
+  <link rel="modulepreload" crossorigin href="./assets/index-63b74402.js">
+  <link rel="modulepreload" crossorigin href="./assets/instruments-f1fe233a.js">
+  <link rel="modulepreload" crossorigin href="./assets/index-6dd30b57.js">
+  <link rel="modulepreload" crossorigin href="./assets/index-051a2696.js">
   <link rel="modulepreload" crossorigin href="./assets/plyr.min-ade72a33.js">
   <link rel="stylesheet" href="./assets/index-50691166.css">
   <link rel="stylesheet" href="./assets/index-cc0254c0.css">
@@ -101,7 +101,7 @@
   
   <script nomodule>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
   <script nomodule crossorigin id="vite-legacy-polyfill" src="./assets/polyfills-legacy-23f2ea46.js"></script>
-  <script nomodule crossorigin id="vite-legacy-entry" data-src="./assets/index-legacy-03e1f82d.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
+  <script nomodule crossorigin id="vite-legacy-entry" data-src="./assets/index-legacy-2ed585d3.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
 </body>
 
 </html>

+ 7 - 7
dist/instrument.html

@@ -42,12 +42,12 @@
     }
 
   </script>
-  <script type="module" crossorigin src="./assets/instrument-7661ddc0.js"></script>
-  <link rel="modulepreload" crossorigin href="./assets/index-0dbc5171.js">
-  <link rel="modulepreload" crossorigin href="./assets/vue3-lottie.es-e8dd1803.js">
-  <link rel="modulepreload" crossorigin href="./assets/index-67f9671e.js">
-  <link rel="modulepreload" crossorigin href="./assets/index-ad825f6b.js">
-  <link rel="modulepreload" crossorigin href="./assets/instruments-a3925dcf.js">
+  <script type="module" crossorigin src="./assets/instrument-24439d7a.js"></script>
+  <link rel="modulepreload" crossorigin href="./assets/index-56035035.js">
+  <link rel="modulepreload" crossorigin href="./assets/vue3-lottie.es-0041314e.js">
+  <link rel="modulepreload" crossorigin href="./assets/index-63b74402.js">
+  <link rel="modulepreload" crossorigin href="./assets/index-8d0c5318.js">
+  <link rel="modulepreload" crossorigin href="./assets/instruments-f1fe233a.js">
   <link rel="stylesheet" href="./assets/index-50691166.css">
   <link rel="stylesheet" href="./assets/index-cc0254c0.css">
   <link rel="stylesheet" href="./assets/instrument-6fcc9d8d.css">
@@ -61,7 +61,7 @@
   
   <script nomodule>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
   <script nomodule crossorigin id="vite-legacy-polyfill" src="./assets/polyfills-legacy-23f2ea46.js"></script>
-  <script nomodule crossorigin id="vite-legacy-entry" data-src="./assets/instrument-legacy-9b0a8186.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
+  <script nomodule crossorigin id="vite-legacy-entry" data-src="./assets/instrument-legacy-f8f6acb9.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
 </body>
 
 </html>

+ 8 - 8
dist/orchestra.html

@@ -41,13 +41,13 @@
       transition: opacity .3s;
     }
   </style>
-  <script type="module" crossorigin src="./assets/orchestra-180ec01c.js"></script>
-  <link rel="modulepreload" crossorigin href="./assets/index-0dbc5171.js">
-  <link rel="modulepreload" crossorigin href="./assets/index-67f9671e.js">
-  <link rel="modulepreload" crossorigin href="./assets/vue3-lottie.es-e8dd1803.js">
-  <link rel="modulepreload" crossorigin href="./assets/index-a67667d8.js">
-  <link rel="modulepreload" crossorigin href="./assets/index-35c5f154.js">
-  <link rel="modulepreload" crossorigin href="./assets/index-ad825f6b.js">
+  <script type="module" crossorigin src="./assets/orchestra-14d8628e.js"></script>
+  <link rel="modulepreload" crossorigin href="./assets/index-56035035.js">
+  <link rel="modulepreload" crossorigin href="./assets/index-63b74402.js">
+  <link rel="modulepreload" crossorigin href="./assets/vue3-lottie.es-0041314e.js">
+  <link rel="modulepreload" crossorigin href="./assets/index-6dd30b57.js">
+  <link rel="modulepreload" crossorigin href="./assets/index-051a2696.js">
+  <link rel="modulepreload" crossorigin href="./assets/index-8d0c5318.js">
   <link rel="stylesheet" href="./assets/index-50691166.css">
   <link rel="stylesheet" href="./assets/index-cc0254c0.css">
   <link rel="stylesheet" href="./assets/index-85f95688.css">
@@ -73,7 +73,7 @@
   
   <script nomodule>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
   <script nomodule crossorigin id="vite-legacy-polyfill" src="./assets/polyfills-legacy-23f2ea46.js"></script>
-  <script nomodule crossorigin id="vite-legacy-entry" data-src="./assets/orchestra-legacy-e8e4293b.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
+  <script nomodule crossorigin id="vite-legacy-entry" data-src="./assets/orchestra-legacy-36154a95.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
 </body>
 
 </html>

+ 3 - 3
dist/report-share.html

@@ -25,8 +25,8 @@
       transition: opacity .3s;
     }
   </style>
-  <script type="module" crossorigin src="./assets/report-share-1bd1fd46.js"></script>
-  <link rel="modulepreload" crossorigin href="./assets/index-0dbc5171.js">
+  <script type="module" crossorigin src="./assets/report-share-fec82787.js"></script>
+  <link rel="modulepreload" crossorigin href="./assets/index-56035035.js">
   <link rel="modulepreload" crossorigin href="./assets/plyr.min-ade72a33.js">
   <link rel="stylesheet" href="./assets/index-50691166.css">
   <link rel="stylesheet" href="./assets/plyr-aeb30ba4.css">
@@ -52,7 +52,7 @@
   
   <script nomodule>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
   <script nomodule crossorigin id="vite-legacy-polyfill" src="./assets/polyfills-legacy-23f2ea46.js"></script>
-  <script nomodule crossorigin id="vite-legacy-entry" data-src="./assets/report-share-legacy-92d703cd.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
+  <script nomodule crossorigin id="vite-legacy-entry" data-src="./assets/report-share-legacy-db5c1da8.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
 </body>
 
 </html>


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
images/index.json


+ 25 - 15
src/page-instrument/api.ts

@@ -2,47 +2,57 @@ import request from "../utils/request";
 
 /** 获取用户信息 */
 export const studentQueryUserInfo = async () => {
-	return await request.get(`/user/getUserInfo`);
+  return await request.get(`/user/getUserInfo`);
 };
 
 /** 获取曲谱详情 */
 export const sysMusicScoreAccompanimentQueryPage = (sysMusicScoreId: string) => {
-	return request.get("/musicSheet/detail/" + sysMusicScoreId);
+  return request.get("/musicSheet/detail/" + sysMusicScoreId);
 };
 
 /** 新增练习记录(包含评测) */
 export const api_musicPracticeRecordSave = (data: any) => {
-	return request.post("/musicPracticeRecord/save", { requestType: "json", data });
+  return request.post("/musicPracticeRecord/save", { requestType: "json", data });
 };
 /** 添加作业记录 */
 export const api_lessonTrainingSubmitTraining = (data: any) => {
-	return request.post("/lessonTraining/submitTraining", { requestType: "json", data });
+  return request.post("/lessonTraining/submitTraining", { requestType: "json", data });
 };
 /** 获取作业详情 */
 export const api_lessonTrainingTrainingStudentDetail = (id: any) => {
-	return request.get(`/lessonTraining/trainingContentStudentDetail?id=${id}`);
+  return request.get(`/lessonTraining/trainingContentStudentDetail?id=${id}`);
 };
 /** 上传评测视频 */
 export const api_musicPracticeRecordVideoUpload = (data: any) => {
-	return request.post(`/musicPracticeRecord/videoUpload`, {
-		data,
-		requestType: "json",
-	});
+  return request.post(`/musicPracticeRecord/videoUpload`, {
+    data,
+    requestType: "json",
+  });
 };
 
 /** 提交意见反馈 */
 export const sysSuggestionAdd = (data: any) => {
-	return request.post("/sysSuggestion/save", { data, requestType: "json" });
+  return request.post("/sysSuggestion/save", { data, requestType: "json" });
 };
 
 /** 获取评测报告 */
 export const api_musicPracticeRecordDetail = (recordId: string) => {
-	return request.get("/musicPracticeRecord/detail/" + recordId);
+  return request.get("/musicPracticeRecord/detail/" + recordId);
 };
 /** 获取曲谱列表 */
 export const api_musicSheetPage = (data: any) => {
-	return request.post("/musicSheet/page", {
-		data,
-		requestType: "json",
-	});
+  return request.post("/musicSheet/page", {
+    data,
+    requestType: "json",
+  });
+};
+
+/**
+ * 获取声部列表
+ */
+export const getSubjectList = (data: any) => {
+  return request.post("/subject/page", {
+    data,
+    requestType: "json",
+  });
 };

+ 37 - 34
src/page-instrument/router.ts

@@ -3,46 +3,49 @@ import Home from "./view-detail/index";
 import Notfind from "../view/notfind";
 
 const routes: RouteRecordRaw[] = [
-	{
-		path: "/",
-		component: Home,
-	},
-	{
-		path: "/product-img",
-		component: () => import("./view-product-img/index"),
-	},
-	{
-		path: "/evaluat-report",
-		component: () => import("./view-evaluat-report/index"),
-	},
-	{
-		path: "/preview",
-		component: () => import("./view-preview/index"),
-	},
-	{
-		path: "/view-figner",
-		component: () => import("./view-figner/index"),
-	},
-	{
-		path: "/:pathMatch(.*)*",
-		component: Notfind,
-		meta: {
-			title: "404 Not Fund",
-		},
-	},
-	
+  {
+    path: "/",
+    component: Home,
+  },
+  {
+    path: "/product-img",
+    component: () => import("./view-product-img/index"),
+  },
+  {
+    path: "/evaluat-report",
+    component: () => import("./view-evaluat-report/index"),
+  },
+  {
+    path: "/preview",
+    component: () => import("./view-preview/index"),
+  },
+  {
+    path: "/view-figner",
+    component: () => import("./view-figner/index"),
+  },
+  {
+    path: "/view-figner-listen",
+    component: () => import("./view-figner-listen/index"),
+  },
+  {
+    path: "/:pathMatch(.*)*",
+    component: Notfind,
+    meta: {
+      title: "404 Not Fund",
+    },
+  },
 ];
 
 const router = createRouter({
-	history: createWebHashHistory(),
-	routes,
+  history: createWebHashHistory(),
+  routes,
 });
 
 router.beforeEach((to, from, next) => {
-	if (to.meta.title) {
-		document.title = to.meta.title as string;
-	}
-	next();
+  if (to.meta.title) {
+    document.title = to.meta.title as string;
+  }
+  next();
 });
 
 export default router;

+ 19 - 0
src/page-instrument/view-figner-listen/guide/detail-guide.tsx

@@ -0,0 +1,19 @@
+import { defineComponent, onMounted, ref } from "vue";
+import styles from "./index.module.less";
+import { Icon } from "vant";
+
+export default defineComponent({
+	name: "DetailGuide",
+	emits: ["close"],
+	setup(props, { emit }) {
+		const detailRef = ref();
+		return () => (
+			<div ref={detailRef} class={styles.detail}>
+				<div class={styles.btn} onClick={() => emit("close", true)}>
+					不再提醒
+				</div>
+				<Icon class={styles.close} name="cross" onClick={() => emit("close")} />
+			</div>
+		);
+	},
+});

+ 107 - 0
src/page-instrument/view-figner-listen/guide/finger-guide.tsx

@@ -0,0 +1,107 @@
+import { defineComponent, onMounted, reactive, ref } from "vue";
+import styles from "./index.module.less";
+import { Button, Icon, Popup } from "vant";
+import icons from "./image/icons.json";
+import state from "/src/state";
+import { getQuery } from "/src/utils/queryString";
+
+export default defineComponent({
+	name: "DetailGuide",
+	emits: ["close"],
+	setup(props, { emit }) {
+		const query = getQuery();
+		const data = reactive({
+			box: {},
+			show: true,
+			steps: [
+				{
+					className: "boxItem1",
+					des: `快点击下排按钮听听${state.fingeringInfo.code}的声音吧,按钮可以滑动哦~`,
+					img: icons.icon_cursor_1,
+				},
+				{
+					className: "boxItem2",
+					des: "这里可以切换音调,查看不同音调的指法~",
+					img: icons.icon_cursor_2,
+				},
+				{
+					className: "boxItem3",
+					des: "可以通过手势放大缩小乐器哦~",
+					img: icons.icon_cursor_3,
+				},
+			],
+			step: 0,
+		});
+		const steps = ["finger-note-0", "finger-note-1", "finger-note-2"];
+		const getStepELe = () => {
+			const ele: HTMLElement = document.getElementById(steps[data.step])!;
+			console.log(data.step, ele);
+			if (ele) {
+				const eleRect = ele.getBoundingClientRect();
+				const increment = data.step === 2 ? eleRect.width : 0;
+				data.box = {
+					left: eleRect.x - increment + "px",
+					top: eleRect.y + "px",
+					width: (data.step === 2 ? 0 : eleRect.width) + "px",
+					height: (data.step === 2 ? 0 : eleRect.height) + "px",
+				};
+			} else {
+				handleNext();
+			}
+		};
+		onMounted(() => {
+			getStepELe();
+		});
+
+		const handleNext = () => {
+			if (data.step >= 2) {
+				endGuide();
+				return;
+			}
+			data.step = data.step + 1;
+			getStepELe();
+		};
+
+		const endGuide = () => {
+			emit("close", true);
+		};
+		return () => (
+			<Popup
+				zIndex={5051}
+				teleport="body"
+				overlay={false}
+				closeOnClickOverlay={false}
+				class={["popup-custom", styles.fingerGuide]}
+				v-model:show={data.show}
+			>
+				<div class={styles.content} onClick={() => handleNext()}>
+					<div class={styles.box} style={data.box}>
+						{data.steps.map((item, index) => (
+							<div style={{ display: index === data.step ? "" : "none" }} class={styles[item.className]}>
+								<img src={item.img} />
+							</div>
+						))}
+					</div>
+					<div onClick={(e: Event) => e.stopPropagation()}>
+						{data.steps.map((item, index) => (
+							<div style={{ display: index === data.step ? "" : "none" }} class={[styles.item, ['Woodwind', 'Tenor Recorder'].includes(query.code) && styles.itemScale]}>
+								<div class={styles.title}>
+									<img src={icons.guide_2} />
+									<div class={styles.des} style={{fontSize: index === 2 ? '0.34667rem' : ''}}>
+										{item.des}
+									</div>
+								</div>
+								<div class={styles.icon}>
+									<img src={icons.guide_1} />
+								</div>
+								<Button class={styles.btn} round type="primary" onClick={() => handleNext()}>
+									我知道了
+								</Button>
+							</div>
+						))}
+					</div>
+				</div>
+			</Popup>
+		);
+	},
+});

+ 69 - 0
src/page-instrument/view-figner-listen/guide/guide-index.tsx

@@ -0,0 +1,69 @@
+import { PropType, defineComponent, onMounted, reactive } from "vue";
+import DetailGuide from "./detail-guide";
+import FingerGuide from "./finger-guide";
+import { getQuery } from "/src/utils/queryString";
+
+type guideType = "detail" | "finger";
+export default defineComponent({
+	name: "guide-index",
+	props: {
+		list: {
+			type: Array as PropType<guideType[]>,
+			default: "",
+		},
+		showGuide: {
+			type: Boolean,
+			default: true,
+		}
+	},
+	setup(props) {
+        const query = getQuery();
+		const detailGuideKey = "detailGuideKey";
+		const fingerGuideKey = "fingerGuideKey";
+		const data = reactive({
+			list: props.list,
+			detailShow: false,
+			fingerShow: false,
+		});
+		const init = () => {
+            if (props.showGuide && !query.showGuide) return;
+			if (data.list.includes("detail")) {
+				if (localStorage.getItem(detailGuideKey)) return;
+				setTimeout(() => {
+					data.detailShow = true;
+				}, 300)
+			}
+			if (data.list.includes("finger")) {
+				if (localStorage.getItem(fingerGuideKey)) return;
+				data.fingerShow = true;
+			}
+		};
+		onMounted(() => {
+			init();
+		});
+		return () => (
+			<>
+				{data.detailShow && (
+					<DetailGuide
+						onClose={(val) => {
+							if (val) {
+								localStorage.setItem(detailGuideKey, "1");
+							}
+							data.detailShow = false;
+						}}
+					/>
+				)}
+				{data.fingerShow && (
+					<FingerGuide
+						onClose={(val) => {
+							if (val) {
+								localStorage.setItem(fingerGuideKey, "1");
+							}
+							data.fingerShow = false;
+						}}
+					/>
+				)}
+			</>
+		);
+	},
+});

BIN
src/page-instrument/view-figner-listen/guide/image/icon_detail.png


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
src/page-instrument/view-figner-listen/guide/image/icons.json


+ 135 - 0
src/page-instrument/view-figner-listen/guide/index.module.less

@@ -0,0 +1,135 @@
+.detail {
+    position: fixed;
+    left: 50%;
+    bottom: 90px;
+    transform: translateX(-50%);
+    width: 357px;
+    height: 47px;
+    background: url('./image/icon_detail.png') no-repeat;
+    background-size: 100%;
+    display: flex;
+    justify-content: flex-end;
+    padding: 14px 10px 0 0;
+
+    .btn {
+        width: 55px;
+        height: 22px;
+        background: linear-gradient(180deg, #44C9FF 0%, #259CFE 100%);
+        border-radius: 12px;
+        color: #FFFFFF;
+        font-size: 11px;
+        line-height: 22px;
+        text-align: center;
+    }
+
+    .close {
+        color: rgba(255, 255, 255, .55);
+        font-size: 14px;
+        padding: 0 8px;
+        padding-top: 6px;
+    }
+}
+
+.fingerGuide {
+    width: 100%;
+    height: 100%;
+
+    .content {
+        width: 100%;
+        height: 100%;
+    }
+
+    .box {
+        position: fixed;
+        box-shadow: rgba(33, 33, 33, 0.8) 0px 0px 0px 5000px;
+        transition: all 0.25s;
+        border-radius: 8px;
+    }
+    .boxItem1{
+        position: absolute;
+        left: -32px;
+        top: -55px;
+        img{
+            width: 94px;
+        }
+    }
+    .boxItem2{
+        position: absolute;
+        left: -12px;
+        top: -40px;
+        img{
+            width: 42px;
+        }
+    }
+    .boxItem3{
+        position: absolute;
+        left: 20px;
+        top: 0;
+        img{
+            width: 83px;
+        }
+    }
+
+    .item {
+        position: absolute;
+        right: 50px;
+        bottom: 0;
+
+        .title {
+            width: 182px;
+
+            img {
+                width: 100%;
+                height: 67px;
+                display: block;
+            }
+
+            .des {
+                position: absolute;
+                left: 0;
+                top: 0;
+                padding: 8px 8px 0 10px;
+                font-size: 12px;
+                color: #FFFFFF;
+                line-height: 19px;
+            }
+        }
+
+        .icon {
+            width: 88px;
+            height: 99px;
+            margin-left: auto;
+            margin-right: -39px;
+            margin-top: -17px;
+
+            img {
+                width: 100%;
+                height: 100%;
+                object-fit: contain;
+                display: block;
+            }
+        }
+
+        .btn {
+            position: absolute;
+            left: 0;
+            bottom: 45px;
+            width: 83px;
+            height: 27px;
+            line-height: 27px;
+            background: linear-gradient(180deg, #FFF385 0%, #FFC036 100%);
+            border-radius: 13px;
+            border: 1px solid #FFF9DA;
+            font-size: 13px;
+            font-weight: 500;
+            color: #131415;
+            padding: 0;
+        }
+
+        &.itemScale{
+            transform: scale(.8);
+            transform-origin: right bottom;
+            right: 35px;
+        }
+    }
+}

BIN
src/page-instrument/view-figner-listen/image/icon_action_cancel.png


BIN
src/page-instrument/view-figner-listen/image/icon_action_confirm.png


BIN
src/page-instrument/view-figner-listen/image/icon_bg_t.png


BIN
src/page-instrument/view-figner-listen/image/icon_bg_v.png


BIN
src/page-instrument/view-figner-listen/image/icon_btn_1.png


BIN
src/page-instrument/view-figner-listen/image/icon_btn_2.png


BIN
src/page-instrument/view-figner-listen/image/icon_btn_3.png


BIN
src/page-instrument/view-figner-listen/image/icon_btn_4.png


BIN
src/page-instrument/view-figner-listen/image/icon_btn_green_sub.png


BIN
src/page-instrument/view-figner-listen/image/icon_btn_red_sub.png


BIN
src/page-instrument/view-figner-listen/image/icon_loading_head.png


BIN
src/page-instrument/view-figner-listen/image/icon_loading_img.png


BIN
src/page-instrument/view-figner-listen/image/icon_popup_book.png


BIN
src/page-instrument/view-figner-listen/image/icon_popup_book_h.png


BIN
src/page-instrument/view-figner-listen/image/icon_popup_book_v.png


BIN
src/page-instrument/view-figner-listen/image/icon_popup_top.png


BIN
src/page-instrument/view-figner-listen/image/icon_shadow_left.png


BIN
src/page-instrument/view-figner-listen/image/icon_shadow_r.png


BIN
src/page-instrument/view-figner-listen/image/icon_shuo_h.png


BIN
src/page-instrument/view-figner-listen/image/icon_shuo_v.png


BIN
src/page-instrument/view-figner-listen/image/icon_trans_bg.png


BIN
src/page-instrument/view-figner-listen/image/icon_trans_bg_hu.png


Разлика између датотеке није приказан због своје велике величине
+ 3 - 0
src/page-instrument/view-figner-listen/image/icons.json


+ 1037 - 0
src/page-instrument/view-figner-listen/index.module.less

@@ -0,0 +1,1037 @@
+@font-face {
+    font-family: 'jianzhu';
+    src: url('./lsy.ttf');
+    font-weight: normal;
+    font-size: normal;
+}
+
+.fingerBox {
+    position: relative;
+    display: flex;
+    flex-direction: column;
+    width: 100vw;
+    height: 100vh;
+    background: rgba(215, 205, 199, 1);
+    user-select: none;
+
+    &.fingerRight {
+        background: url('./image/icon_bg_t.png') no-repeat;
+        background-size: cover;
+
+        .fingerContent {
+            flex-direction: row;
+
+        }
+
+        .backBtn {
+            padding: 26px 17px 26px 29px;
+        }
+
+
+        .tips {
+            width: 43%;
+            border-radius: 18px 0px 0px 18px;
+            padding: 8px;
+            background-image: url('./image/icon_shuo_h.png');
+
+            &::before {
+                content: '';
+                position: absolute;
+                left: 8px;
+                top: 8px;
+                right: 8px;
+                bottom: 8px;
+                border-radius: 15px;
+                border: 1px solid rgba(240, 234, 230, 1);
+                pointer-events: none;
+            }
+
+            &.tipHidden {
+                margin-right: -43%;
+            }
+
+            .tipContentbox {
+                padding: 6px 8px 8px 8px;
+                border-radius: 16px;
+            }
+
+            .tipContent {
+                border-radius: 16px;
+                padding: 14px 8px 4px 8px;
+            }
+        }
+    }
+
+    &.fingerBottom {
+        background: url('./image/icon_bg_v.png') no-repeat;
+        background-size: cover;
+
+        .fingerContent {
+            flex-direction: column;
+        }
+
+
+        .tips {
+            height: 280px;
+            border-radius: 18px 18px 0 0;
+            padding: 8px 8px 0 8px;
+            background-image: url('./image/icon_shuo_v.png');
+
+            &::before {
+                content: '';
+                position: absolute;
+                left: 8px;
+                top: 8px;
+                right: 8px;
+                bottom: 0;
+                border-radius: 15px;
+                border: 1px solid rgba(240, 234, 230, 1);
+                pointer-events: none;
+            }
+
+            &.tipHidden {
+                margin-bottom: -280px;
+            }
+
+            .tipContentbox {
+                padding: 6px 8px 0 8px;
+                border-radius: 16px 16px 0 0;
+            }
+
+            .tipContent {
+                border-radius: 16px 16px 0 0;
+                border-bottom: transparent;
+                padding: 14px 4px 4px 4px;
+            }
+        }
+    }
+}
+
+.popoverContainer {
+    --van-popover-action-height: 34px;
+    --van-popover-action-font-size: 14px;
+    --van-popover-radius: 12px;
+    --van-popover-action-width: 85px;
+    margin-top: 9px !important;
+    color: #999;
+
+    :global {
+        .van-popover__content {
+            max-height: 200px;
+            overflow-y: auto;
+        }
+
+        .van-popover__action {
+            padding: 0 9px;
+        }
+    }
+
+    .selected {
+        color: #1CACF1;
+        font-weight: 600;
+    }
+}
+
+.head {
+    position: absolute;
+    left: 0;
+    top: 0;
+    right: 0;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    pointer-events: none;
+    padding-right: 18px;
+    padding-top: env(safe-area-inset-top);
+    z-index: 5;
+
+    .backBtn {
+        position: relative;
+        padding: 12px 12px 12px 18px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        border: none;
+        background: none;
+        cursor: pointer;
+        pointer-events: auto;
+
+        img {
+            height: 34px;
+        }
+    }
+
+    .left {
+        display: flex;
+        align-items: center;
+    }
+
+    .baseBtn {
+        width: 60px;
+        height: 45px;
+        background: rgba(255, 255, 255, .48);
+        border-radius: 10px;
+        font-size: 12px;
+        font-weight: 400;
+        color: #616161;
+        line-height: 17px;
+        text-align: center;
+        cursor: pointer;
+        display: flex;
+        flex-direction: column;
+        justify-content: space-evenly;
+        align-items: center;
+        pointer-events: auto;
+
+        img {
+            width: 18px;
+            height: 18px;
+        }
+
+        &:active {
+            opacity: .8;
+        }
+    }
+
+    .rightBtn {
+        display: flex;
+
+        .baseBtn {
+            margin: 0 4px;
+        }
+    }
+}
+
+
+.fingerContent {
+    flex: 1;
+    overflow: hidden;
+    display: flex;
+
+    .wrapFinger {
+        flex: 1;
+        overflow: hidden;
+        display: flex;
+        flex-direction: column;
+    }
+
+    .boxFinger {
+        flex: 1;
+        padding-top: 50px;
+        overflow: hidden;
+    }
+
+
+}
+
+.tips {
+    display: flex;
+    flex-direction: column;
+    height: 100%;
+    position: relative;
+    z-index: 11;
+    flex-shrink: 0;
+    transition: all .3s;
+    // background-color: rgba(190, 166, 140, 1);
+    background-size: 100% 100%;
+    background-repeat: no-repeat;
+    overflow: hidden;
+
+    .tipTitle {
+        position: relative;
+        height: 48px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        flex-shrink: 0;
+        padding-bottom: 8px;
+
+        :global {
+            .van-button:active:before {
+                opacity: 0 !important;
+            }
+        }
+    }
+
+    .tipTitleName {
+        position: relative;
+        font-weight: 600;
+        z-index: 1;
+        color: #fff;
+        font-size: 16px;
+        text-shadow: 0px 1px 2px #6D4825;
+
+        &::before {
+            content: '';
+            position: absolute;
+            left: -40px;
+            top: 50%;
+            transform: translateY(-50%);
+            width: 25px;
+            height: 1px;
+            background: #fff;
+            z-index: -1;
+        }
+
+        &::after {
+            content: '';
+            position: absolute;
+            right: -40px;
+            top: 50%;
+            transform: translateY(-50%);
+            width: 25px;
+            height: 1px;
+            background: #fff;
+            z-index: -1;
+        }
+    }
+
+    .tipImg {
+        position: absolute;
+        top: 53px;
+        left: 8px;
+        right: 8px;
+
+        img {
+            position: absolute;
+            width: 100%;
+            height: 30px;
+            display: block;
+        }
+    }
+
+    .tipClose {
+        position: absolute;
+        right: 0;
+        top: 0;
+        height: 100%;
+        border: none;
+        background: transparent;
+        border-radius: 0;
+    }
+
+    .iconBook {
+        position: absolute;
+        top: 48px;
+        left: 37px;
+        right: 37px;
+        height: 26px;
+        pointer-events: none;
+        background: url('./image/icon_popup_book.png');
+        background-size: contain;
+        z-index: 1;
+    }
+
+    .tipContentbox {
+        position: relative;
+        flex: 1;
+        background: #FFFFFF;
+        display: flex;
+        overflow: hidden;
+
+        &::before {
+            content: '';
+            position: absolute;
+            top: 0;
+            left: 0;
+            right: 0;
+            padding-bottom: 45%;
+            background: url('./image/icon_popup_top.png') no-repeat;
+            background-size: 100%;
+            opacity: .4;
+            pointer-events: none;
+            z-index: 1;
+        }
+
+        &::after {
+            content: '';
+            position: absolute;
+            top: 6.5px;
+            left: 16px;
+            right: 16px;
+            height: 10px;
+            background: #fff;
+            border-radius: 5px;
+            pointer-events: none;
+            border-top: 1.5px solid rgba(180, 165, 154, 1);
+        }
+    }
+
+    .tipContent {
+        flex: 1;
+        border: 1.5px solid rgba(180, 165, 154, 1);
+        color: rgba(68, 59, 59, 1);
+        font-size: 12px;
+        overflow: hidden;
+        overflow-y: auto;
+    }
+}
+
+.tipItem {
+    display: flex;
+    line-height: 18px;
+    margin-bottom: 8px;
+    background: linear-gradient(180deg, #FFFFFF 0%, #F3F4F7 100%);
+    border-radius: 5px;
+    padding: 10px;
+
+    .iconWrap {
+        display: flex;
+        align-items: center;
+        height: 18px;
+        margin-right: 6px;
+    }
+
+    .tipItemIcon {
+        width: 16px;
+        height: 16px;
+        background: linear-gradient(180deg, rgba(224, 180, 135, 1) 0%, rgba(195, 164, 134, 1) 100%);
+        font-weight: 600;
+        line-height: 16px;
+        color: #FFFFFF;
+        text-shadow: 0px 1px 1px #C8946D;
+        border-radius: 50%;
+        text-align: center;
+
+    }
+}
+
+.notes {
+    position: relative;
+    display: flex;
+    justify-content: center;
+    align-items: flex-start;
+    height: 65px;
+    flex-shrink: 0;
+
+    &.paddingLeft {
+        padding-left: 20Px;
+    }
+
+    .noteContent {
+        display: flex;
+        position: relative;
+        max-width: calc(100% - 92px);
+        border-radius: 25px;
+        background: rgba(255, 255, 255, 0.5);
+        border: 1px solid rgba(255, 255, 255, 0.6);
+        overflow: hidden;
+
+        &.noteContentWrap {
+            &::before {
+                content: '';
+                position: absolute;
+                left: 0;
+                top: 0;
+                height: 100%;
+                width: 23px;
+                background: url('./image/icon_shadow_left.png') no-repeat;
+                background-size: 100% 100%;
+                z-index: 10;
+                pointer-events: none;
+            }
+
+            &::after {
+                content: '';
+                position: absolute;
+                right: 0;
+                top: 0;
+                height: 100%;
+                width: 23px;
+                background: url('./image/icon_shadow_r.png') no-repeat;
+                background-size: 100% 100%;
+                z-index: 10;
+                pointer-events: none;
+            }
+        }
+
+    }
+
+    .noteBox {
+        display: flex;
+        overflow-y: hidden;
+        overflow-x: auto;
+        border-radius: 0 25px 25px 0;
+
+        &::-webkit-scrollbar {
+            width: 0;
+            display: none;
+        }
+    }
+
+    .noteBtn {
+        background: transparent;
+        color: rgba(112, 99, 88, .41);
+        border: 0;
+        padding: 0;
+        font-size: 22px;
+        height: 46px;
+
+        :global {
+            .van-icon {
+                font-weight: bold;
+            }
+        }
+
+        &.disabled {
+            color: rgba(69, 143, 177, .32);
+        }
+
+        &::before {
+            opacity: 0 !important;
+        }
+    }
+}
+
+
+.note {
+    position: relative;
+    margin: 0 2.5Px;
+    width: 46px;
+    height: 46px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    flex-shrink: 0;
+    padding: 6px;
+    z-index: 2;
+
+    img {
+        position: absolute;
+        left: 0;
+        top: 0;
+        width: 100%;
+        height: 100%;
+    }
+
+    .showAnswer {
+        width: 20px;
+        height: 20px;
+        background: url('./image/icon_btn_green_sub.png') no-repeat center / contain;
+        position: absolute;
+        bottom: 2px;
+        right: -2px;
+
+        &.errorAnswer {
+            background: url('./image/icon_btn_red_sub.png') no-repeat center / contain;
+        }
+    }
+}
+
+.noteKey {
+    position: relative;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    z-index: 1;
+    font-size: 16px;
+    font-family: 'jianzhu';
+    font-weight: normal;
+    color: #616161;
+    line-height: 1;
+    height: 100%;
+
+    &.keyActive {
+        color: #FFF9EC;
+    }
+
+    .dot {
+        width: 3px;
+        height: 3px;
+        border-radius: 50%;
+        background-color: currentColor;
+    }
+
+    .dot+.dot {
+        margin: 2px 0;
+    }
+
+    .noteName {
+        position: relative;
+    }
+
+    .noteFixed {
+        font-size: 12px;
+        color: #FFFFFF;
+        font-weight: 600;
+        padding-bottom: 5px;
+        transform: scale(0.8);
+        white-space: nowrap;
+    }
+
+    .dotFixed {
+        width: 5px;
+        height: 5px;
+    }
+
+    .mark {
+        position: absolute;
+        left: -80%;
+        font-size: 12px;
+    }
+}
+
+.optionBtns {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    padding-bottom: 21px;
+
+    .oBtn {
+        width: 104px;
+        height: 46px;
+        border: none;
+        font-weight: 600;
+        font-size: 15px;
+        color: #fff;
+        cursor: pointer;
+        margin: 0 3px;
+
+        &.gamut {
+            background: url('./image/icon_btn_3.png') no-repeat center / contain;
+        }
+
+        &.play {
+            background: url('./image/icon_btn_2.png') no-repeat center / contain;
+        }
+
+        &.success {
+            background: url('./image/icon_btn_4.png') no-repeat center / contain;
+        }
+
+        &.disabled {
+            background: url('./image/icon_btn_1.png') no-repeat center / contain;
+            color: #616161;
+            cursor: not-allowed;
+        }
+    }
+}
+
+.fingeringContainer {
+    position: relative;
+    width: 100%;
+    height: 100%;
+    display: flex;
+    justify-content: space-evenly;
+    align-items: center;
+    padding: 0 10px 8px 10px;
+}
+
+.loading {
+    position: absolute;
+    left: 0;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    z-index: 100;
+    background: rgba(0, 0, 0, .6);
+}
+
+.loadingWrap {
+    position: relative;
+    width: 295px;
+    padding: 21px 17px;
+    background: rgba(135, 135, 135, .72);
+    border-radius: 24px;
+
+    .loadingIcon {
+        position: absolute;
+        left: 50%;
+        top: -35px;
+        transform: translateX(-50%);
+        width: 216px;
+    }
+
+    .loadingTip {
+        position: absolute;
+        left: 50%;
+        transform: translateX(-50%);
+        bottom: -35px;
+        color: #fff;
+        font-size: 13px;
+        font-weight: 400px;
+    }
+
+    :global {
+        .van-progress {
+            height: 7px;
+        }
+
+        .van-progress__portion {
+            background: linear-gradient(180deg, #3CD6F9 0%, #1CACF1 100%);
+            border: 1px solid rgba(255, 255, 255, .5);
+        }
+
+        .van-progress__pivot {
+            top: 0;
+            color: transparent;
+            background-color: transparent;
+            width: 35px;
+            height: 37px;
+            background-image: url('./image/icon_loading_head.png');
+            background-repeat: no-repeat;
+            background-size: 100% 100%;
+        }
+    }
+}
+
+
+.imgs {
+    position: relative;
+    width: 84%;
+    height: 100%;
+    pointer-events: none;
+
+    &>img {
+        position: absolute;
+        left: 50%;
+        top: 50%;
+        transform: translate(-50%, -50%);
+        display: block;
+        max-width: 100%;
+        max-height: 100%;
+    }
+}
+
+.tizhi {
+    position: absolute;
+    top: 20%;
+    left: 0;
+    width: 30px;
+    height: 30px;
+    text-align: center;
+    line-height: 30px;
+    border-radius: 100%;
+    background-color: #6F99CA;
+    color: #fff;
+    box-shadow: 0 0 10px rgba(0, 0, 0, .05);
+    font-size: 12Px;
+    opacity: 0;
+    pointer-events: none;
+
+    &:active {
+        opacity: .8;
+    }
+}
+
+.canDisplay {
+    opacity: 1;
+    pointer-events: auto;
+}
+
+.disabled {
+    opacity: .5;
+    pointer-events: none;
+}
+
+.toggleBtn {
+    position: fixed;
+    right: 0;
+    top: 50%;
+    transform: translateY(-50%);
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    width: 34px;
+    height: 60px;
+    background: url('./image/icon_trans_bg.png') no-repeat;
+    background-size: 100%;
+    font-size: 14px;
+    color: #616161;
+    line-height: 14px;
+    font-weight: 600;
+    padding-left: 10px;
+    text-align: center;
+    cursor: pointer;
+    z-index: 12;
+
+    &:active {
+        opacity: .8;
+    }
+
+    img {
+        width: 9px;
+        height: 5px;
+        margin-top: 3px;
+    }
+}
+
+.toggleBtnhulusi {
+    height: auto;
+    padding: 14px 0 15px 12px;
+    background-image: url('./image/icon_trans_bg_hu.png');
+    background-size: 100% 100%;
+}
+
+.tones {
+    display: flex;
+    flex-direction: column;
+    height: 100%;
+    position: relative;
+    z-index: 12;
+    transition: all .3s;
+    overflow: hidden;
+    // background-color: rgba(190, 166, 140, 1);
+    background-size: 100% 100%;
+    background-repeat: no-repeat;
+
+    .toneTitle {
+        position: relative;
+        height: 45px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        flex-shrink: 0;
+
+        :global {
+            .van-button:active:before {
+                opacity: 0 !important;
+            }
+        }
+    }
+
+    .tipTitleName {
+        position: relative;
+        font-weight: 500;
+        font-size: 15px;
+        z-index: 1;
+        color: #fff;
+        font-size: 16px;
+        text-shadow: 0px 1px 2px #6D4825;
+
+        &::before {
+            content: '';
+            position: absolute;
+            left: -40px;
+            top: 50%;
+            transform: translateY(-50%);
+            width: 25px;
+            height: 1px;
+            background: #fff;
+            z-index: -1;
+        }
+
+        &::after {
+            content: '';
+            position: absolute;
+            right: -40px;
+            top: 50%;
+            transform: translateY(-50%);
+            width: 25px;
+            height: 1px;
+            background: #fff;
+            z-index: -1;
+        }
+    }
+
+    .tipClose {
+        position: absolute;
+        right: 0;
+        top: 0;
+        height: 100%;
+        border: none;
+        background: transparent;
+        border-radius: 0;
+    }
+
+    .tipContentbox {
+        position: relative;
+        flex: 1;
+        background: #FFFFFF;
+        display: flex;
+        flex-direction: column;
+        overflow: hidden;
+
+        &::before {
+            content: '';
+            position: absolute;
+            top: 0;
+            left: 0;
+            right: 0;
+            padding-bottom: 45%;
+            background: url('./image/icon_popup_top.png') no-repeat;
+            background-size: 100%;
+            opacity: .4;
+            pointer-events: none;
+        }
+    }
+
+    .tipWrap {
+        flex: 1;
+        overflow: hidden;
+    }
+
+    .tipContent {
+        flex: 1;
+        display: flex;
+        flex-direction: column;
+        border: 1.5px solid rgba(180, 165, 154, 1);
+        color: rgba(68, 59, 59, 1);
+        font-size: 12px;
+
+    }
+
+    .toneAction {
+        border-top: 1px solid #EBEBEB;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        padding: 16px 0;
+
+        img {
+            width: 45%;
+            max-width: 128px;
+            margin: 0 6px;
+
+            &:active {
+                opacity: .85;
+            }
+        }
+    }
+
+    .toneContent {
+        display: flex;
+        flex-wrap: wrap;
+        --van-button-primary-background: rgba(174, 137, 103, 1);
+        --van-button-primary-border-color: rgba(174, 137, 103, 1);
+
+        :global {
+            .van-space-item {
+                width: calc(100% / 4);
+                padding: 6px 2px;
+            }
+
+            .van-button {
+                position: relative;
+                font-size: 13px;
+                width: 100%;
+                height: 0;
+                padding: 0;
+                padding-bottom: 40.5%;
+                flex-shrink: 0;
+
+
+                &::before {
+                    display: none;
+                }
+
+                .van-button__content {
+                    position: absolute;
+                    left: 0;
+                    top: 0;
+                    width: 100%;
+                }
+
+                &:active {
+                    opacity: .8;
+                }
+            }
+
+            .van-button--primary {
+                --van-button-plain-background: RGBA(255, 246, 231, 1);
+            }
+        }
+
+        :global(.van-button--primary) {
+            .dot {
+                background: var(--van-button-primary-background) !important;
+            }
+        }
+
+        .hulusiNoteKey {
+            color: inherit;
+            text-shadow: none;
+        }
+    }
+}
+
+:global(.van-popup--right.tonePopup) {
+    width: 43%;
+    height: 100%;
+    border-radius: 18px 0px 0px 18px;
+    background-color: transparent;
+
+    .tones {
+        padding: 8px;
+        background-image: url('./image/icon_shuo_h.png');
+
+        &::before {
+            content: '';
+            position: absolute;
+            left: 8px;
+            top: 8px;
+            right: 8px;
+            bottom: 8px;
+            border-radius: 15px;
+            border: 1px solid rgba(240, 234, 230, 1);
+            pointer-events: none;
+        }
+
+        .tipContentbox {
+            padding: 6px 8px 8px 8px;
+            border-radius: 16px;
+        }
+
+        .tipContent {
+            border-radius: 16px;
+            padding: 4px 8px;
+        }
+    }
+
+    .hulusiBtn {
+        font-size: 10px;
+        text-wrap: nowrap;
+    }
+}
+
+:global(.van-popup--bottom.tonePopup) {
+    display: flex;
+    flex-direction: column;
+    min-height: 238px;
+    border-radius: 18px 18px 0 0;
+    background-color: transparent;
+
+    .tones {
+        flex: 1;
+        padding: 8px 8px 0 8px;
+        background-image: url('./image/icon_shuo_v.png');
+
+        &::before {
+            content: '';
+            position: absolute;
+            left: 8px;
+            top: 8px;
+            right: 8px;
+            bottom: 0;
+            border-radius: 15px;
+            border: 1px solid rgba(240, 234, 230, 1);
+            pointer-events: none;
+        }
+
+        .tipContentbox {
+            padding: 6px 8px 0 8px;
+            border-radius: 16px 16px 0 0;
+        }
+
+        .tipContent {
+            border-radius: 16px 16px 0 0;
+            border-bottom: transparent;
+            padding: 4px 8px;
+        }
+    }
+
+    .toneContent {
+        margin-top: auto;
+
+        :global {
+            .van-space-item {
+                max-width: 100px;
+            }
+        }
+    }
+}

+ 1060 - 0
src/page-instrument/view-figner-listen/index.tsx

@@ -0,0 +1,1060 @@
+import { PropType, computed, defineComponent, nextTick, onBeforeMount, onMounted, onUnmounted, reactive, ref } from "vue";
+import styles from "./index.module.less";
+import icons from "./image/icons.json";
+import { FIGNER_INSTRUMENT_DATA, FIGNER_INSTRUMENT_REALKEY, IFIGNER_INSTRUMENT_Note } from "/src/view/figner-preview";
+import { ITypeFingering, IVocals, getFingeringConfig, mappingVoicePart, subjectFingering } from "/src/view/fingering/fingering-config";
+import { Howl } from "howler";
+import { storeData } from "/src/store";
+import { api_back, api_cloudLoading, api_setRequestedOrientation, api_setStatusBarVisibility, isSpecialShapedScreen } from "/src/helpers/communication";
+import Hammer from "hammerjs";
+import { Button, Icon, Loading, Popover, Popup, Progress, Space } from "vant";
+// import GuideIndex from "./guide/guide-index";
+import qs from "query-string";
+import { getQuery } from "/src/utils/queryString";
+import { browser } from "/src/utils";
+import { usePageVisibility } from "@vant/use";
+import { watch } from "vue";
+import icon_loading_img from "./image/icon_loading_img.png";
+import state, { IPlatform } from "/src/state";
+
+export default defineComponent({
+  name: "viewFigner",
+  emits: ["close"],
+  props: {
+    show: {
+      type: Boolean,
+      default: true,
+    },
+    // isComponent: {
+    //   type: Boolean,
+    //   default: false,
+    // },
+    // subject: {
+    //   type: String as PropType<IVocals>,
+    //   default: "",
+    // },
+  },
+  setup(props, { emit }) {
+    const query = getQuery();
+    const browsInfo = browser();
+    const code = query.subjectCode || mappingVoicePart(storeData.user?.subjectId, "INSTRUMENT");
+    const subject = code || "pan-flute";
+
+    // 设置屏幕方向
+    api_setRequestedOrientation(["hulusi-flute", "piccolo"].includes(subject) ? 1 : 0);
+
+    const data = reactive({
+      loading: true,
+      subject: subject as any,
+      realKey: 0,
+      notes: [] as IFIGNER_INSTRUMENT_Note[],
+      tones: [] as IFIGNER_INSTRUMENT_Note[],
+      activeTone: {} as IFIGNER_INSTRUMENT_Note,
+      popupActiveTone: {} as IFIGNER_INSTRUMENT_Note,
+      activeToneName: "",
+      soundFonts: {} as any,
+      viewIndex: 0,
+      viewTotal: 1,
+      noteAudio: null as unknown as Howl,
+      transform: {
+        scale: 1,
+        x: 0,
+        y: 0,
+        startScale: 1,
+        startX: 0,
+        startY: 0,
+        transition: "",
+      },
+      tipShow: false,
+      tips: [] as IFIGNER_INSTRUMENT_Note[],
+      tnoteShow: false,
+      loadingSoundFonts: true,
+      loadingSoundProgress: 0,
+
+      huaweiPad: navigator?.userAgent?.includes("UAWEIVRD-W09") ? true : false,
+      paddingTop: "",
+      paddingLeft: "",
+
+      subjects: [
+        {
+          text: "排箫",
+          value: "pan-flute",
+          className: "",
+        },
+        {
+          text: "陶笛",
+          value: "ocarina",
+          className: "",
+        },
+        {
+          text: "葫芦丝",
+          value: "hulusi-flute",
+          className: "",
+        },
+        {
+          text: "竖笛",
+          value: "piccolo",
+          className: "",
+        },
+        {
+          text: "口风琴",
+          value: "melodica",
+          className: "",
+        },
+      ],
+      fingeringModeList: [
+        {
+          text: "指法模式",
+          value: "fingeringMode",
+          className: styles.selected,
+        },
+        {
+          text: "听音模式",
+          value: "listenMode",
+          className: "",
+        },
+      ],
+      fingeringMode: "fingeringMode" as "fingeringMode" | "listenMode", // 模式
+      noteType: "all" as "#c" | "all", // 音调
+    });
+
+    const fingerData = reactive({
+      relationshipIndex: 0,
+      subject: null as unknown as ITypeFingering,
+      fingeringInfo: subjectFingering(data.subject),
+    });
+    // if (!props.isComponent) {
+    //   state.fingeringInfo = fingerData.fingeringInfo;
+    // }
+
+    const getAPPData = async (type: "top" | "left") => {
+      const screenData = await isSpecialShapedScreen();
+      if (screenData?.content) {
+        // console.log("🚀 ~ screenData:", screenData.content);
+        const { isSpecialShapedScreen, notchHeight } = screenData.content;
+        if (isSpecialShapedScreen) {
+          if (type === "top") {
+            data.paddingTop = 25 + "px";
+          }
+          if (type === "left") {
+            data.paddingLeft = 25 + "px";
+          }
+        }
+      }
+    };
+
+    const getHeadTop = () => {
+      if (!browsInfo.ios && fingerData.fingeringInfo.orientation === 1) {
+        getAPPData("top");
+      }
+      if (!browsInfo.ios && fingerData.fingeringInfo.orientation === 0) {
+        getAPPData("left");
+      }
+    };
+
+    const getNotes = () => {
+      const fignerData = FIGNER_INSTRUMENT_DATA[data.subject as keyof typeof FIGNER_INSTRUMENT_DATA];
+      if (fignerData) {
+        data.tones = fignerData.tones || [];
+        if (data.tones.length) {
+          data.activeTone = data.tones[0];
+          data.popupActiveTone = data.tones[0];
+        }
+        data.tips = fignerData.tips || [];
+        setNotes();
+        setTimeout(() => {
+          data.loading = false;
+        }, 600);
+      }
+    };
+    const setNotes = () => {
+      const fignerData = FIGNER_INSTRUMENT_DATA[data.subject as keyof typeof FIGNER_INSTRUMENT_DATA];
+      if (fignerData) {
+        const tempNotes = fignerData[`list${data.activeTone.realName || ""}`];
+        const appendNote: any = [];
+        tempNotes.forEach((note: any) => {
+          note.steps = new Array(Math.abs(note.step)).fill(1);
+          if (FIGNER_INSTRUMENT_REALKEY.includes(note.realKey)) {
+            appendNote.push(note);
+          }
+        });
+        // 判断是音符状态
+        data.notes = data.noteType === "#c" ? appendNote : tempNotes;
+      }
+    };
+    const getFingeringData = async () => {
+      const subject: any = data.subject + (data.viewIndex === 0 ? "" : data.viewIndex);
+      console.log("🚀 ~ subject:", subject);
+      fingerData.subject = await getFingeringConfig(subject);
+    };
+    const createAudio = (url: string) => {
+      return new Promise((resolve) => {
+        const noteAudio = new Howl({
+          src: url,
+          loop: true,
+          onload: () => {
+            resolve(noteAudio);
+          },
+        });
+      });
+    };
+    const getSounFonts = async () => {
+      const pathname = /(192|localhost)/.test(location.origin) ? "/" : location.pathname;
+      data.loadingSoundFonts = true;
+      data.loadingSoundProgress = 0;
+      for (let i = 0; i < data.notes.length; i++) {
+        const note = data.notes[i];
+        // console.log("🚀 ~ note:", i);
+        let url = `${pathname}soundfonts/${data.subject}/`;
+        url += note.realName;
+        url += ".mp3";
+        data.soundFonts[note.realKey] = await createAudio(url);
+        data.loadingSoundProgress = Math.floor(((i + 1) / data.notes.length) * 100);
+      }
+      data.loadingSoundProgress = 100;
+      api_cloudLoading();
+      data.loadingSoundFonts = false;
+      // console.log("🚀 ~ data.soundFonts:", data.soundFonts);
+    };
+
+    const selectSubjectType = (subject: string) => {
+      data.subjects.forEach((item: any) => {
+        if (item.value === subject) {
+          item.className = styles.selected;
+        } else {
+          item.className = "";
+        }
+      });
+    };
+
+    onBeforeMount(() => {
+      getNotes();
+
+      if (["pan-flute", "ocarina"].includes(data.subject)) {
+        data.viewIndex = 1;
+      }
+
+      selectSubjectType(data.subject);
+      // const o: any = {
+      //   "pan-flute": 2,
+      //   ocarina: 2,
+      //   piccolo: 2,
+      //   "hulusi-flute": 2,
+      // };
+      // data.viewTotal = o[data.subject] || 1;
+      getFingeringData();
+      getSounFonts();
+      getHeadTop();
+    });
+
+    const noteClick = (item: IFIGNER_INSTRUMENT_Note) => {
+      if (data.noteAudio) {
+        data.noteAudio.stop();
+        if (data.realKey === item.realKey) {
+          data.realKey = 0;
+          data.noteAudio = null as unknown as Howl;
+          return;
+        }
+      }
+      data.realKey = item.realKey;
+      data.noteAudio = data.soundFonts[item.realKey];
+      data.noteAudio.play();
+    };
+    const handleStop = () => {
+      if (data.noteAudio) {
+        data.noteAudio.stop();
+        data.realKey = 0;
+        data.noteAudio = null as unknown as Howl;
+      }
+    };
+
+    /** 返回 */
+    const handleBack = () => {
+      handleStop();
+      // if (props.isComponent) {
+      //   console.log("关闭");
+      //   emit("close");
+      //   return;
+      // } else {
+      //   // if (fingerData.fingeringInfo.orientation === 0) {
+      //   // 	api_setRequestedOrientation(1);
+      //   // }
+      // }
+      // 不在APP中,
+      if (!storeData.isApp) {
+        window.close();
+        return;
+      }
+      api_back();
+    };
+
+    onMounted(() => {
+      loadElement();
+      api_setStatusBarVisibility();
+    });
+    const loadElement = () => {
+      const fingeringContainer = document.getElementById("fingeringContainer");
+      // console.log("🚀 ~ fingeringContainer:", fingeringContainer);
+      const mc = new Hammer.Manager(fingeringContainer as HTMLElement);
+      mc.add(new Hammer.Pan({ threshold: 0, pointers: 0 }));
+      mc.add(new Hammer.Pinch({ threshold: 0 })).recognizeWith([mc.get("pan")]);
+      // mc.get("pan").set({ direction: Hammer.DIRECTION_ALL });
+      // mc.get("pinch").set({ enable: true });
+      mc.on("panstart pinchstart", function (ev) {
+        data.transform.transition = "";
+      });
+      mc.on("panmove pinchmove", function (ev) {
+        if (ev.type === "pinchmove") {
+          // console.log("🚀 ~ ev:", ev.type, ev.scale, ev.deltaX, ev.deltaY);
+          data.transform.scale = ev.scale * data.transform.startScale;
+          data.transform.x = data.transform.startX + ev.deltaX;
+          data.transform.y = data.transform.startY + ev.deltaY;
+        }
+        if (ev.type === "panmove") {
+          // console.log("🚀 ~ ev:", ev.type, ev.deltaX, ev.deltaY);
+          data.transform.x = data.transform.startX + ev.deltaX;
+          data.transform.y = data.transform.startY + ev.deltaY;
+        }
+      });
+      //
+      mc.on("hammer.input", function (ev) {
+        // console.log("🚀 ~ ev:", ev.type, ev.isFinal);
+        if (ev.isFinal) {
+          data.transform.startScale = data.transform.scale;
+          data.transform.startX = data.transform.x;
+          data.transform.startY = data.transform.y;
+        }
+      });
+    };
+    const resetElement = () => {
+      data.transform.transition = "all 0.3s";
+      nextTick(() => {
+        data.transform.scale = 1;
+        data.transform.x = 0;
+        data.transform.y = 0;
+        data.transform.startScale = 1;
+        data.transform.startX = 0;
+        data.transform.startY = 0;
+      });
+    };
+
+    const pageVisible = usePageVisibility();
+    watch(
+      () => pageVisible.value,
+      (val) => {
+        if (val === "hidden") {
+          console.log("页面隐藏停止播放");
+          handleStop();
+        }
+      }
+    );
+    /** 课件播放 */
+    const changePlay = (res: any) => {
+      if (res?.data?.api === "setPlayState") {
+        handleStop();
+      }
+    };
+
+    const noteBoxRef = ref();
+    const scrollNoteBox = (type: "left" | "right") => {
+      const width = noteBoxRef.value.offsetWidth / 2;
+      (noteBoxRef.value as unknown as HTMLElement).scrollBy({
+        left: type === "left" ? -width : width,
+        behavior: "smooth",
+      });
+    };
+
+    const playStatus = reactive({
+      gamut: false, // 是否播放音阶
+      answer: false, // 是否显示答案
+      action: false, // 是否开始播放
+    });
+
+    /** 音符切换 */
+    const noteChangeShow = () => {
+      // 播放音阶时不能切换
+      if (playStatus.gamut) return;
+      // 开始答题不能切换
+      if (playStatus.action) return;
+      if (data.noteType === "all") {
+        data.noteType = "#c";
+      } else {
+        data.noteType = "all";
+      }
+      getNotes();
+    };
+
+    // 开始播放音阶
+    const onGamutPlayOrPause = async () => {
+      if (playStatus.gamut) {
+        playStatus.gamut = false;
+        gaumntPause();
+      } else {
+        // 不管当前显示在哪个音老师滚动到开始位置
+        (noteBoxRef.value as unknown as HTMLElement).scroll({
+          left: 0,
+          top: 0,
+          behavior: "smooth",
+        });
+        playStatus.gamut = true;
+        const notes = data.notes;
+        let step = 7;
+        for (let i = 0; i < notes.length; i++) {
+          if (!playStatus.gamut) return false;
+
+          if (i % 8 === 0 && i !== 0) {
+            scrollNoteBox("right");
+            step = notes[i].step;
+          }
+          await gaumtPlay(notes[i]);
+        }
+
+        // // 处理播放到最后一个
+        setTimeout(() => {
+          playStatus.gamut = false;
+          gaumntPause();
+        }, 667);
+      }
+    };
+    const gaumtPlay = (note: any, status?: boolean) => {
+      return new Promise((resolve) => {
+        setTimeout(() => {
+          if (playStatus.gamut || status) {
+            noteClick(note);
+          }
+
+          resolve(note);
+        }, 667);
+      });
+    };
+    const gaumntPause = () => {
+      if (data.noteAudio) {
+        data.noteAudio.stop();
+        data.realKey = 0;
+        data.noteAudio = null as unknown as Howl;
+      }
+    };
+
+    /** 开始播放 */
+    const playAction = reactive({
+      exampleAnser: {} as any, // 示例声音
+      standardAnswer: {} as any, // 标准答案key
+      showAnswerLoading: false, // 显示按答案中
+      listenModeStatus: false, // 听音模式
+      listenLock: false,
+      /** 0: 未答,1: 答对,2: 答错 */
+      userAnswerStatus: 0 as 0 | 1 | 2, // 用户回答状态
+      userAnswer: {} as any, // 用户答的数据
+    });
+    const onActionPlay = async () => {
+      if (playAction.listenLock) return;
+      playStatus.action = true;
+      playStatus.answer = true;
+      // 先暂停播放声音
+      gaumntPause();
+      if (data.fingeringMode === "fingeringMode") {
+        onFingeringMode();
+      } else if (data.fingeringMode === "listenMode") {
+        if (playAction.listenModeStatus) {
+          playAction.listenLock = true;
+          await fingeringPlay(playAction.standardAnswer);
+          gaumntPause();
+          playAction.listenLock = false;
+        } else {
+          onListenMode();
+        }
+      }
+    };
+
+    // 指法模式
+    const fingeringPlay = (note: any, timer = 1500) => {
+      return new Promise((resolve) => {
+        noteClick(note);
+        setTimeout(() => {
+          resolve(note);
+        }, timer);
+      });
+    };
+    const onFingeringMode = () => {
+      const randomIndex = Math.floor(Math.random() * data.notes.length);
+      playAction.standardAnswer = data.notes[randomIndex];
+      data.realKey = data.notes[randomIndex].realKey;
+    };
+    // 听音模式
+    const onListenMode = async () => {
+      playAction.listenModeStatus = true; // 是否开始听音
+      playAction.listenLock = true; // 锁
+      let randomIndex = Math.floor(Math.random() * data.notes.length);
+      playAction.exampleAnser = data.notes[randomIndex];
+      data.realKey = playAction.exampleAnser.realKey;
+      scrollAnswer();
+      await fingeringPlay(playAction.exampleAnser);
+      data.realKey = 0;
+      playAction.exampleAnser = {};
+      gaumntPause();
+      setTimeout(async () => {
+        randomIndex = Math.floor(Math.random() * data.notes.length);
+        playAction.standardAnswer = data.notes[randomIndex];
+        await fingeringPlay(data.notes[randomIndex]);
+        gaumntPause();
+        playAction.listenLock = false;
+      }, 1000);
+    };
+
+    // 显示答案
+    const onShowAnswer = async () => {
+      if (data.fingeringMode === "fingeringMode") {
+        playAction.showAnswerLoading = true;
+        scrollAnswer();
+        ressetMode();
+      } else if (data.fingeringMode === "listenMode") {
+        if (playAction.listenLock) return;
+        playAction.showAnswerLoading = true;
+        scrollAnswer(playAction.standardAnswer.realKey);
+        await fingeringPlay(playAction.standardAnswer);
+        ressetMode(true, 0);
+      }
+    };
+    // 滚动到对应答案位置
+    const scrollAnswer = (realKey?: any) => {
+      const index = data.notes.findIndex((item: any) => item.realKey === realKey || data.realKey);
+      const activeDom = document.querySelectorAll(".note-class")[index] as any;
+      if (activeDom) {
+        const aWidth = activeDom.offsetWidth;
+        const width = noteBoxRef.value.offsetWidth - aWidth;
+        const wLeft = noteBoxRef.value.offsetLeft;
+        const aLeft = Math.max(activeDom?.offsetLeft - aWidth, 0);
+
+        console.log(aLeft - wLeft - width / 2);
+        (noteBoxRef.value as unknown as HTMLElement).scroll({
+          left: aLeft - wLeft - width / 2,
+          top: 0,
+          behavior: "smooth",
+        });
+      }
+    };
+
+    const ressetMode = (status = true, timer = 2000) => {
+      // 2秒钟后重置
+      setTimeout(() => {
+        gaumntPause();
+        if (status) {
+          playAction.standardAnswer = {};
+          playAction.showAnswerLoading = false;
+          playAction.userAnswerStatus = 0;
+          playAction.userAnswer = {};
+          playAction.listenModeStatus = false;
+          playStatus.action = false;
+          playStatus.answer = false;
+          data.realKey = 0;
+        } else {
+          playAction.userAnswerStatus = 0;
+          playAction.userAnswer = {};
+        }
+      }, timer);
+    };
+
+    /** 滚轮缩放 */
+    const handleWheel = (e: WheelEvent) => {
+      e.preventDefault();
+      if (e.deltaY > 0) {
+        data.transform.scale -= 0.1;
+        if (data.transform.scale <= 0.5) {
+          data.transform.scale = 0.5;
+        }
+      } else {
+        data.transform.scale += 0.1;
+        if (data.transform.scale >= 2) {
+          data.transform.scale = 2;
+        }
+      }
+    };
+
+    onMounted(() => {
+      window.addEventListener("message", changePlay);
+      const fingeringContainer = document.getElementById("fingeringContainer");
+      fingeringContainer?.addEventListener("wheel", handleWheel);
+    });
+
+    onUnmounted(() => {
+      window.removeEventListener("message", changePlay);
+      const fingeringContainer = document.getElementById("fingeringContainer");
+      fingeringContainer?.removeEventListener("wheel", handleWheel);
+    });
+
+    const containerBox = computed(() => {
+      if (state.platform === IPlatform.PC || query.modelType) {
+        return {
+          paddingTop: "1rem",
+          paddingBottom: "",
+        };
+      }
+      if (data.subject === "hulusi-flute") {
+        return {
+          paddingTop: "2.6rem",
+          paddingBottom: ".6rem",
+        };
+      } else if (data.subject === "piccolo") {
+        return {
+          paddingTop: "3.5rem",
+          paddingBottom: ".6rem",
+        };
+      } else if (data.subject === "pan-flute") {
+        return {
+          paddingTop: "0",
+          paddingBottom: "0",
+        };
+      } else if (data.subject === "ocarina") {
+        return {
+          paddingTop: "1rem",
+          paddingBottom: "0",
+        };
+      } else if (data.subject === "melodica") {
+        return {
+          paddingTop: "2.8rem",
+          paddingBottom: "1rem",
+        };
+      } else {
+        return {
+          paddingTop: "",
+          paddingBottom: "",
+        };
+      }
+    });
+
+    const listenText = computed(() => {
+      if (data.fingeringMode === "fingeringMode") {
+        if (playStatus.action) {
+          return "换一换";
+        } else {
+          return "开始";
+        }
+      } else if (data.fingeringMode === "listenMode") {
+        if (playStatus.action) {
+          return "再听一遍";
+        } else {
+          return "开始听音";
+        }
+      }
+      return "开始听音";
+    });
+
+    const modeText = computed(() => {
+      let text = "";
+      data.fingeringModeList.forEach((item: any) => {
+        if (item.value === data.fingeringMode) {
+          text = item.text;
+        }
+      });
+      return text;
+    });
+
+    const resultImg = (note: any) => {
+      if (data.realKey === note.realKey && !playStatus.action) {
+        return {
+          icon: icons.icon_btn_ylow,
+          status: false,
+        };
+      } else if (playAction.exampleAnser.realKey === note.realKey) {
+        return {
+          icon: icons.icon_btn_ylow,
+          status: false,
+        };
+      } else if (playAction.standardAnswer.realKey === note.realKey) {
+        // 没有开始答题
+        if (!playStatus.action) {
+          return {
+            icon: icons.icon_btn_ylow,
+            status: false,
+          };
+        }
+        // 显示答案中
+        if (playAction.showAnswerLoading) {
+          return {
+            icon: icons.icon_btn_green,
+            status: true,
+          };
+        }
+        // 用户答对
+        if (playAction.userAnswerStatus === 1) {
+          return {
+            icon: icons.icon_btn_green,
+            status: true,
+          };
+        }
+      } else {
+        // 用户答错
+        if (playAction.userAnswerStatus === 2 && playAction.userAnswer.realKey === note.realKey) {
+          return {
+            icon: icons.icon_btn_red,
+            status: true,
+          };
+        }
+      }
+      return {
+        icon: icons.icon_btn_blue,
+        status: true,
+      };
+    };
+
+    const relactionObj = computed(() => {
+      const relationship = fingerData.subject?.relationship?.[data.realKey] || [];
+      const rs: number[] = Array.isArray(relationship[1]) ? relationship[fingerData.relationshipIndex] : relationship;
+      const canTizhi = Array.isArray(relationship[1]);
+      return {
+        rs,
+        canTizhi,
+      };
+    });
+    return () => {
+      return (
+        <div class={[styles.fingerBox, state.platform !== IPlatform.PC && !query.modelType && fingerData.fingeringInfo.orientation === 1 ? styles.fingerBottom : styles.fingerRight]}>
+          <div
+            class={styles.head}
+            style={{
+              paddingTop: data.paddingTop ? data.paddingTop : "",
+              paddingLeft: data.paddingLeft ? data.paddingLeft : "",
+            }}
+          >
+            <div class={styles.left}>
+              <button class={[styles.backBtn]} onClick={() => handleBack()}>
+                <img src={icons.icon_back} />
+              </button>
+              <Popover
+                placement="bottom"
+                class={styles.popoverContainer}
+                actions={data.subjects}
+                onSelect={(val: any) => {
+                  //
+                  selectSubjectType(val.value);
+                  const _url =
+                    location.origin +
+                    location.pathname +
+                    "#/view-figner-listen?" +
+                    qs.stringify({
+                      ...query,
+                      _t: new Date().valueOf(),
+                      subjectCode: val.value,
+                    });
+                  location.href = _url;
+                  window.location.reload();
+                }}
+              >
+                {{
+                  reference: () => (
+                    <div
+                      class={styles.baseBtn}
+                      onClick={() => {
+                        //
+                      }}
+                    >
+                      <img src={icons.icon_change_instrument} />
+                      <span>切换乐器</span>
+                    </div>
+                  ),
+                }}
+              </Popover>
+            </div>
+            <div class={styles.rightBtn}>
+              <Popover
+                placement="bottom"
+                class={styles.popoverContainer}
+                actions={data.fingeringModeList}
+                onSelect={(val: any) => {
+                  //
+                  if (playAction.listenLock) return;
+                  data.fingeringModeList.forEach((item: any) => {
+                    if (item.value === val.value) {
+                      item.className = styles.selected;
+                    } else {
+                      item.className = styles.normal;
+                    }
+                  });
+                  data.fingeringMode = val.value;
+
+                  // 重置
+                  ressetMode(true, 0);
+                }}
+              >
+                {{
+                  reference: () => (
+                    <div class={styles.baseBtn}>
+                      <img src={icons.icon_mode} />
+                      <span>{modeText.value}</span>
+                    </div>
+                  ),
+                }}
+              </Popover>
+
+              <div class={styles.baseBtn} onClick={() => resetElement()}>
+                <img src={icons.icon_2_0} />
+                <span>还原</span>
+              </div>
+              <div
+                class={styles.baseBtn}
+                onClick={() => {
+                  resetElement();
+                  data.tipShow = !data.tipShow;
+                }}
+              >
+                <img src={icons.icon_2_1} />
+                <span>使用说明</span>
+              </div>
+            </div>
+          </div>
+          <div class={styles.fingerContent}>
+            <div class={styles.wrapFinger}>
+              <div
+                id="fingeringContainer"
+                class={styles.boxFinger}
+                style={{
+                  paddingTop: containerBox.value.paddingTop,
+                  paddingBottom: containerBox.value.paddingBottom,
+                }}
+              >
+                <div
+                  style={{
+                    transform: `translate3d(${data.transform.x}px,${data.transform.y}px,0px) scale(${data.transform.scale})`,
+                    transition: data.transform.transition,
+                  }}
+                  class={[styles.fingeringContainer]}
+                >
+                  <div class={styles.imgs}>
+                    <img src={fingerData.subject?.json?.full1} />
+                    {relactionObj.value.rs.map((key: number | string, index: number) => {
+                      const nk: string = typeof key === "string" ? key.replace("active-", "") : String(key);
+                      return <img data-index={nk} src={fingerData.subject?.json?.[nk]} />;
+                    })}
+                    <div style={{ left: data.viewIndex == 2 ? "0" : "64%" }} class={[styles.tizhi, relactionObj.value.canTizhi && styles.canDisplay]} onClick={() => (fingerData.relationshipIndex = fingerData.relationshipIndex === 0 ? 1 : 0)}>
+                      替指
+                    </div>
+                    <div id="finger-note-2" style={{ left: "50%", transform: "translateX(-50%)" }} class={styles.tizhi} onClick={() => (fingerData.relationshipIndex = fingerData.relationshipIndex === 0 ? 1 : 0)}></div>
+                  </div>
+                </div>
+              </div>
+              <div
+                class={styles.notes}
+                style={{
+                  paddingLeft: data.paddingLeft ? data.paddingLeft : "",
+                }}
+              >
+                <Button class={styles.noteBtn} onClick={() => scrollNoteBox("left")}>
+                  <Icon name="arrow-left" />
+                </Button>
+                <div class={[styles.noteContent, browsInfo.ios ? "" : styles.noteContentWrap, data.huaweiPad && styles.huaweiPad]}>
+                  <div draggable={false} class={styles.note} onClick={noteChangeShow}>
+                    <img draggable={false} src={icons.icon_btn_orange} />
+                    <div class={[styles.noteKey]}>
+                      <div class={[styles.noteName, styles.noteFixed]}>{data.noteType === "all" ? "全按键" : "C调"}</div>
+                      <span class={styles.dotFixed}></span>
+                    </div>
+                  </div>
+                  <div ref={noteBoxRef} id="noteBox1" class={styles.noteBox}>
+                    {data.notes.map((note: any, index: number) => (
+                      <div
+                        id={index == 0 ? "finger-note-0" : ""}
+                        draggable={false}
+                        class={[styles.note, "note-class"]}
+                        key={note.realKey}
+                        onClick={async () => {
+                          // 判断是否在播放音阶
+                          if (playStatus.gamut) return;
+                          if (playAction.listenLock) return;
+                          if (playStatus.action) {
+                            playAction.userAnswer = note;
+                            // 判断用户答题
+                            playAction.userAnswerStatus = note.realKey === playAction.standardAnswer.realKey ? 1 : 2;
+                            if (data.fingeringMode === "listenMode") {
+                              playAction.listenLock = true;
+                              data.realKey = note.realKey;
+                              await fingeringPlay(note, 1000);
+                              ressetMode(note.realKey === playAction.standardAnswer.realKey ? true : false, 0);
+                              data.realKey = 0;
+                              playAction.listenLock = false;
+                            } else {
+                              ressetMode(note.realKey === playAction.standardAnswer.realKey ? true : false);
+                            }
+                          } else {
+                            noteClick(note);
+                          }
+                        }}
+                      >
+                        <img draggable={false} src={resultImg(note).icon} />
+
+                        {playStatus.action && ((playAction.showAnswerLoading && playAction.standardAnswer.realKey === note.realKey) || (playAction.userAnswerStatus === 1 && playAction.userAnswer.realKey === note.realKey)) ? <span class={styles.showAnswer}></span> : ""}
+                        {playStatus.action && playAction.userAnswerStatus === 2 && playAction.userAnswer.realKey === note.realKey ? <span class={[styles.showAnswer, styles.errorAnswer]}></span> : ""}
+
+                        <div
+                          class={[
+                            styles.noteKey,
+                            ((data.realKey === note.realKey && !playStatus.action) ||
+                              (playStatus.action && ((playAction.showAnswerLoading && playAction.standardAnswer.realKey === note.realKey) || (playAction.userAnswerStatus === 1 && playAction.userAnswer.realKey === note.realKey))) ||
+                              (playStatus.action && playAction.userAnswerStatus === 2 && playAction.userAnswer.realKey === note.realKey)) &&
+                              styles.keyActive,
+                          ]}
+                        >
+                          {/* 显示对应的点 */}
+                          {note.step > 0 ? note.steps.map((n: any) => <span class={styles.dot}></span>) : null}
+
+                          <div class={styles.noteName}>
+                            <sup>{note.mark && (note.mark === "rise" ? "#" : "b")}</sup>
+                            {note.key}
+                          </div>
+                          {/* 显示对应的点 */}
+                          {note.step < 0 ? note.steps.map((n: any) => <span class={styles.dot}></span>) : null}
+                        </div>
+                      </div>
+                    ))}
+                  </div>
+                </div>
+                <Button class={styles.noteBtn} onClick={() => scrollNoteBox("right")}>
+                  <Icon name="arrow" />
+                </Button>
+              </div>
+              <div class={styles.optionBtns}>
+                {/* , styles.disabled */}
+                <Button class={[styles.oBtn, styles.gamut, playStatus.action && styles.disabled]} round onClick={onGamutPlayOrPause}>
+                  {playStatus.gamut ? "暂停" : "播放音阶"}
+                </Button>
+                <Button class={[styles.oBtn, styles.play, playStatus.gamut && styles.disabled]} round onClick={onActionPlay}>
+                  {listenText.value}
+                </Button>
+                <Button class={[styles.oBtn, styles.success, !playStatus.answer && styles.disabled]} round onClick={onShowAnswer}>
+                  显示答案
+                </Button>
+              </div>
+            </div>
+            <div class={[styles.tips, data.tipShow ? "" : styles.tipHidden]}>
+              <div class={styles.tipTitle}>
+                <div class={styles.tipTitleName}>{fingerData.fingeringInfo.code}使用说明</div>
+                <Button class={styles.tipClose} onClick={() => (data.tipShow = false)}>
+                  <Icon name="cross" size={19} color="#fff" />
+                </Button>
+              </div>
+              <div class={styles.iconBook}></div>
+              <div class={styles.tipContentbox}>
+                <div class={styles.tipContent}>
+                  {data.tips.map((tip, tipIndex) => (
+                    <div class={styles.tipItem}>
+                      <div class={styles.iconWrap}>
+                        <div class={styles.tipItemIcon}>{tipIndex + 1}</div>
+                      </div>
+                      <div>
+                        {tip.name}: {tip.realName}
+                      </div>
+                    </div>
+                  ))}
+                </div>
+              </div>
+            </div>
+            {data.loadingSoundFonts && (
+              <div class={styles.loading}>
+                <div class={styles.loadingWrap}>
+                  <img class={styles.loadingIcon} src={icon_loading_img} />
+                  <Progress percentage={data.loadingSoundProgress} />
+                  <div class={styles.loadingTip}>加载中,请稍后…</div>
+                </div>
+              </div>
+            )}
+          </div>
+          {!!data.tones.length && (
+            <>
+              {fingerData.fingeringInfo.name == "hulusi-flute" ? (
+                <div id="finger-note-1" class={[styles.toggleBtn, styles.toggleBtnhulusi]} onClick={() => (data.tnoteShow = true)}>
+                  <div>
+                    全按作
+                    <div class={[styles.noteKey]}>
+                      {data.activeTone.step > 0 ? <span class={styles.dot}></span> : null}
+
+                      <div class={styles.noteName}>
+                        <sup>{data.activeTone.mark && (data.activeTone.mark === "rise" ? "#" : "b")}</sup>
+                        {data.activeTone.key}
+                      </div>
+                      {data.activeTone.step < 0 ? <span class={styles.dot}></span> : null}
+                    </div>
+                  </div>
+                  <img src={icons.icon_arrow} />
+                </div>
+              ) : (
+                <div id="finger-note-1" class={styles.toggleBtn} onClick={() => (data.tnoteShow = true)}>
+                  <div style={{ marginTop: "-4px" }}>
+                    <sup>{data.activeTone.mark && (data.activeTone.mark === "rise" ? "#" : "b")}</sup>
+                    {data.activeTone.name}
+                  </div>
+                  调
+                  <img src={icons.icon_arrow} />
+                </div>
+              )}
+            </>
+          )}
+
+          <Popup class="tonePopup" v-model:show={data.tnoteShow} position={state.platform !== IPlatform.PC && !query.modelType && fingerData.fingeringInfo.orientation === 1 ? "bottom" : "right"}>
+            <div class={styles.tones}>
+              <div class={styles.toneTitle}>
+                <div class={styles.tipTitleName}>移调</div>
+                <Button class={styles.tipClose} onClick={() => (data.tnoteShow = false)}>
+                  <Icon name="cross" size={19} color="#fff" />
+                </Button>
+              </div>
+              <div class={styles.tipContentbox}>
+                <div class={styles.tipContent}>
+                  <div class={styles.tipWrap}>
+                    <Space size={0} class={styles.toneContent}>
+                      {data.tones.map((tone: IFIGNER_INSTRUMENT_Note) => {
+                        const steps = new Array(Math.abs(tone.step)).fill(1);
+                        return (
+                          <Button
+                            class={[fingerData.fingeringInfo.name == "hulusi-flute" && styles.hulusiBtn]}
+                            round
+                            plain
+                            type={data.popupActiveTone.realName === tone.realName ? "primary" : "default"}
+                            onClick={() => {
+                              data.popupActiveTone = tone;
+                              setNotes();
+                            }}
+                          >
+                            {fingerData.fingeringInfo.name == "hulusi-flute" ? (
+                              <div style={{ display: "flex", alignItems: "center" }}>
+                                全按作
+                                <div class={[styles.noteKey, styles.hulusiNoteKey]}>
+                                  {tone.step > 0 ? <span class={styles.dot}></span> : null}
+                                  <div class={styles.noteName} style={{ fontSize: "0.25rem" }}>
+                                    <sup>{tone.mark && (tone.mark === "rise" ? "#" : "b")}</sup>
+                                    {tone.key}
+                                  </div>
+                                  {tone.step < 0 ? <span class={styles.dot}></span> : null}
+                                </div>
+                              </div>
+                            ) : (
+                              <div class={styles.noteName}>
+                                <sup>{tone.mark && (tone.mark === "rise" ? "#" : "b")}</sup>
+                                {tone.name}
+                              </div>
+                            )}
+                          </Button>
+                        );
+                      })}
+                    </Space>
+                  </div>
+                  <div class={styles.toneAction}>
+                    <img onClick={() => (data.tnoteShow = false)} src={icons.icon_action_cancel} />
+                    <img
+                      onClick={() => {
+                        data.activeTone = data.popupActiveTone;
+                        setNotes();
+                        data.tnoteShow = false;
+                      }}
+                      src={icons.icon_action_confirm}
+                    />
+                  </div>
+                </div>
+              </div>
+            </div>
+          </Popup>
+
+          {/* {props.show && !data.loading && !data.loadingSoundFonts && <GuideIndex showGuide={false} list={["finger"]} />} */}
+        </div>
+      );
+    };
+  },
+});

BIN
src/page-instrument/view-figner-listen/lsy.ttf


BIN
src/page-instrument/view-figner/image/icon_btn_1.png


BIN
src/page-instrument/view-figner/image/icon_btn_2.png


BIN
src/page-instrument/view-figner/image/icon_btn_3.png


BIN
src/page-instrument/view-figner/image/icon_btn_4.png


BIN
src/page-instrument/view-figner/image/icon_btn_green_sub.png


BIN
src/page-instrument/view-figner/image/icon_btn_red_sub.png


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
src/page-instrument/view-figner/image/icons.json


BIN
src/page-instrument/view-figner/image/tips1.png


BIN
src/page-instrument/view-figner/image/tips2.png


BIN
src/page-instrument/view-figner/image/tips3.png


BIN
src/page-instrument/view-figner/image/tips4.png


+ 181 - 17
src/page-instrument/view-figner/index.module.less

@@ -23,11 +23,10 @@
 
         }
 
-        .backBtn{
-            padding: 26px 17px 26px 29px;
+        .backBtn {
+            padding: 26px 5px 26px 18px;
         }
 
-
         .tips {
             width: 43%;
             border-radius: 18px 0px 0px 18px;
@@ -107,6 +106,53 @@
     }
 }
 
+.popoverContainer {
+    --van-popover-action-height: 32px;
+    --van-popover-action-font-size: 14px;
+    --van-popover-radius: 12px;
+    --van-popover-action-width: 85px;
+    padding: 6Px 0;
+    background-color: #fff;
+    box-shadow: 0 0.05333rem 0.32rem rgba(50, 50, 51, .12);
+    margin-top: 9px !important;
+    border-radius: 8px;
+    color: #999;
+
+    :global {
+        .van-popover__content {
+            max-height: 200px;
+            box-shadow: none;
+            overflow-y: auto;
+            overflow-x: hidden;
+
+            &::-webkit-scrollbar {
+                width: 4px;
+            }
+
+            &::-webkit-scrollbar-thumb {
+                border-radius: 12px;
+                background: rgba(0, 0, 0, 0.2);
+
+                visibility: hidden;
+            }
+
+            &::-webkit-scrollbar-track {
+                border-radius: 0;
+                background: rgba(0, 0, 0, 0.1);
+                visibility: hidden;
+            }
+        }
+
+        .van-popover__action {
+            padding: 0 9px;
+        }
+    }
+
+    .selected {
+        color: #1CACF1;
+        font-weight: 600;
+    }
+}
 
 .head {
     position: absolute;
@@ -140,10 +186,16 @@
     .left {
         display: flex;
         align-items: center;
+
+        .baseBtn {
+            margin: 0 4px;
+        }
     }
 
     .baseBtn {
-        width: 60px;
+        // width: 60px;
+        // height: 45px;
+        width: 54px;
         height: 45px;
         background: rgba(255, 255, 255, .48);
         border-radius: 10px;
@@ -221,8 +273,9 @@
         align-items: center;
         flex-shrink: 0;
         padding-bottom: 8px;
-        :global{
-            .van-button:active:before{
+
+        :global {
+            .van-button:active:before {
                 opacity: 0 !important;
             }
         }
@@ -384,6 +437,7 @@
     }
 
     .noteContent {
+        display: flex;
         position: relative;
         max-width: calc(100% - 92px);
         border-radius: 25px;
@@ -391,6 +445,10 @@
         border: 1px solid rgba(255, 255, 255, 0.6);
         overflow: hidden;
 
+        &.noteContentOther {
+            max-width: calc(100% - 92px - 52px - 5Px);
+        }
+
         &.noteContentWrap {
             &::before {
                 content: '';
@@ -421,18 +479,27 @@
 
     }
 
+    .lastNoteContent {
+        display: flex;
+        position: relative;
+        max-width: calc(100%);
+        border-radius: 0 25px 25px 0;
+        // background: rgba(255, 255, 255, 0.5);
+        // border: 1px solid rgba(255, 255, 255, 0.6);
+        overflow: hidden;
+    }
+
     .noteBox {
         display: flex;
         overflow-y: hidden;
         overflow-x: auto;
-        border-radius: 25px;
+        border-radius: 0 25px 25px 0;
+        z-index: 9;
 
         &::-webkit-scrollbar {
             width: 0;
             display: none;
         }
-
-
     }
 
     .noteBtn {
@@ -457,6 +524,36 @@
             opacity: 0 !important;
         }
     }
+
+    .tipsT {
+        position: absolute;
+        z-index: 99;
+        top: -40px;
+    }
+
+    .playTips {
+        width: 91px;
+        height: 23px;
+        background: url('./image/tips1.png') no-repeat center center / contain;
+    }
+
+    .playTips2 {
+        width: 122px;
+        height: 23px;
+        background: url('./image/tips4.png') no-repeat center center / contain;
+    }
+
+    .playError {
+        width: 83px;
+        height: 23px;
+        background: url('./image/tips3.png') no-repeat center center / contain;
+    }
+
+    .playSuccess {
+        width: 83px;
+        height: 23px;
+        background: url('./image/tips2.png') no-repeat center center / contain;
+    }
 }
 
 
@@ -480,7 +577,18 @@
         height: 100%;
     }
 
+    .showAnswer {
+        width: 20px;
+        height: 20px;
+        background: url('./image/icon_btn_green_sub.png') no-repeat center / contain;
+        position: absolute;
+        bottom: 2px;
+        right: -2px;
 
+        &.errorAnswer {
+            background: url('./image/icon_btn_red_sub.png') no-repeat center / contain;
+        }
+    }
 }
 
 .noteKey {
@@ -516,6 +624,20 @@
         position: relative;
     }
 
+    // .noteFixed {
+    //     font-size: 12px;
+    //     color: #FFFFFF;
+    //     font-weight: 600;
+    //     padding-bottom: 5px;
+    //     transform: scale(0.8);
+    //     white-space: nowrap;
+    // }
+
+    .dotFixed {
+        width: 5px;
+        height: 5px;
+    }
+
     .mark {
         position: absolute;
         left: -80%;
@@ -523,6 +645,42 @@
     }
 }
 
+.optionBtns {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    padding-bottom: 21px;
+
+    .oBtn {
+        width: 104px;
+        height: 46px;
+        border: none;
+        font-weight: 600;
+        font-size: 15px;
+        color: #fff;
+        cursor: pointer;
+        margin: 0 3px;
+
+        &.gamut {
+            background: url('./image/icon_btn_3.png') no-repeat center / contain;
+        }
+
+        &.play {
+            background: url('./image/icon_btn_2.png') no-repeat center / contain;
+        }
+
+        &.success {
+            background: url('./image/icon_btn_4.png') no-repeat center / contain;
+        }
+
+        &.disabled {
+            background: url('./image/icon_btn_1.png') no-repeat center / contain;
+            color: #616161;
+            cursor: not-allowed;
+        }
+    }
+}
+
 .fingeringContainer {
     position: relative;
     width: 100%;
@@ -702,8 +860,9 @@
         justify-content: center;
         align-items: center;
         flex-shrink: 0;
-        :global{
-            .van-button:active:before{
+
+        :global {
+            .van-button:active:before {
                 opacity: 0 !important;
             }
         }
@@ -774,7 +933,8 @@
             pointer-events: none;
         }
     }
-    .tipWrap{
+
+    .tipWrap {
         flex: 1;
         overflow: hidden;
     }
@@ -786,7 +946,7 @@
         border: 1.5px solid rgba(180, 165, 154, 1);
         color: rgba(68, 59, 59, 1);
         font-size: 12px;
-        
+
     }
 
     .toneAction {
@@ -795,11 +955,13 @@
         justify-content: center;
         align-items: center;
         padding: 16px 0;
+
         img {
             width: 45%;
             max-width: 128px;
             margin: 0 6px;
-            &:active{
+
+            &:active {
                 opacity: .85;
             }
         }
@@ -825,7 +987,7 @@
                 padding: 0;
                 padding-bottom: 40.5%;
                 flex-shrink: 0;
-                
+
 
                 &::before {
                     display: none;
@@ -842,7 +1004,8 @@
                     opacity: .8;
                 }
             }
-            .van-button--primary{
+
+            .van-button--primary {
                 --van-button-plain-background: RGBA(255, 246, 231, 1);
             }
         }
@@ -892,7 +1055,8 @@
             padding: 4px 8px;
         }
     }
-    .hulusiBtn{
+
+    .hulusiBtn {
         font-size: 10px;
         text-wrap: nowrap;
     }

+ 40 - 39
src/store.ts

@@ -1,23 +1,24 @@
 import { reactive } from "vue";
 
 type IUser = {
-	username?: string;
-	nickname?: string;
-	/** 真实姓名 */
-	realName?: string;
-	/** 会员结束时间 */
-	membershipEndTime?: string;
-	tenantId?: number;
-	/** 声部名称 */
-	subjectNames?: string;
-	subjectName?: string;
-	/** 头像 */
-	avatar?: string;
-	memberRankSettingId?: number;
-	id?: string | number;
-	clientType?: "BACKEND" | "SCHOOL" | "TEACHER" | "STUDENT";
-	/** 是否是VIP */
-	vipMember?: boolean;
+  username?: string;
+  nickname?: string;
+  /** 真实姓名 */
+  realName?: string;
+  /** 会员结束时间 */
+  membershipEndTime?: string;
+  tenantId?: number;
+  /** 声部名称 */
+  subjectId?: any;
+  subjectNames?: string;
+  subjectName?: string;
+  /** 头像 */
+  avatar?: string;
+  memberRankSettingId?: number;
+  id?: string | number;
+  clientType?: "BACKEND" | "SCHOOL" | "TEACHER" | "STUDENT";
+  /** 是否是VIP */
+  vipMember?: boolean;
 };
 type IStatus = "init" | "login" | "logout" | "error";
 type IPlatformType = "STUDENT" | "TEACHER" | "WEB" | "";
@@ -25,41 +26,41 @@ type IPlatformApi = "/api-student" | "/api-teacher" | "/api-web" | "/api-backend
 type IProxy = "" | "/gym" | "/colexiu" | "/orchestra" | "/instrument";
 
 export interface IStoreData {
-	platformType: IPlatformType;
-	platformApi: IPlatformApi;
-	proxy: IProxy;
-	isApp: boolean;
+  platformType: IPlatformType;
+  platformApi: IPlatformApi;
+  proxy: IProxy;
+  isApp: boolean;
 }
 
 export const storeData = reactive({
-	status: "init" as IStatus,
-	/** 用户信息 */
-	user: {} as IUser,
-	/** 端口 */
-	platformType: "STUDENT" as IPlatformType,
-	/** api地址前缀 */
-	platformApi: "/api-student" as IPlatformApi,
-	/** 开发模式api前缀 */
-	proxy: "" as IProxy,
-	/** 是否在APP中 */
-	isApp: false,
+  status: "init" as IStatus,
+  /** 用户信息 */
+  user: {} as IUser,
+  /** 端口 */
+  platformType: "STUDENT" as IPlatformType,
+  /** api地址前缀 */
+  platformApi: "/api-student" as IPlatformApi,
+  /** 开发模式api前缀 */
+  proxy: "" as IProxy,
+  /** 是否在APP中 */
+  isApp: false,
 });
 
 /** 初始化 */
 export const setStoreData = (data: IStoreData) => {
-	Object.assign(storeData, data);
+  Object.assign(storeData, data);
 };
 
 /** 设置用户信息 */
 export const setUserInfo = (user: IUser) => {
-	storeData.status = "login";
-	storeData.user = user || {};
+  storeData.status = "login";
+  storeData.user = user || {};
 };
 export const setLogout = () => {
-	storeData.status = "logout";
-	storeData.user = {};
+  storeData.status = "logout";
+  storeData.user = {};
 };
 export const setLoginError = () => {
-	storeData.status = "error";
-	storeData.user = {};
+  storeData.status = "error";
+  storeData.user = {};
 };

+ 3 - 0
src/view/figner-preview/index.ts

@@ -5011,3 +5011,6 @@ export const FIGNER_INSTRUMENT_DATA: { [_: string]: IFIGNER_INSTRUMENT_DATA } =
 		],
 	},
 };
+
+
+export const FIGNER_INSTRUMENT_REALKEY = [60, 62, 64, 65, 67, 69, 71, 72];

+ 313 - 305
src/view/fingering/fingering-config.ts

@@ -2,29 +2,29 @@ import { CSSProperties } from "vue";
 import relationships from "./fingering-relationships";
 
 export type ITypeFingering = {
-	json: any;
-	relationship: any;
-	height?: number | string;
-	width?: number | string;
-	maxWidth?: number;
-	styles?: CSSProperties;
+  json: any;
+  relationship: any;
+  height?: number | string;
+  width?: number | string;
+  maxWidth?: number;
+  styles?: CSSProperties;
 } | null;
 export type IFingering = {
-	name?: IVocals;
-	direction?: "vertical" | "transverse";
-	width?: string;
-	height?: string;
-	/** 禁用替指 */
-	disabledFinger?: boolean;
-	/** 横竖屏 0:横屏 1: 竖屏 */
-	orientation?: number;
-	code?: string;
-	/** 是否有替指 */
-	hasTizhi?: boolean;
+  name?: IVocals;
+  direction?: "vertical" | "transverse";
+  width?: string;
+  height?: string;
+  /** 禁用替指 */
+  disabledFinger?: boolean;
+  /** 横竖屏 0:横屏 1: 竖屏 */
+  orientation?: number;
+  code?: string;
+  /** 是否有替指 */
+  hasTizhi?: boolean;
 };
 
 type ITypeContent = {
-	[key: string | number]: IFingering;
+  [key: string | number]: IFingering;
 };
 
 export type IVocals =
@@ -56,290 +56,298 @@ export type IVocals =
   | "baroque-recorder";
 
 /** 映射声部ID */
-export const mappingVoicePart = (
-	id: number | string,
-	soruce: "GYM" | "COLEXIU" | "ORCHESTRA" | "INSTRUMENT" | "ENSEMBLE"
-): number => {
-	if (soruce === "GYM") {
-		return Number(id);
-	} else if (soruce === "COLEXIU") {
-		const subject: { [_key: string | number]: number } = {
-			Flute: 2,
-			Clarinet: 4,
-			Trombone: 14,
-			Tuba: 17,
-			Trumpet: 12,
-			Horn: 13,
-			AltoSaxophone: 6,
-			TenorSaxophone: 6,
-			Saxophone: 6,
-			UpBassHorn: 15,
-			Melodica: 137,
-			HulusiFlute: 136,
-			PanFlute: 135,
-			Ocarina: 134,
-			Recorder: 120,
-			Ukulele: 130,
-			Mouthorgan: 140,
-			Piano: 150,
-		};
-		return subject[id];
-	} else if (soruce === "ORCHESTRA") {
-		const subject: { [_key: string | number]: number } = {
-			1: 23,
-			2: 2,
-			3: 5,
-			4: 4,
-			5: 12,
-			6: 14,
-			7: 13,
-			8: 15,
-			9: 17,
-		};
-		return subject[id];
-	} else if (soruce === "INSTRUMENT") {
-		let code = id;
-		if (typeof code === "string") {
-			code = code.toLocaleLowerCase().replace(/ /g, "");
-		}
-		const subject: { [_key: string | number]: any } = {
-			flute: 2,
-			clarinet: 4,
-			trombone: 14,
-			tuba: 17,
-			trumpet: 12,
-			horn: 13,
-			altosaxophone: 6,
-			tenorsaxophone: 6,
-			saxophone: 6,
-			upbasshorn: 15,
-			melodica: 137,
-			hulusiFlute: 136,
-			panflute: 135,
-			recorder: 120,
-			ukulele: 130,
-			mouthorgan: 140,
-			piano: 150,
-			4: "piccolo",
-			3: "hulusi-flute",
-			1: "pan-flute",
-			2: "ocarina",
-			5: "melodica",
-			23: 2,
-			24: 6,
-			25: 4,
-			26: 12,
-			27: 14,
-			28: 13,
-			29: 15,
-			30: 17,
-			tenorrecorder: "piccolo",
-			woodwind: "hulusi-flute",
-			panpipes: "pan-flute",
-			ocarina: "ocarina",
-			nai: "melodica",
-		};
-		return subject[code] || 0;
-	} else if (soruce === "ENSEMBLE") {
-		let code = id;
-		const subject: { [_key: string | number]: any } = {
-			"Piccolo": "piccolo",
-			"Flute": 2,
-			"Flute 1": 2,
-			"Flute 2": 2,
-			"Oboe": 1,
-			"Clarinet in Bb 1": 4,
-			"Clarinet in Bb 2": 4,
-			"Alto Clarinet in Eb": 4,
-			"Bass Clarinet in Bb": 4,
-			"Bassoon": 1,
-			"Alto Saxophone": 5,
-			"Tenor Saxophone": 5,
-			"Baritone Saxophone": 5,
-			"Trumpet in Bb 1": 12,
-			"Trumpet in Bb 2": 12,
-			"Horn in F": 13,
-			"Horn in F 1": 13,
-			"Horn in F 2": 13,
-			"Trombone 1": 14,
-			"Trombone 2": 14,
-			"Trombone 3": 14,
-			"Euphonium": 15,
-			"Tuba": 17,
-			"Chimes": 1,
-			"Bells": 1,
-			"Xylophone": 1,
-			"Snare Drum": 1,
-			"Bass Drum": 1,
-			"Triangle": 1,
-			"Suspended Cymbal": 1,
-			"Crash Cymbals": 1,
-			"Concert Toms": 1,
-			"Timpani": 1,
-			flute: 2,
-			oboe: 4,
-			clarinet: 4,
-			trombone: 14,
-			tuba: 17,
-			trumpet: 12,
-			horn: 13,
-			altosaxophone: 6,
-			tenorsaxophone: 6,
-			saxophone: 6,
-			upbasshorn: 15,
-			melodica: 137,
-			hulusiFlute: 136,
-			panflute: 135,
-			recorder: 120,
-			ukulele: 130,
-			mouthorgan: 140,
-			piano: 150,
-			4: "piccolo",
-			3: "hulusi-flute",
-			1: "pan-flute",
-			2: "ocarina",
-			5: "melodica",
-			26: 12,
-			tenorrecorder: "piccolo",
-			woodwind: "hulusi-flute",
-			panpipes: "pan-flute",
-			ocarina: "ocarina",
-			nai: "melodica",
-		};
-		let _track;
-		if (typeof code === 'string') {
-			for (let sKey in subject) {
-				if(sKey === code) {
-					_track = subject[sKey]
-					break;
-				}
-			}
-		} else {
-			_track = subject.code
-		}
-		return _track;
-	}
-	return 0;
+export const mappingVoicePart = (id: number | string, soruce: "GYM" | "COLEXIU" | "ORCHESTRA" | "INSTRUMENT" | "ENSEMBLE"): number => {
+  if (soruce === "GYM") {
+    return Number(id);
+  } else if (soruce === "COLEXIU") {
+    const subject: { [_key: string | number]: number } = {
+      Flute: 2,
+      Clarinet: 4,
+      Trombone: 14,
+      Tuba: 17,
+      Trumpet: 12,
+      Horn: 13,
+      AltoSaxophone: 6,
+      TenorSaxophone: 6,
+      Saxophone: 6,
+      UpBassHorn: 15,
+      Melodica: 137,
+      HulusiFlute: 136,
+      PanFlute: 135,
+      Ocarina: 134,
+      Recorder: 120,
+      Ukulele: 130,
+      Mouthorgan: 140,
+      Piano: 150,
+    };
+    return subject[id];
+  } else if (soruce === "ORCHESTRA") {
+    const subject: { [_key: string | number]: number } = {
+      1: 23,
+      2: 2,
+      3: 5,
+      4: 4,
+      5: 12,
+      6: 14,
+      7: 13,
+      8: 15,
+      9: 17,
+    };
+    return subject[id];
+  } else if (soruce === "INSTRUMENT") {
+    let code = id;
+    if (typeof code === "string") {
+      code = code.toLocaleLowerCase().replace(/ /g, "");
+    }
+    const subject: { [_key: string | number]: any } = {
+      flute: 2,
+      clarinet: 4,
+      trombone: 14,
+      tuba: 17,
+      trumpet: 12,
+      horn: 13,
+      altosaxophone: 6,
+      tenorsaxophone: 6,
+      saxophone: 6,
+      upbasshorn: 15,
+      melodica: 137,
+      hulusiFlute: 136,
+      panflute: 135,
+      recorder: 120,
+      ukulele: 130,
+      mouthorgan: 140,
+      piano: 150,
+	  BaroqueRecorder: 'baroque-recorder',
+      4: "piccolo",
+      3: "hulusi-flute",
+      1: "pan-flute",
+      2: "ocarina",
+      5: "melodica",
+      23: 2,
+      24: 6,
+      25: 4,
+      26: 12,
+      27: 14,
+      28: 13,
+      29: 15,
+      30: 17,
+      tenorrecorder: "piccolo",
+      woodwind: "hulusi-flute",
+      panpipes: "pan-flute",
+      ocarina: "ocarina",
+      nai: "melodica",
+    };
+    return subject[code] || 0;
+  } else if (soruce === "ENSEMBLE") {
+    let code = id;
+    const subject: { [_key: string | number]: any } = {
+      Piccolo: "piccolo",
+      Flute: 2,
+      "Flute 1": 2,
+      "Flute 2": 2,
+      Oboe: 1,
+      "Clarinet in Bb 1": 4,
+      "Clarinet in Bb 2": 4,
+      "Alto Clarinet in Eb": 4,
+      "Bass Clarinet in Bb": 4,
+      Bassoon: 1,
+      "Alto Saxophone": 5,
+      "Tenor Saxophone": 5,
+      "Baritone Saxophone": 5,
+      "Trumpet in Bb 1": 12,
+      "Trumpet in Bb 2": 12,
+      "Horn in F": 13,
+      "Horn in F 1": 13,
+      "Horn in F 2": 13,
+      "Trombone 1": 14,
+      "Trombone 2": 14,
+      "Trombone 3": 14,
+      Euphonium: 15,
+      Tuba: 17,
+      Chimes: 1,
+      Bells: 1,
+      Xylophone: 1,
+      "Snare Drum": 1,
+      "Bass Drum": 1,
+      Triangle: 1,
+      "Suspended Cymbal": 1,
+      "Crash Cymbals": 1,
+      "Concert Toms": 1,
+      Timpani: 1,
+      flute: 2,
+      oboe: 4,
+      clarinet: 4,
+      trombone: 14,
+      tuba: 17,
+      trumpet: 12,
+      horn: 13,
+      altosaxophone: 6,
+      tenorsaxophone: 6,
+      saxophone: 6,
+      upbasshorn: 15,
+      melodica: 137,
+      hulusiFlute: 136,
+      panflute: 135,
+      recorder: 120,
+      ukulele: 130,
+      mouthorgan: 140,
+      piano: 150,
+      4: "piccolo",
+      3: "hulusi-flute",
+      1: "pan-flute",
+      2: "ocarina",
+      5: "melodica",
+      26: 12,
+      tenorrecorder: "piccolo",
+      woodwind: "hulusi-flute",
+      panpipes: "pan-flute",
+      ocarina: "ocarina",
+      nai: "melodica",
+	  BaroqueRecorder: 'baroque-recorder',
+    };
+    let _track;
+    if (typeof code === "string") {
+      for (let sKey in subject) {
+        if (sKey === code) {
+          _track = subject[sKey];
+          break;
+        }
+      }
+    } else {
+      _track = subject.code;
+    }
+    return _track;
+  }
+  return 0;
 };
 
 /** 声部的指法配置信息 */
 export const subjectFingering = (subjectId: number | string): IFingering => {
-	switch (subjectId) {
-		case 2: // 长笛
-			return {
-				name: "flute",
-				direction: "transverse",
-				height: "1.6rem",
-				hasTizhi: true,
-			};
-		case 4: // 单簧管
-			return {
-				name: "clarinet",
-				direction: "vertical",
-				width: "3rem",
-				hasTizhi: true,
-			};
-		case 5: // 萨克斯
-		case 6: // 中音萨克斯
-			return {
-				name: "saxophone",
-				direction: "vertical",
-				width: "4.34rem",
-				hasTizhi: true,
-			};
-		case 12: // 小号
-			return {
-				name: "trumpet",
-				direction: "transverse",
-				height: "1.6rem",
-				hasTizhi: false,
-			};
-		case 13: // 圆号
-			return {
-				name: "horn",
-				direction: "vertical",
-				width: "4.98rem",
-				hasTizhi: false,
-			};
-		case 14: // 长号
-			return {
-				name: "trombone",
-				direction: "transverse",
-				height: "1.6rem",
-				hasTizhi: false,
-			};
-		case 15: // 上低音号
-			return {
-				name: "up-bass-horn",
-				direction: "vertical",
-				width: "4.34rem",
-				hasTizhi: false,
-			};
-		case 17: // 大号
-			return {
-				name: "tuba",
-				direction: "vertical",
-				width: "4.34rem",
-				hasTizhi: false,
-			};
-		case 120: // 短笛
-			return {
-				name: "piccolo",
-				direction: "vertical",
-				width: "3rem",
-				orientation: 1,
-				hasTizhi: true,
-			};
-		case "piccolo": // 竖笛
-			return {
-				name: "piccolo",
-				direction: "vertical",
-				width: "3rem",
-				orientation: 1,
-				code: "竖笛",
-				hasTizhi: true,
-			};
-		case "hulusi-flute": // 葫芦丝
-			return {
-				name: "hulusi-flute",
-				direction: "vertical",
-				width: "3rem",
-				orientation: 1,
-				code: "葫芦丝",
-				hasTizhi: false,
-			};
-		case "pan-flute": // 排箫
-			return {
-				name: "pan-flute",
-				direction: "transverse",
-				height: "2rem",
-				disabledFinger: true,
-				orientation: 0,
-				code: "排箫",
-				hasTizhi: false,
-			};
-		case "ocarina": // 陶笛
-			return {
-				name: "ocarina",
-				direction: "vertical",
-				width: "3rem",
-				disabledFinger: true,
-				orientation: 0,
-				code: "陶笛",
-				hasTizhi: false,
-			};
-		case "melodica": // 口风琴
-			return {
-				name: "melodica",
-				direction: "transverse",
-				height: "2rem",
-				orientation: 0,
-				code: "口风琴",
-				hasTizhi: false,
-			};
-		default:
-			return {};
-	}
+  switch (subjectId) {
+    case 2: // 长笛
+      return {
+        name: "flute",
+        direction: "transverse",
+        height: "1.6rem",
+        hasTizhi: true,
+      };
+    case 4: // 单簧管
+      return {
+        name: "clarinet",
+        direction: "vertical",
+        width: "3rem",
+        hasTizhi: true,
+      };
+    case 5: // 萨克斯
+    case 6: // 中音萨克斯
+      return {
+        name: "saxophone",
+        direction: "vertical",
+        width: "4.34rem",
+        hasTizhi: true,
+      };
+    case 12: // 小号
+      return {
+        name: "trumpet",
+        direction: "transverse",
+        height: "1.6rem",
+        hasTizhi: false,
+      };
+    case 13: // 圆号
+      return {
+        name: "horn",
+        direction: "vertical",
+        width: "4.98rem",
+        hasTizhi: false,
+      };
+    case 14: // 长号
+      return {
+        name: "trombone",
+        direction: "transverse",
+        height: "1.6rem",
+        hasTizhi: false,
+      };
+    case 15: // 上低音号
+      return {
+        name: "up-bass-horn",
+        direction: "vertical",
+        width: "4.34rem",
+        hasTizhi: false,
+      };
+    case 17: // 大号
+      return {
+        name: "tuba",
+        direction: "vertical",
+        width: "4.34rem",
+        hasTizhi: false,
+      };
+    case 120: // 短笛
+      return {
+        name: "piccolo",
+        direction: "vertical",
+        width: "3rem",
+        orientation: 1,
+        hasTizhi: true,
+      };
+    case "piccolo": // 德式竖笛
+      return {
+        name: "piccolo",
+        direction: "vertical",
+        width: "3rem",
+        orientation: 1,
+        code: "竖笛",
+        hasTizhi: true,
+      };
+    case "hulusi-flute": // 葫芦丝
+      return {
+        name: "hulusi-flute",
+        direction: "vertical",
+        width: "3rem",
+        orientation: 1,
+        code: "葫芦丝",
+        hasTizhi: false,
+      };
+    case "pan-flute": // 排箫
+      return {
+        name: "pan-flute",
+        direction: "transverse",
+        height: "2rem",
+        disabledFinger: true,
+        orientation: 0,
+        code: "排箫",
+        hasTizhi: false,
+      };
+    case "ocarina": // 陶笛
+      return {
+        name: "ocarina",
+        direction: "vertical",
+        width: "3rem",
+        disabledFinger: true,
+        orientation: 0,
+        code: "陶笛",
+        hasTizhi: false,
+      };
+    case "melodica": // 口风琴
+      return {
+        name: "melodica",
+        direction: "transverse",
+        height: "2rem",
+        orientation: 0,
+        code: "口风琴",
+        hasTizhi: false,
+      };
+	case "baroque-recorder": // 英式竖笛
+	  return {
+		name: "baroque-recorder",
+		direction: "vertical",
+		width: "3rem",
+		orientation: 1,
+		code: "竖笛",
+		hasTizhi: true,
+	  };	  
+    default:
+      return {};
+  }
 };
 
 export const getFingeringConfig = async (type: IVocals | undefined): Promise<ITypeFingering> => {
@@ -389,12 +397,6 @@ export const getFingeringConfig = async (type: IVocals | undefined): Promise<ITy
         json: piccolo.default,
         relationship: relationships.piccolo,
       };
-	case "baroque-recorder":
-	const baroqueRecorder = await import(`./fingering-img/baroque-recorder/index.json`);
-	return {
-		json: baroqueRecorder.default,
-		relationship: relationships.baroqueRecorder,
-	};	  
     case "piccolo1":
       const piccolo1 = await import(`./fingering-img/piccolo1/index.json`);
       return {
@@ -543,7 +545,13 @@ export const getFingeringConfig = async (type: IVocals | undefined): Promise<ITy
           marginTop: "auto",
         },
       };
+	case "baroque-recorder":
+		const baroqueRecorder = await import(`./fingering-img/baroque-recorder/index.json`);
+		return {
+			json: baroqueRecorder.default,
+			relationship: relationships.baroqueRecorder,
+		};  	  
     default:
       return null;
   }
-};
+};

Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
src/view/fingering/fingering-img/hulusi-flute/index.json


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
src/view/fingering/fingering-img/hulusi-flute1/index.json


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
src/view/fingering/fingering-img/melodica/index.json


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
src/view/fingering/fingering-img/melodica1/index.json


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
src/view/fingering/fingering-img/ocarina1/index.json


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
src/view/fingering/fingering-img/pan-flute/index.json


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
src/view/fingering/fingering-img/pan-flute1/index.json


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
src/view/fingering/fingering-img/pan-flute3/index.json


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
src/view/fingering/fingering-img/piccolo/index.json


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
src/view/fingering/fingering-img/piccolo1/index.json


Неке датотеке нису приказане због велике количине промена