Browse Source

Merge branch 'feature-tianyong' into gym-dev

TIANYONG 1 month ago
parent
commit
155605ceb6
100 changed files with 680 additions and 445 deletions
  1. 0 1
      dist/css/index-23ff396c.css
  2. 0 0
      dist/css/index-8f0b3834.css
  3. 1 0
      dist/css/index-aa672475.css
  4. 1 0
      dist/css/instrument-2961d3e7.css
  5. 1 0
      dist/css/instrument-b327992e.css
  6. 0 1
      dist/css/modeView-c4c5480d.css
  7. 11 1
      dist/instrument.html
  8. 4 0
      dist/js/index-24b018ba.js
  9. 0 0
      dist/js/index-38da8b16.js
  10. 1 0
      dist/js/index-4f0ded3f.js
  11. 5 0
      dist/js/index-98612534.js
  12. 1 0
      dist/js/index-acb8a89e.js
  13. 0 0
      dist/js/index-b18c1417.js
  14. 0 0
      dist/js/index-c46b557b.js
  15. 0 0
      dist/js/index-f23e3dbf.js
  16. 0 0
      dist/js/index-legacy-06a5aa41.js
  17. 0 0
      dist/js/index-legacy-2eb3d340.js
  18. 1 0
      dist/js/index-legacy-4fae1ae5.js
  19. 0 0
      dist/js/index-legacy-51cf0eb7.js
  20. 5 0
      dist/js/index-legacy-5816d614.js
  21. 1 0
      dist/js/index-legacy-955740ec.js
  22. 0 0
      dist/js/index-legacy-9b4d7da4.js
  23. 4 0
      dist/js/index-legacy-f321a0d0.js
  24. 0 0
      dist/js/instrument-e10b8181.js
  25. 0 0
      dist/js/instrument-legacy-b493ffbb.js
  26. 1 0
      dist/js/modeView-31f847f2.js
  27. 1 0
      dist/js/modeView-legacy-129fa188.js
  28. 0 0
      dist/js/polyfills-3291dfd6.js
  29. 0 0
      dist/js/polyfills-86411078.js
  30. 0 0
      dist/js/polyfills-legacy-b653339e.js
  31. BIN
      dist/png/audio-pan-cd59ec13.png
  32. BIN
      dist/png/audio-pan-f4738bc4.png
  33. BIN
      dist/png/cancelBtn-3ab99c9b.png
  34. BIN
      dist/png/cancelBtn-741db7a5.png
  35. BIN
      dist/png/gl-0a9176b7.png
  36. BIN
      dist/png/glImg-a338f32f.png
  37. BIN
      dist/png/glImg-d3eac918.png
  38. BIN
      dist/png/icon_bg-d91f5fbc.png
  39. BIN
      dist/png/icon_btn-0e47c646.png
  40. BIN
      dist/png/icon_btn-60e05a0a.png
  41. BIN
      dist/png/lx-4dd7abe9.png
  42. BIN
      dist/png/lxImg-e8f0b8ae.png
  43. BIN
      dist/png/lxImg-fbb47a02.png
  44. BIN
      dist/png/modalDragBg-bb96be8c.png
  45. BIN
      dist/png/modalDragBg2-49467837.png
  46. BIN
      dist/png/modalDragBgLeft-2bf56331.png
  47. BIN
      dist/png/modalDragBgRight-ba78929e.png
  48. BIN
      dist/png/modalDragDone-778539d8.png
  49. BIN
      dist/png/no_erji-ba8ab7da.png
  50. BIN
      dist/png/no_erji-d48d9289.png
  51. BIN
      dist/png/okBtn-165dcef2.png
  52. BIN
      dist/png/okBtn-a21777e5.png
  53. BIN
      dist/png/pc-bb226da5.png
  54. BIN
      dist/png/pcImg-32762e6c.png
  55. BIN
      dist/png/pcImg-3dcac44f.png
  56. BIN
      dist/png/pitchHigh-5caac9d1.png
  57. BIN
      dist/png/pitchLow-3223f352.png
  58. BIN
      dist/png/tip_erji-79083763.png
  59. BIN
      dist/png/tip_erji-f7865e7f.png
  60. BIN
      dist/png/tips-02a6a659.png
  61. BIN
      dist/png/ty-56e3a830.png
  62. BIN
      dist/png/videobg-01c75ff9.png
  63. BIN
      dist/png/videobg-28992a9b.png
  64. BIN
      dist/wav/tick-7706b760.wav
  65. BIN
      dist/wav/tock-32d5f74b.wav
  66. 1 1
      osmd-extended
  67. 0 45
      report-share.html
  68. BIN
      src/assets/tick.wav
  69. BIN
      src/assets/tock.wav
  70. 3 1
      src/constant/instruments.ts
  71. 2 0
      src/constant/instrumentsClassfiy.ts
  72. 72 0
      src/helpers/beatConfig.ts
  73. 11 0
      src/helpers/customMusicScore.ts
  74. 73 71
      src/helpers/formateMusic.ts
  75. 126 122
      src/helpers/metronome.ts
  76. 29 0
      src/helpers/svgToPng.ts
  77. 5 5
      src/page-instrument/api.ts
  78. BIN
      src/page-instrument/component/the-music-list/imgs/icon-music-vip.png
  79. BIN
      src/page-instrument/component/the-music-list/imgs/searImg.png
  80. 4 4
      src/page-instrument/component/the-music-list/index.module.less
  81. 2 3
      src/page-instrument/component/the-music-list/index.tsx
  82. 19 5
      src/page-instrument/component/the-music-list/list.tsx
  83. 33 0
      src/page-instrument/component/vip/index.module.less
  84. 110 0
      src/page-instrument/component/vip/index.tsx
  85. BIN
      src/page-instrument/component/vip/tips.png
  86. 13 9
      src/page-instrument/custom-plugins/ExerciseStatistics/index.module.less
  87. 12 1
      src/page-instrument/custom-plugins/ExerciseStatistics/index.tsx
  88. 31 9
      src/page-instrument/custom-plugins/guide-driver/index.less
  89. 76 36
      src/page-instrument/custom-plugins/guide-driver/index.tsx
  90. 6 5
      src/page-instrument/custom-plugins/helper-model/recommendation/index.module.less
  91. 9 4
      src/page-instrument/custom-plugins/recording-time/index.tsx
  92. BIN
      src/page-instrument/custom-plugins/the-vip/icon_bg.png
  93. BIN
      src/page-instrument/custom-plugins/the-vip/icon_btn.png
  94. BIN
      src/page-instrument/custom-plugins/the-vip/icon_btn_cancel.png
  95. BIN
      src/page-instrument/custom-plugins/the-vip/icon_close.png
  96. BIN
      src/page-instrument/custom-plugins/the-vip/icon_title.png
  97. 0 60
      src/page-instrument/custom-plugins/the-vip/index.module.less
  98. 0 59
      src/page-instrument/custom-plugins/the-vip/index.tsx
  99. 4 1
      src/page-instrument/custom-plugins/work-home/index.tsx
  100. 1 1
      src/page-instrument/custom-plugins/work-index/index.tsx

+ 0 - 1
dist/css/index-23ff396c.css

@@ -1 +0,0 @@
-body{overflow:hidden}._skeleton_oe0r3_4{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_oe0r3_15{width:100vw;height:auto;overflow:hidden;--header-height: 1.65333rem;background:transparent;position:relative}._detail_oe0r3_15 ._mask_oe0r3_23{position:absolute;z-index:6;width:100%;height:100%}._detail_oe0r3_15 ._container_oe0r3_29{margin:0;border-radius:.26667rem}._detail_oe0r3_15 #osmdCanvasPage1{position:relative!important}._detail_oe0r3_15 #musicAndSelection{height:initial!important;max-height:initial!important}._detail_oe0r3_15 .smoothAnimationBox{height:0!important;overflow:hidden}._detail_oe0r3_15 #cursorImg-0{margin-top:-20PX!important;transform:translate(6PX)!important}._whiteBg_oe0r3_48{background:#fff}

File diff suppressed because it is too large
+ 0 - 0
dist/css/index-8f0b3834.css


+ 1 - 0
dist/css/index-aa672475.css

@@ -0,0 +1 @@
+body{overflow:hidden}._skeleton_li4n4_4{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_li4n4_15{width:100vw;height:auto;overflow:hidden;--header-height: 1.65333rem;background:transparent;position:relative}._detail_li4n4_15 ._mask_li4n4_23{position:absolute;z-index:6;width:100%;height:100%}._detail_li4n4_15 ._container_li4n4_29{margin:0;border-radius:.26667rem}._detail_li4n4_15 #osmdCanvasPage1{position:relative!important}._detail_li4n4_15 #musicAndSelection{height:initial!important;max-height:initial!important}._detail_li4n4_15 .smoothAnimationBox{height:0!important;overflow:hidden}._detail_li4n4_15 #cursorImg-0{margin-top:-20PX!important;opacity:0!important}._whiteBg_li4n4_48{background:#fff}

File diff suppressed because it is too large
+ 1 - 0
dist/css/instrument-2961d3e7.css


File diff suppressed because it is too large
+ 1 - 0
dist/css/instrument-b327992e.css


+ 0 - 1
dist/css/modeView-c4c5480d.css

@@ -1 +0,0 @@
-._container_jp744_1{position:relative;width:7.41333rem;height:6.72rem;background:url(../png/icon_bg-d91f5fbc.png) no-repeat;background-size:contain;display:flex;flex-direction:column;padding-top:3.36rem}._close_jp744_11{position:absolute;right:0;top:.8rem;width:.64rem;height:.64rem}._title_jp744_18{margin-left:.37333rem;width:2.13333rem;display:block}._content_jp744_23{position:relative;padding:0 .34667rem .66667rem;font-size:.37333rem;font-weight:400;color:#333;line-height:.58667rem;z-index:10}._btns_jp744_32{margin:0 auto .61333rem;display:flex;justify-content:center;font-size:.42667rem;color:#777;line-height:.58667rem;text-align:center}._btns_jp744_32 ._btn_jp744_32{width:2.69333rem;height:.98667rem;cursor:pointer}._btns_jp744_32 ._btnCancel_jp744_46{margin-right:.26667rem}._btns_jp744_32 img{width:100%}

+ 11 - 1
dist/instrument.html

@@ -2,7 +2,7 @@
 <html lang="en">
 
 <head>
-  <script type="module" crossorigin src="./js/polyfills-86411078.js"></script>
+  <script type="module" crossorigin src="./js/polyfills-3291dfd6.js"></script>
 
   <meta charset="UTF-8" />
   <meta name="viewport"
@@ -41,8 +41,13 @@
       })
     }
   </script>
+<<<<<<< HEAD
   <script type="module" crossorigin src="./js/instrument-209332b4.js"></script>
   <link rel="stylesheet" href="./css/instrument-2961d3e7.css">
+=======
+  <script type="module" crossorigin src="./js/instrument-e10b8181.js"></script>
+  <link rel="stylesheet" href="./css/instrument-b327992e.css">
+>>>>>>> feature-tianyong
   <script type="module">import.meta.url;import("_").catch(()=>1);async function* g(){};window.__vite_is_modern_browser=true;</script>
   <script type="module">!function(){if(window.__vite_is_modern_browser)return;console.warn("vite: loading legacy chunks, syntax error above and the same error below should be ignored");var e=document.getElementById("vite-legacy-polyfill"),n=document.createElement("script");n.src=e.src,n.onload=function(){System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))},document.body.appendChild(n)}();</script>
 </head>
@@ -65,8 +70,13 @@
     var vConsole = new window.VConsole();
   </script>   -->
   <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>
+<<<<<<< HEAD
   <script nomodule crossorigin id="vite-legacy-polyfill" src="./js/polyfills-legacy-f54b6d40.js"></script>
   <script nomodule crossorigin id="vite-legacy-entry" data-src="./js/instrument-legacy-bc9a4a23.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
+=======
+  <script nomodule crossorigin id="vite-legacy-polyfill" src="./js/polyfills-legacy-b653339e.js"></script>
+  <script nomodule crossorigin id="vite-legacy-entry" data-src="./js/instrument-legacy-b493ffbb.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
+>>>>>>> feature-tianyong
 </body>
 
 </html>

+ 4 - 0
dist/js/index-24b018ba.js

@@ -1 +1,5 @@
+<<<<<<<< HEAD:dist/js/index-24b018ba.js
 import{d as i,g as l,r as d,E as e,o as r,s as c,b as s,M as u}from"./instrument-209332b4.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:""}]});r(()=>{window.appName="colexiu",c.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,r as d,E as e,o as r,s as c,b as s,M as u}from"./instrument-e10b8181.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:""}]});r(()=>{window.appName="colexiu",c.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};
+>>>>>>>> feature-tianyong:dist/js/index-98612534.js

File diff suppressed because it is too large
+ 0 - 0
dist/js/index-38da8b16.js


File diff suppressed because it is too large
+ 1 - 0
dist/js/index-4f0ded3f.js


+ 5 - 0
dist/js/index-98612534.js

@@ -0,0 +1,5 @@
+<<<<<<<< HEAD:dist/js/index-24b018ba.js
+import{d as i,g as l,r as d,E as e,o as r,s as c,b as s,M as u}from"./instrument-209332b4.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:""}]});r(()=>{window.appName="colexiu",c.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,r as d,E as e,o as r,s as c,b as s,M as u}from"./instrument-e10b8181.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:""}]});r(()=>{window.appName="colexiu",c.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};
+>>>>>>>> feature-tianyong:dist/js/index-98612534.js

File diff suppressed because it is too large
+ 1 - 0
dist/js/index-acb8a89e.js


File diff suppressed because it is too large
+ 0 - 0
dist/js/index-b18c1417.js


File diff suppressed because it is too large
+ 0 - 0
dist/js/index-c46b557b.js


File diff suppressed because it is too large
+ 0 - 0
dist/js/index-f23e3dbf.js


File diff suppressed because it is too large
+ 0 - 0
dist/js/index-legacy-06a5aa41.js


File diff suppressed because it is too large
+ 0 - 0
dist/js/index-legacy-2eb3d340.js


File diff suppressed because it is too large
+ 1 - 0
dist/js/index-legacy-4fae1ae5.js


File diff suppressed because it is too large
+ 0 - 0
dist/js/index-legacy-51cf0eb7.js


+ 5 - 0
dist/js/index-legacy-5816d614.js

@@ -0,0 +1,5 @@
+<<<<<<<< HEAD:dist/js/index-legacy-f321a0d0.js
+System.register(["./instrument-legacy-bc9a4a23.js"],(function(e,t){"use strict";var i,n,a,o,r,s,l,d,c=document.createElement("style");return c.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(c),{setters:[e=>{i=e.d,n=e.g,a=e.r,o=e.E,r=e.o,s=e.s,l=e.b,d=e.M}],execute:function(){const t="_detail_vtlsh_12",c="_container_vtlsh_20";e("default",i({name:"music-list",setup(){const e=n(),i=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,i.isLoading=!1}));const h=async()=>{console.log("渲染完成")};return()=>l("div",{class:t},[l("div",{id:"scrollContainer",class:[c,"hideCursor"]},[!i.isLoading&&l(d,{onRendered:h},null)])])}}))}}}));
+========
+System.register(["./instrument-legacy-b493ffbb.js"],(function(e,t){"use strict";var i,n,a,o,r,s,l,d,c=document.createElement("style");return c.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(c),{setters:[e=>{i=e.d,n=e.g,a=e.r,o=e.E,r=e.o,s=e.s,l=e.b,d=e.M}],execute:function(){const t="_detail_vtlsh_12",c="_container_vtlsh_20";e("default",i({name:"music-list",setup(){const e=n(),i=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,i.isLoading=!1}));const h=async()=>{console.log("渲染完成")};return()=>l("div",{class:t},[l("div",{id:"scrollContainer",class:[c,"hideCursor"]},[!i.isLoading&&l(d,{onRendered:h},null)])])}}))}}}));
+>>>>>>>> feature-tianyong:dist/js/index-legacy-5816d614.js

File diff suppressed because it is too large
+ 1 - 0
dist/js/index-legacy-955740ec.js


File diff suppressed because it is too large
+ 0 - 0
dist/js/index-legacy-9b4d7da4.js


+ 4 - 0
dist/js/index-legacy-f321a0d0.js

@@ -1 +1,5 @@
+<<<<<<<< HEAD:dist/js/index-legacy-f321a0d0.js
 System.register(["./instrument-legacy-bc9a4a23.js"],(function(e,t){"use strict";var i,n,a,o,r,s,l,d,c=document.createElement("style");return c.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(c),{setters:[e=>{i=e.d,n=e.g,a=e.r,o=e.E,r=e.o,s=e.s,l=e.b,d=e.M}],execute:function(){const t="_detail_vtlsh_12",c="_container_vtlsh_20";e("default",i({name:"music-list",setup(){const e=n(),i=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,i.isLoading=!1}));const h=async()=>{console.log("渲染完成")};return()=>l("div",{class:t},[l("div",{id:"scrollContainer",class:[c,"hideCursor"]},[!i.isLoading&&l(d,{onRendered:h},null)])])}}))}}}));
+========
+System.register(["./instrument-legacy-b493ffbb.js"],(function(e,t){"use strict";var i,n,a,o,r,s,l,d,c=document.createElement("style");return c.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(c),{setters:[e=>{i=e.d,n=e.g,a=e.r,o=e.E,r=e.o,s=e.s,l=e.b,d=e.M}],execute:function(){const t="_detail_vtlsh_12",c="_container_vtlsh_20";e("default",i({name:"music-list",setup(){const e=n(),i=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,i.isLoading=!1}));const h=async()=>{console.log("渲染完成")};return()=>l("div",{class:t},[l("div",{id:"scrollContainer",class:[c,"hideCursor"]},[!i.isLoading&&l(d,{onRendered:h},null)])])}}))}}}));
+>>>>>>>> feature-tianyong:dist/js/index-legacy-5816d614.js

File diff suppressed because it is too large
+ 0 - 0
dist/js/instrument-e10b8181.js


File diff suppressed because it is too large
+ 0 - 0
dist/js/instrument-legacy-b493ffbb.js


+ 1 - 0
dist/js/modeView-31f847f2.js

@@ -0,0 +1 @@
+import{d as c,K as r,a1 as i,q as m,b as o,a2 as u,a3 as a,s as e,a4 as t,a5 as s,a6 as g,a7 as h,a8 as p}from"./instrument-e10b8181.js";const v=c({name:"modeView",setup(){var l;r(()=>i.socketErrorStatus,()=>{i.socketErrorStatus===2&&setTimeout(()=>{i.socketErrorPop=!1},1e3)});const n=m(),d=((l=navigator==null?void 0:navigator.userAgent)==null?void 0:l.includes("UAWEIVRD-W09"))||(n==null?void 0:n.iPad)||n.isTablet;return()=>o("div",{class:[a.modeView,d&&a.isiPad,s.modeType!=="init"&&a.hidden]},[o("img",{src:u,class:a.back,onClick:()=>{e.isSingleLine&&(t.isShow.value=e.melodyLine),s.oldModeType!=="practise"&&(i.needCheckErjiStatus=!1,s.handleChangeModeType(s.oldModeType)),s.modeType="show"}},null),o("div",{class:[a.modeBox,(!e.isPercussion&&!e.enableEvaluation||e.isPercussion&&e.enableEvaluation||e.isPercussion&&!e.enableEvaluation)&&a.twoModeBox]},[o("img",{class:a.modeImg,src:g,onClick:()=>{e.isSingleLine&&(t.isShow.value=e.melodyLine),s.handleChangeModeType("practise")}},null),!e.isPercussion&&o("img",{class:a.modeImg,src:h,onClick:()=>s.handleChangeModeType("follow")},null),e.enableEvaluation&&o("img",{class:a.modeImg,src:p,onClick:()=>{i.needCheckErjiStatus=!0,s.handleChangeModeType("evaluating")}},null)])])}});export{v as default};

+ 1 - 0
dist/js/modeView-legacy-129fa188.js

@@ -0,0 +1 @@
+System.register(["./instrument-legacy-b493ffbb.js"],(function(e,i){"use strict";var s,a,n,o,l,t,d,r,u,c,m,g,v;return{setters:[e=>{s=e.d,a=e.K,n=e.a1,o=e.q,l=e.b,t=e.a2,d=e.a3,r=e.s,u=e.a4,c=e.a5,m=e.a6,g=e.a7,v=e.a8}],execute:function(){e("default",s({name:"modeView",setup(){var e,i;a((()=>n.socketErrorStatus),(()=>{2===n.socketErrorStatus&&setTimeout((()=>{n.socketErrorPop=!1}),1e3)}));const s=o(),h=(null===(e=navigator)||void 0===e||null===(i=e.userAgent)||void 0===i?void 0:i.includes("UAWEIVRD-W09"))||(null==s?void 0:s.iPad)||s.isTablet;return()=>l("div",{class:[d.modeView,h&&d.isiPad,"init"!==c.modeType&&d.hidden]},[l("img",{src:t,class:d.back,onClick:()=>{r.isSingleLine&&(u.isShow.value=r.melodyLine),"practise"!==c.oldModeType&&(n.needCheckErjiStatus=!1,c.handleChangeModeType(c.oldModeType)),c.modeType="show"}},null),l("div",{class:[d.modeBox,(!r.isPercussion&&!r.enableEvaluation||r.isPercussion&&r.enableEvaluation||r.isPercussion&&!r.enableEvaluation)&&d.twoModeBox]},[l("img",{class:d.modeImg,src:m,onClick:()=>{r.isSingleLine&&(u.isShow.value=r.melodyLine),c.handleChangeModeType("practise")}},null),!r.isPercussion&&l("img",{class:d.modeImg,src:g,onClick:()=>c.handleChangeModeType("follow")},null),r.enableEvaluation&&l("img",{class:d.modeImg,src:v,onClick:()=>{n.needCheckErjiStatus=!0,c.handleChangeModeType("evaluating")}},null)])])}}))}}}));

File diff suppressed because it is too large
+ 0 - 0
dist/js/polyfills-3291dfd6.js


File diff suppressed because it is too large
+ 0 - 0
dist/js/polyfills-86411078.js


File diff suppressed because it is too large
+ 0 - 0
dist/js/polyfills-legacy-b653339e.js


BIN
dist/png/audio-pan-cd59ec13.png


BIN
dist/png/audio-pan-f4738bc4.png


BIN
dist/png/cancelBtn-3ab99c9b.png


BIN
dist/png/cancelBtn-741db7a5.png


BIN
dist/png/gl-0a9176b7.png


BIN
dist/png/glImg-a338f32f.png


BIN
dist/png/glImg-d3eac918.png


BIN
dist/png/icon_bg-d91f5fbc.png


BIN
dist/png/icon_btn-0e47c646.png


BIN
dist/png/icon_btn-60e05a0a.png


BIN
dist/png/lx-4dd7abe9.png


BIN
dist/png/lxImg-e8f0b8ae.png


BIN
dist/png/lxImg-fbb47a02.png


BIN
dist/png/modalDragBg-bb96be8c.png


BIN
dist/png/modalDragBg2-49467837.png


BIN
dist/png/modalDragBgLeft-2bf56331.png


BIN
dist/png/modalDragBgRight-ba78929e.png


BIN
dist/png/modalDragDone-778539d8.png


BIN
dist/png/no_erji-ba8ab7da.png


BIN
dist/png/no_erji-d48d9289.png


BIN
dist/png/okBtn-165dcef2.png


BIN
dist/png/okBtn-a21777e5.png


BIN
dist/png/pc-bb226da5.png


BIN
dist/png/pcImg-32762e6c.png


BIN
dist/png/pcImg-3dcac44f.png


BIN
dist/png/pitchHigh-5caac9d1.png


BIN
dist/png/pitchLow-3223f352.png


BIN
dist/png/tip_erji-79083763.png


BIN
dist/png/tip_erji-f7865e7f.png


BIN
dist/png/tips-02a6a659.png


BIN
dist/png/ty-56e3a830.png


BIN
dist/png/videobg-01c75ff9.png


BIN
dist/png/videobg-28992a9b.png


BIN
dist/wav/tick-7706b760.wav


BIN
dist/wav/tock-32d5f74b.wav


+ 1 - 1
osmd-extended

@@ -1 +1 @@
-Subproject commit e77aa077f43f575035a4b3821baab0d1e91534c6
+Subproject commit 46bdba03a3654e74d0ad2bd61e993a2467d0f80e

+ 0 - 45
report-share.html

@@ -1,45 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-
-<head>
-  <meta charset="UTF-8" />
-  <!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> -->
-  <meta name="viewport"
-    content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover" />
-  <title>管乐团云练习</title>
-  <!-- <link rel="icon" href="/favicon.ico" /> -->
-  <script src="/flexible.js" charset="UTF-8"></script>
-  <script src="/helpers/lottie.min.js" charset="UTF-8"></script>
-  <style>
-    #loading {
-      position: fixed;
-      z-index: 100;
-      top: 50%;
-      left: 50%;
-      width: 100Px;
-      height: 100Px;
-      transform: translate(-50%, -50%);
-      pointer-events: none;
-      transition: opacity .3s;
-    }
-  </style>
-</head>
-
-<body>
-  <div id="app"></div>
-  <div id="loading"></div>
-  <script>
-    lottie.loadAnimation({
-      container: document.getElementById('loading'),
-      renderer: 'svg',
-      width: '30px',
-      height: '30px',
-      loop: true,
-      autoplay: true,
-      path: './loading.json'
-    });
-  </script>
-  <script type="module" src="/src/report-share/orchestra-share/main.ts"></script>
-</body>
-
-</html>

BIN
src/assets/tick.wav


BIN
src/assets/tock.wav


+ 3 - 1
src/constant/instruments.ts

@@ -201,7 +201,9 @@ const instruments: any = {
 	'Brake Drum': '闸鼓',
 	'Tam-tam': '大锣',
 	Cymbal: '镲',
-	Cymbals: '镲'
+	Cymbals: '镲',
+	Whip: '乐鞭',
+	whip: '乐鞭'
 };
 /** 获取分轨名称 */
 export const getInstrumentName = (name = '') => {

+ 2 - 0
src/constant/instrumentsClassfiy.ts

@@ -197,6 +197,8 @@ const instrumentsClassfiy: any = {
 		"Drums set",
 		"High Bongo",
 		"Timbales",
+		"Whip",
+		"whip"
 	],
 };
 

+ 72 - 0
src/helpers/beatConfig.ts

@@ -0,0 +1,72 @@
+export const unitObj = {
+   "1/1": 1 / 1,
+   "1/2": 1 / 2,
+   "1/4": 1 / 4,
+   "1/8": 1 / 8,
+   "1/16": 1 / 16,
+   "1/2.": (1 / 2) * 1.5,
+   "1/4.": (1 / 4) * 1.5,
+   "1/8.": (1 / 8) * 1.5
+} as Record<string, any>
+
+/**
+ * 速度转换,几分音符的速度转为几分音符的速度
+ */
+export const speedBeatTo = (speedBeat: { unit: string; speed: number }, unit: string) => {
+   return (unitObj[speedBeat.unit] * speedBeat.speed) / unitObj[unit]
+}
+
+/** 谱面速度节拍器转为 约定的节拍器符号 */
+export function beatUnitTo(beatUnit: string, isDot: boolean) {
+   let multiple = "1/4"
+   switch (beatUnit) {
+      case "1024th":
+         multiple = "1/1024"
+         break
+      case "512th":
+         multiple = "1/512"
+         break
+      case "256th":
+         multiple = "1/256"
+         break
+      case "128th":
+         multiple = "1/128"
+         break
+      case "64th":
+         multiple = "1/64"
+         break
+      case "32nd":
+         multiple = "1/32"
+         break
+      case "16th":
+         multiple = "1/16"
+         break
+      case "eighth":
+         multiple = "1/8"
+         break
+      case "quarter":
+         multiple = "1/4"
+         break
+      case "half":
+         multiple = "1/2"
+         break
+      case "whole":
+         multiple = "1/1"
+      default:
+         break
+   }
+   isDot && (multiple += ".")
+   return multiple
+}
+
+/** 几分音符对应的速度图片 */
+export const unitImgs = {
+   "1/1": 'speed1',
+   "1/2": 'speed2',
+   "1/4": 'speed3',
+   "1/8": 'speed4',
+   "1/16": 'spee5',
+   "1/2.": 'speed6',
+   "1/4.": 'speed7',
+   "1/8.": 'speed8',
+} as Record<string, any>

+ 11 - 0
src/helpers/customMusicScore.ts

@@ -698,6 +698,11 @@ const transSinglePage = () => {
 			needTransTop = Math.min(maxTop, needTransTop)
 			// @ts-ignore
 			document.getElementById('osmdSvgPage1').style.transform = `translateY(-${needTransTop}px)`;
+			// 一行谱需要同时偏移光标的位置
+			const cursorDom = document.getElementById('cursorImg-0') || null;
+			if (cursorDom) {
+				cursorDom.style.transform = state.musicRenderType === 'staff' ? `translate(11Px, -${needTransTop}px)` : `translate(6.3Px, -${needTransTop}px)`;
+			}
 			// document.querySelector('.staffline').style.transform = `translateY(-${needTransTop}px)`;
 			// const musicLine =  document.querySelector('.staffline').querySelector('.vf-measure').querySelector('.vf-custom-bg').getBoundingClientRect();
 			// const needTransDistance = svgPage.height / 2 - (musicLine.top - svgPage.top)
@@ -713,6 +718,12 @@ const transSinglePage = () => {
 			const needY = svgPage.height - (staffLine.y+staffLine.height) - 10;
 			// @ts-ignore
 			document.getElementById('osmdSvgPage1').style.transform = `translateY(${needY}px)`;
+			// 一行谱需要同时偏移光标的位置
+			const cursorDom = document.getElementById('cursorImg-0') || null;
+			if (cursorDom) {
+				cursorDom.style.transform = state.musicRenderType === 'staff' ? `translate(6Px, ${needY}px)` : `translate(6.3Px, ${needY}px)`;
+				console.log('一行谱11111')
+			}
 		}
 	}
 }

+ 73 - 71
src/helpers/formateMusic.ts

@@ -14,6 +14,8 @@ import {
 	OpenSheetMusicDisplay,
 } from "/osmd-extended/src";
 import { GradualChange, speedInfo } from "./calcSpeed";
+import { beatUnitTo, speedBeatTo } from "/src/helpers/beatConfig"
+
 const browserInfo = browser();
 dayjs.extend(duration);
 
@@ -32,7 +34,7 @@ export const getFixTime = (speed: number) => {
 	const duration: any = getDuration(state.osmd as unknown as OpenSheetMusicDisplay);
 	let numerator = duration.numerator || 0;
 	let denominator = duration.denominator || 4;
-	const beatUnit = duration.beatUnit || "quarter";
+	const beatUnit = "quarter";
 	// if (state.repeatedBeats) {
 	// 	// 音频制作问题仅2拍不重复
 	// 	numerator = numerator === 2 ? 4 : numerator;
@@ -149,9 +151,9 @@ export const getDuration = (osmd?: OpenSheetMusicDisplay): Duration => {
 		const { Duration, TempoInBPM, ActiveTimeSignature, TempoExpressions } = osmd.GraphicSheet.MeasureList[0][0]?.parentSourceMeasure;
 		if (Duration) {
 			let beatUnit = "quarter";
-			for (const item of TempoExpressions) {
-				beatUnit = item.InstantaneousTempo.beatUnit || "quarter";
-			}
+			// for (const item of TempoExpressions) {
+			// 	beatUnit = item.InstantaneousTempo.beatUnit || "quarter";
+			// }
 			const duration = formatDuration(ActiveTimeSignature, Duration) as unknown as FractionDefault;
 			return {
 				...duration,
@@ -238,11 +240,6 @@ export function formatBeatUnit(beatUnit: string) {
 	return multiple;
 }
 
-/** 根据音符单位,速度,几几拍计算正确的时间 */
-export function getTimeByBeatUnit(beatUnit: string, bpm: number, denominator: number) {
-	return (denominator / formatBeatUnit(beatUnit)) * bpm;
-}
-
 export type CustomInfo = {
 	showSpeed: boolean;
 	parsedXML: string;
@@ -366,7 +363,7 @@ export const onlyVisible = (xml: string, partIndex: number): string => {
 	const detailId = state.examSongId + "";
 	const xmlParse = new DOMParser().parseFromString(xml, "text/xml");
 	const partList = xmlParse.getElementsByTagName("part-list")?.[0]?.getElementsByTagName("score-part") || [];
-	//const partListNames = Array.from(partList).map((item) => item.getElementsByTagName("part-name")?.[0]?.textContent?.trim() || "");
+	const partListNames = Array.from(partList).map((item) => item.getElementsByTagName("part-name")?.[0]?.textContent?.trim() || "");
 	const parts: any = xmlParse.getElementsByTagName("part");
 	// const firstTimeInfo = parts[0]?.getElementsByTagName('metronome')[0]?.parentElement?.parentElement?.cloneNode(true)
 	const firstMeasures = [...parts[0]?.getElementsByTagName("measure")];
@@ -376,10 +373,10 @@ export const onlyVisible = (xml: string, partIndex: number): string => {
 	const rehearsals = [...parts[0]?.getElementsByTagName("rehearsal")];
 
 	/** 第一分谱如果是约定的配置分谱则跳过 */
-	// if (partListNames[0]?.toLocaleUpperCase?.() === "COMMON") {
-	// 	partIndex++;
-	// 	partListNames.shift();
-	// }
+	if (partListNames[0]?.toLocaleUpperCase?.() === "COMMON") {
+		partIndex++;
+		partListNames.shift();
+	}
 	const visiblePartInfo = partList[partIndex];
 	// console.log(visiblePartInfo, partIndex)
 	// 根据后台已选择的分轨筛选出能切换的声轨
@@ -664,8 +661,8 @@ export const formatXML = (xml: string, xmlUrl?: string): string => {
 	for (const minute of minutes) {
 		let measureSpeed = minute.textContent ? Number(minute.textContent) : 0;
 		// 速度带附点,需要转换成不带附点的速度值
-		const hasSpeedDot = Array.from(minute?.parentElement?.children || []).some((item: any) => item?.tagName === 'beat-unit-dot')
-		measureSpeed = hasSpeedDot ? measureSpeed + measureSpeed/2 : measureSpeed;
+		// const hasSpeedDot = Array.from(minute?.parentElement?.children || []).some((item: any) => item?.tagName === 'beat-unit-dot')
+		// measureSpeed = hasSpeedDot ? measureSpeed + measureSpeed/2 : measureSpeed;
 		if (minute.textContent && measureSpeed) {
 			speeds.push(Number(measureSpeed))
 		}
@@ -682,15 +679,29 @@ export const formatXML = (xml: string, xmlUrl?: string): string => {
 		state.originSpeed = speeds[0] ? speeds[0] : 100;
 		state.speed = state.originSpeed;
 	}
+	// 赋值谱面速度节拍器,没有的时候 以后台传入的为准
+	const metronomeXml = xmlParse.getElementsByTagName('metronome')?.[0]
+	const beatUnit = metronomeXml?.getElementsByTagName('beat-unit')?.[0]?.textContent || ''
+	if(beatUnit){
+		const beatUnitDot = metronomeXml?.getElementsByTagName('beat-unit-dot')?.[0]
+		state.speedBeatUnit = beatUnitTo(beatUnit, !!beatUnitDot)
+	}
 	// 如果谱面和小节都没有打速度,osmd设置的小节速度默认取后台设置的速度
 	if (speeds.length === 0) {
 		;(window as any).baseMeasureSpeed = state.originSpeed
 	} else {
-		state.originAudioPlayRate = speeds[0] / state.originSpeed
+		// 当前谱面的速度转为4分音符速度 因为我们速度比例转为4分音符了
+		state.originAudioPlayRate = speedBeatTo({unit:state.speedBeatUnit, speed:speeds[0]}, "1/4") / state.originSpeed
 	}
 	console.log('是否是变速的曲子:',hasVaryingSpeed,speeds)
-
-	const repeats: any = Array.from(xmlParse.querySelectorAll('repeat'));
+	let repeats: any = [];
+	if (state.partIndex === 999) {
+		repeats = Array.from(xmlParse.querySelectorAll('repeat')) || [];
+	} else {
+		const hasCommon = xmlParse.querySelectorAll('part-name')?.[0]?.textContent === 'common';
+		const currentTrackIndex = hasCommon ? state.partIndex + 1 : state.partIndex;
+		repeats = Array.from(xmlParse.querySelectorAll('part')?.[currentTrackIndex]?.querySelectorAll('repeat')) || [];
+	}
 	compatibleXmlPitchVoice(xmlParse);
 	// 获取作词、作曲家
 	getComposer(xmlParse);
@@ -791,7 +802,8 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 	const customNoteCurrentTime = customData.customNoteCurrentTime;
 	const detailId = state.examSongId + "";
 	const partIndex = state.partIndex + "";
-	let fixtime = browserInfo.huawei ? 0.08 : 0; //getFixTime()
+	//let fixtime = browserInfo.huawei ? 0.08 : 0; //getFixTime()
+	let fixtime = 0;
 	const allNotes: any[] = [];
 	const allNoteId: string[] = [];
 	const allMeasures: any[] = [];
@@ -849,6 +861,8 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 
 	let preNoteMeasureNumber = 0; // 上一个小节的number值
 
+	let currentRealTempo: any = {}; // 当前小节的速度与拍号信息
+
 	const _notes = [] as any[];
 	if (state.gradualTimes) {
 		console.log("后台设置的渐慢小节时间", state.gradual, state.gradualTimes);
@@ -963,13 +977,20 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 			}
 			note.maxNoteNum = maxNoteNum;
 			note.trackIndex = minIndex;
+			currentRealTempo = iterator.currentMeasure.tempoExpressions.length ? iterator.currentMeasure.tempoExpressions.find((item: any) => item?.InstantaneousTempo?.isMetronomeMark)?.InstantaneousTempo || currentRealTempo : currentRealTempo;
+			const { beatUnit="quarter", dotted=false, tempoInBpm=state.originSpeed } = currentRealTempo
+			const speedBeatUnit = beatUnitTo(beatUnit, dotted)
 			_notes.push({
 				note,
 				iterator: { ...iterator },
 				currentTime,
 				isDouble,
 				isMutileSubject,
-				measuresTempoInBPM: note?.sourceMeasure?.tempoInBPM
+				// measuresTempoInBPM: note?.sourceMeasure?.tempoInBPM,
+				// 转换成1/4拍的速度
+				measuresTempoInBPM: speedBeatTo({unit: speedBeatUnit || "1/4",speed: tempoInBpm || 0}, `1/4`),
+				speedBeatUnit, // 当前谱面小节的速度对应的是几分音符
+				currentRealTempo
 			});
 		}
 
@@ -987,7 +1008,7 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 	console.log('变速曲子',hasVaryingSpeed, _notes)
 	let noteIds: any = [];
 	// let voicesBBox: any = null;
-	for (let { note, iterator, currentTime, isDouble, isMutileSubject } of _notes) {
+	for (let { note, iterator, currentTime, isDouble, isMutileSubject, speedBeatUnit, measuresTempoInBPM } of _notes) {
 		if (note) {
 			if (preMeasureNumber != note?.sourceMeasure?.MeasureNumberXML) {
 				si = 0
@@ -996,14 +1017,14 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 				preMeasureNumber = note?.sourceMeasure?.MeasureNumberXML
 				allMeasures.push(note.sourceMeasure);
 			}
-			if (si === 0 && state.isSpecialBookCategory) {
-				for (const expression of (note.sourceMeasure as SourceMeasure)?.TempoExpressions) {
-					if (expression?.InstantaneousTempo?.beatUnit) {
-						// 取最后一个有效的tempo
-						beatUnit = expression.InstantaneousTempo.beatUnit;
-					}
-				}
-			}
+			// if (si === 0 && state.isSpecialBookCategory) {
+			// 	for (const expression of (note.sourceMeasure as SourceMeasure)?.TempoExpressions) {
+			// 		if (expression?.InstantaneousTempo?.beatUnit) {
+			// 			// 取最后一个有效的tempo
+			// 			beatUnit = expression.InstantaneousTempo.beatUnit;
+			// 		}
+			// 	}
+			// }
 			// 判断是否是同一小节
 			if (staveIndex == note.sourceMeasure?.MeasureNumberXML && i !== 0) {
 				staveNoteIndex++
@@ -1095,12 +1116,15 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 
 			let beatSpeed = 0;
 			// 速度不能为0 此处的速度应该是按照设置的速度而不是校准后的速度,否则mp3速度不对
-			if (measureSpeed !== baseSpeed && !hasVaryingSpeed) {
-				beatSpeed = baseSpeed || measureSpeed || 100
-			} else {
-				beatSpeed = (state.isSpecialBookCategory ? measureSpeed : baseSpeed) || 1;
-			}
+			// if (measureSpeed !== baseSpeed && !hasVaryingSpeed) {
+			// 	beatSpeed = baseSpeed || measureSpeed || 100
+			// } else {
+			// 	beatSpeed = (state.isSpecialBookCategory ? measureSpeed : baseSpeed) || 1;
+			// }
+			// 计算音符时值,使用转换成1/4的速度计算
+			beatSpeed = measuresTempoInBPM;
 			// let beatSpeed = measureSpeed || baseSpeed
+			beatSpeed = beatSpeed / state.originAudioPlayRate;
 			// 如果有节拍器,需要将节拍器的时间算出来
 			if (i === 0) {
 				if(state.isOpenMetronome){
@@ -1111,9 +1135,9 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 				xmlMp3BeatFixTime = getFixTime(beatSpeed)
 				// console.log("fixtime:", fixtime, '速度:', beatSpeed, "state.isSpecialBookCategory:", state.isSpecialBookCategory, 'state.isOpenMetronome:', state.isOpenMetronome);
 			}
-			// console.log(getTimeByBeatUnit(beatUnit, measureSpeed, iterator.currentMeasure.activeTimeSignature.Denominator))
 			let gradualLength = 0;
-			let speed = (state.isSpecialBookCategory ? measureSpeed : baseSpeed) || 1;
+			// let speed = (state.isSpecialBookCategory ? measureSpeed : baseSpeed) || 1;
+			let speed = measureSpeed ? measureSpeed : baseSpeed;
 			gradualChange = iterator.currentMeasure.speedInfo || gradualChange;
 			gradualSpeed = osmd.Sheet.SoundTempos?.get(note.sourceMeasure.measureListIndex) || gradualSpeed;
 			if (!gradualSpeed || gradualSpeed.length < 2) {
@@ -1151,34 +1175,6 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 						}
 					}
 				}
-			} else if (state.appName === "GYM" && gradualChange && gradualSpeed && (gradualChange.startXmlNoteIndex === si || gradualChangeIndex > 0)) {
-				const startSpeed = gradualSpeed[0] - (gradualSpeed[1] - gradualSpeed[0]);
-				const { resetXmlNoteIndex, endXmlNoteIndex } = gradualChange;
-				const noteDiff = endXmlNoteIndex;
-				let stepSpeed = (gradualSpeed[gradualSpeed.length - 1] - startSpeed) / noteDiff;
-				stepSpeed = note.DotsXml ? stepSpeed / 1.5 : stepSpeed;
-				if (gradualChangeIndex < noteDiff) {
-					const tempSpeed = Math.ceil(speed + stepSpeed * gradualChangeIndex);
-					let tmpSpeed = getTimeByBeatUnit(beatUnit, tempSpeed, iterator.currentMeasure.activeTimeSignature.Denominator);
-					const maxLength = (wholeValue + numerator / denominator) * vDenominator * (60 / tmpSpeed);
-					// speed += stepSpeeds.reduce((a, b) => a + b, 0)
-					speed += Math.ceil(stepSpeed * (gradualChangeIndex + 1));
-					tmpSpeed = getTimeByBeatUnit(beatUnit, speed, iterator.currentMeasure.activeTimeSignature.Denominator);
-					const minLength = (wholeValue + numerator / denominator) * vDenominator * (60 / tmpSpeed);
-					gradualLength = (maxLength + minLength) / 2;
-				} else if (resetXmlNoteIndex > gradualChangeIndex) {
-					speed = allNotes[i - 1]?.speed;
-				}
-				beatSpeed =
-					(state.isSpecialBookCategory ? getTimeByBeatUnit(beatUnit, speed, iterator.currentMeasure.activeTimeSignature.Denominator) : baseSpeed) || 1;
-				const isEnd = !(gradualChangeIndex < noteDiff) && !(resetXmlNoteIndex > gradualChangeIndex);
-				gradualChangeIndex++;
-				if (isEnd) {
-					gradualChangeIndex = 0;
-					gradualChange = undefined;
-					gradualSpeed = undefined;
-					stepSpeeds = [];
-				}
 			}
 			const _noteLength = NoteRealValue;
 			// 当前音符的持续时长,当前音符的RealValue值*拍数*(60/后台设置的基准速度)
@@ -1225,9 +1221,11 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 				const staffEntries = note.sourceMeasure.verticalMeasureList?.[0]?.staffEntries || [];
 				//计算第一个小节里面的音符时值是否等于整个小节的时值
 				staffEntries.forEach((_a: any) => {
-					if (_a?.sourceStaffEntry?.voiceEntries?.[0]?.notes?.[0]?.length?.realValue) {
-						_firstMeasureRealValue += _a.sourceStaffEntry.voiceEntries[0].notes[0].length.realValue;
-					}
+					// 需要过滤掉倚音音符
+					const matchNote = _a?.sourceStaffEntry?.voiceEntries?.length > 1 ? _a?.sourceStaffEntry?.voiceEntries.find((item: any) => !item.isGrace) : _a?.sourceStaffEntry?.voiceEntries?.[0]
+					if (matchNote?.notes?.[0]?.length?.realValue) {
+						_firstMeasureRealValue += matchNote.notes[0].length.realValue;
+					}					
 				});
 				if (_firstMeasureRealValue < vRealValue) {
 					// console.log(_firstMeasureRealValue, vRealValue)
@@ -1292,7 +1290,8 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 				// 找出这个音符前面音符的结束时间
 				let preNoteTImes = allNotes[allNotes.length - 1]?.endtime*1000
 				if(!preNoteTImes){
-					preNoteTImes = Math.max(fixtime - noteLength, 0)*1000 //如果前一个音符没有结束时间,证明这个音符是第一个音符没有打时间,所以往前奏里面找补
+					//如果前一个音符没有结束时间,证明这个音符是第一个音符没有打时间,当有timegap以fixtime当开始时间(1795013294269087745),当第一个小节有times这个往前奏里面找补(1795013306436763649)
+					preNoteTImes = (state.evXmlBeginArr.length>0 ? fixtime : Math.max(fixtime - noteLength, 0))*1000
 				}
 				// 找出这个音符后面音符的开始时间
 				let nextI = i
@@ -1405,7 +1404,8 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 				firstVerticalMeasure: activeVerticalMeasureList[0],
 				noteLength: 1,
 				//osdmContext: osmd,
-				speedbeatUnit: beatUnit,
+				// speedbeatUnit: beatUnit,
+				speedBeatUnit, // 当前谱面小节的速度对应的是几分音符
 				multipleRestMeasures: multipleRestMeasures, // 当前合并小节的索引,从1开始到当前的totalMultipleRestMeasures结束,
 				totalMultipleRestMeasures, // 当前小节总的合并小节数
 				measureSpeed,  // 小节速度
@@ -1759,7 +1759,9 @@ export const compatibleXmlPitchVoice = (xmlParse: any) => {
 				xmlNeedAdjustVoice = !instrumentName || instrumentName.includes('solo') ? true : false
 				break;
 		}
-		(window as any).xmlNeedAdjustVoice = xmlNeedAdjustVoice
+		// (window as any).xmlNeedAdjustVoice = xmlNeedAdjustVoice
+		// 管乐迷的曲子不需要上述判断,修改为都需要程序处理(保持和之前逻辑一致)
+		(window as any).xmlNeedAdjustVoice = true
 	}
 }
 

+ 126 - 122
src/helpers/metronome.ts

@@ -42,6 +42,7 @@ export const metronomeData = reactive({
 	cursorTips: '' as string, // 光标模式提示文字
 	followAudioIndex: 1, // 当前的拍数
 	totalNumerator: 2, // 总拍数
+	firstBeatTypeArr:[] as number[] // 第一小节的节拍
 });
 
 watch(
@@ -182,7 +183,7 @@ class Metronome {
 	
 	// 暂停的时候,点击音符,需要找到对应的节拍器的位置
 	findMetronomePosition = (currentTime: number) => {
-		console.log('取消选段',currentTime)
+		// console.log('取消选段',currentTime)
 		const originTime = currentTime;
 		// if (!state.sectionStatus){
 		// 	currentTime = setCurrentTime(currentTime);
@@ -217,6 +218,8 @@ class Metronome {
 
 	// 播放
 	playAudio = () => {
+		// 关闭定时器节拍器
+		return
 		/* 如果是 评测模式且不为MIDI并且节拍器资源加载成功的时候  不运行节拍器播放*/
 		if (state.modeType === "practise" && state.playMode !== "MIDI") {
 			if(state.playType === "play" && state.playSource === "music" && audioDataState.songCollection.beatSongEle){
@@ -321,6 +324,11 @@ class Metronome {
 			// console.log("🚀 ~ measureNumberXML", measureNumberXML, note)
 			// console.log("🚀 ~ measureNumberXML", note)
 			const measureListIndex = measureNumberXML - 1;
+			// 当渐快渐慢的时候  不播节拍器
+			if(isWithinRange(state.gradual, measureListIndex)){
+				xmlNumber = measureNumberXML;
+				continue
+			}
 			if (measureNumberXML > -1) {
 				if (measureNumberXML != xmlNumber) {
 					// 弱起的时候 根据音符结尾时间减去音符开头时间,得到的不是正常小节的时间,然后平均分配节拍之后,当前节拍间隔会非常短 这里弱起取整个小节的时间
@@ -365,7 +373,9 @@ class Metronome {
 					const m = {
 						measureNumberXML: measureNumberXML,
 						measureNumberIndex: measureListIndex,
+						CompoundTempo: note?.noteElement?.sourceMeasure?.CompoundTempo || "",
 						numerator: note?.noteElement?.sourceMeasure?.ActiveTimeSignature?.numerator || 0,
+						denominator: note?.noteElement?.sourceMeasure?.ActiveTimeSignature?.denominator || 0,
 						start: startTime,
 						end: noteEndTime,
 						time: noteEndTime - startTime,
@@ -375,48 +385,15 @@ class Metronome {
 						svgs: [] as any[],
 						isRestFlag: note.isRestFlag,
 					};
-					// 2.统计小节的拍数
-					// 3.统计小节的时长, 开始时间,结束时间
-					// console.log(measureNumberXML,note.measures, times.filter((n: any) => n?.noteElement?.sourceMeasure?.measureListIndex == measureListIndex))
-					if ([121].includes(state.subjectId)) {
-						const _measures = times.filter((n: any) => n?.noteElement?.sourceMeasure?.measureListIndex == measureListIndex);
-						note.measures = _measures;
-						m.start = note.measures[0].time;
-						m.end = note.measures[note.measures.length - 1].endtime;
-						m.time = note.measures[note.measures.length - 1].endtime - note.measures[0].time;
-						try {
-							const tickables = note.noteElement.sourceMeasure.verticalMeasureList.reduce((arr: any[], value: any) => {
-								arr.push(...value.vfVoices["1"].tickables);
-								return arr;
-							}, []);
-							const xList: any[] = [];
-							m.svgs = tickables
-								.map((n: any) => {
-									const x = n.getBoundingBox().x;
-									if (!xList.includes(x) && n.duration !== "w") {
-										xList.push(x);
-										n._start_x = x;
-										return n;
-									}
-								})
-								.filter(Boolean)
-								.sort((a: any, b: any) => a._start_x - b._start_x);
-							// console.log(measureNumberXML, m.svgs)
-						} catch (error) {
-							console.log(error);
-						}
-						m.stepList = calculateMutilpleMetroStep(note.measures, m);
-					} else {
-						/**
-						 * bug:#9877
-						 * 多分轨合并显示,不同分轨的音符数量可能不同
-						 */
-						let measureArr = note.measures;
-						if (state.isCombineRender) {
-							measureArr = measureArr.filter((item: any) => item.MeasureNumberXML === m.measureNumberXML)
-						}
-						m.stepList = calculateMetroStep(measureArr, m);
+					/**
+					 * bug:#9877
+					 * 多分轨合并显示,不同分轨的音符数量可能不同
+					*/
+					let measureArr = note.measures;
+					if (state.isCombineRender) {
+						measureArr = measureArr.filter((item: any) => item.MeasureNumberXML === m.measureNumberXML)
 					}
+					m.stepList = calculateMetroStep(measureArr, m);
 					measures.push(m);
 					xmlNumber = measureNumberXML;
 				}
@@ -433,34 +410,60 @@ class Metronome {
 				measureNumberXML: item.measureNumberXML
 			}
 		}))
-		// 4.按照拍数将时长平均分配
 		try {
 			for (let i = 0; i < measures.length; i++) {
 				const measure = measures[i];
-				const noteStep = measure.time / measure.numerator;
-				// console.log("🚀 ~ measure.measureNumberXML",measure.measureNumberXML, noteStep)
-				const WIDTH = [121].includes(state.subjectId) ? 95 : 100;
-				const widthStep = WIDTH / (measure.numerator + 1);
+				// 87拍和45拍要根据小节返回的CompoundTempo特殊处理
+				const beatTypeArr = getBeatTypeArr(measure.numerator, measure.denominator, measure.CompoundTempo)
+				const CompoundTempoArr = beatTypeArr.map((beatType:number) => {
+					return Math.abs(beatType*measure.numerator)
+				})
+				if(i===0){
+					metronomeData.firstBeatTypeArr = beatTypeArr
+				}
 				metroMeasure[i] = [] as number[];
-				// console.log('stepList', [...measure.stepList], measure.measureNumberXML)
-				for (let j = 0; j < measure.numerator; j++) {
-					const time = noteStep * j + measure.start;
+				// 根据有几个拍子,划分成几份
+				const widthStep = 100 / (beatTypeArr.length+1);
+				// 当前拍子的组合数(2+3+2,3+2)中的数字
+				let beatNum = 0;
+				// if (measure.measureNumberXML == 98) {
+				// 	debugger
+				// }
+				for (let j = 0; j < beatTypeArr.length; j++) {
+					// 累加
+					const beatMuit = Array(j).fill("").reduce((num:number,v:any,i:number) => {
+						return num += Math.abs(beatTypeArr[i])
+					}, 0) || 0
+					const time = measure.time * beatMuit + measure.start;
 					metroList.push(time);
 					let left = "";
-					if (measure.stepList[j]) {
-						left = measure.stepList[j] + "px";
+					// 当前拍子数对应的节拍位置索引
+					let currentIdx = 0;
+					if (j == 0) {
+						currentIdx = 0
+					} else {
+						beatNum += CompoundTempoArr[j-1];
+						currentIdx = beatNum
+					}
+					// 如果是87拍,并且是3+2+2的组合,第二拍的节拍指针需要定位到第四个音符的位置
+					// if (measure.numerator === 7 && measure.denominator === 8 && measure.CompoundTempo === '3+2+2' && j === 1) {
+					// 	currentIdx += 1;
+					// }
+					if (measure.stepList[currentIdx]) {
+						left = measure.stepList[currentIdx] + "px";
 					} else {
 						const preLeft = measure.stepList[j - 1];
-						left = !preLeft ? `${widthStep}%` : preLeft.toString().indexOf("%") > -1 ? `${preLeft} + ${widthStep}%` : `${preLeft}px + ${widthStep}%`;
+						left = !preLeft || preLeft.toString().indexOf("%") > -1 ? `${widthStep*(j+1)}%` : `${preLeft}px + ${widthStep}%`;
 						measure.stepList[j] = left;
-					}
+					}					
 					metroMeasure[i].push({
+						isTick: beatTypeArr[j] < 0,
 						index: j,
 						time,
-						// left: (measure.stepList[j] ? measure.stepList[j] + 'px' : (j + 1) * widthStep + '%'),
 						left: left?.indexOf("%") > -1 ? `calc(${left})` : left,
 						measureNumberXML: measure.measureNumberXML,
 						isRestFlag: measure.isRestFlag,
+						stepList: measure.stepList
 					});
 				}
 			}
@@ -476,6 +479,64 @@ class Metronome {
 	}
 }
 
+/** 获取节拍类型数组 */
+export function getBeatTypeArr(numerator?:number, denominator?:number, CompoundTempo?:string){
+	const speedBeatUnit = state.speedBeatUnit
+	const Numerator = numerator || state.osmd?.Sheet?.SheetPlaybackSetting?.Rhythm?.Numerator || 4
+	const Denominator = denominator || state.osmd?.Sheet?.SheetPlaybackSetting?.Rhythm?.Denominator || 4
+	let loopArr = []
+	// 规则 负数代表重声,正数代表轻声
+	switch (`${Numerator}/${Denominator}`) {
+		case "2/2":
+			loopArr = [-1/2, 1/2]
+			break;		
+		case "3/2":
+			loopArr = [-1/3, 1/3, 1/3]
+			break;
+		case "5/4":
+			//5/4拍根据谱面的CompoundTempo来特殊处理
+			if(CompoundTempo==="2+3"){
+				loopArr = [-1/5, 1/5, -1/5, 1/5, 1/5]
+			}else{
+				loopArr = [-1/5, 1/5, 1/5, -1/5, 1/5]
+			}
+			break;
+		case "3/8":
+			// 3/8拍 速度为浮点4分音符时候特殊处理
+			if(speedBeatUnit==="1/4."){
+				loopArr = [-1/1]
+			}else{
+				loopArr = [-1/3, 1/3, 1/3]
+			}
+			break;
+		case "6/8":
+			loopArr = [-1/2, 1/2]
+			break;	
+		case "7/8":
+			//7/8拍根据谱面的CompoundTempo来特殊处理
+			if(CompoundTempo==="2+2+3"){
+				loopArr = [-2/7, 2/7, 3/7]
+			}else if(CompoundTempo==="2+3+2"){
+				loopArr = [-2/7, 3/7, 2/7]
+			}else{
+				loopArr = [-3/7, 2/7, 2/7]
+			}
+			break;	
+		case "9/8":
+			loopArr = [-3/9, 3/9, 3/9]
+				break;				
+		default:
+			loopArr.push(-1/Numerator);
+			for (let i = 1; i < Numerator; i++) {
+				loopArr.push(1/Numerator);
+			}
+			break;
+	}
+	// console.log(loopArr, "loopArr")
+	return loopArr
+}
+
+
 // 计算拍子的时值
 function calculateMetroStep(arr: any[], m: any): number[] {
 	const measureLength = arr.reduce((total: number, item: any) => {
@@ -602,72 +663,6 @@ function calculateMetroStep(arr: any[], m: any): number[] {
 	// console.log("stepList", [...stepList], m.measureNumberXML);
 	return stepList;
 }
-// 计算单声部多声轨的拍子的时值
-function calculateMutilpleMetroStep(arr: any[], m: any): number[] {
-	// console.log("🚀 ~ m:", [...m.svgs])
-	const step = m.time / m.numerator;
-	const measure_bbox = arr[0]?.svgElement?.attrs?.el?.parentElement?.parentElement?.getBoundingClientRect?.() || { x: 0 };
-	if (arr.length === 1) {
-		const staveNote = m.svgs[0];
-		// 大于一拍
-		let bbox = staveNote?.attrs?.el?.getBoundingClientRect?.() || { x: 0 };
-		if (staveNote && !staveNote.isRest()) {
-			return [bbox.x - measure_bbox.x];
-		}
-		return [];
-	}
-	// console.log("🚀 ~ arr", arr, step, m.measureNumberXML);
-	let total = 0;
-	let notes: any[] = [];
-	let stepList: number[] = [];
-	for (let i = 0; i < arr.length; i++) {
-		const item = arr[i];
-		item._index = i;
-		const noteTime = item.endtime - item.time;
-		total += noteTime;
-		let svgEle = m.svgs[i]?.attrs?.el;
-		// 大于一拍
-		let bbox = svgEle?.getBoundingClientRect?.() || { x: 0 };
-		// console.log(m.measureNumberXML, svgEle, i)
-		if (noteTime > step) {
-			total -= step;
-			// console.log('超过一拍了', notes, m.measureNumberXML)
-			let x = bbox.x - measure_bbox.x;
-			if (notes.length > 0) {
-				svgEle = m.svgs[notes[0]._index]?.attrs?.el;
-				bbox = svgEle?.getBoundingClientRect?.() || { x: 0 };
-				x = bbox.x - measure_bbox.x;
-			}
-			stepList.push(x);
-			notes = [];
-		} else {
-			notes.push(item);
-		}
-		// console.log(notes)
-		if (Math.abs(total - step) < 0.001) {
-			let x = bbox.x - measure_bbox.x;
-			if (notes.length > 0) {
-				svgEle = m.svgs[notes[0]._index]?.attrs?.el;
-				bbox = svgEle?.getBoundingClientRect?.() || { x: 0 };
-				x = bbox.x - measure_bbox.x;
-			}
-			// console.log("一拍",svgEle,notes,m.svgs, m.measureNumberXML);
-			stepList.push(x);
-			total = 0;
-			notes = [];
-		}
-	}
-	stepList = stepList.reduce((list: any[], n: number) => {
-		if (list.includes(n)) {
-			list.push(undefined as any);
-		} else {
-			list.push(n);
-		}
-		return list;
-	}, []); //Array.from(new Set(stepList))
-	// console.log('stepList', stepList, m.measureNumberXML)
-	return stepList;
-}
 
 // 延迟兼容处理
 function setCurrentTime(time: number) {
@@ -698,5 +693,14 @@ function hideCursorTip() {
 		}, 2000);
 	}
 }
-
+function isWithinRange(ranges:any[], index:number) {
+	for (const range of ranges) {
+		const start = range[0].measureIndex;
+		const end = range[1].measureIndex;
+		if (index >= start && index < end) {
+			return true;
+		}
+	}
+	return false;
+}
 export default Metronome;

+ 29 - 0
src/helpers/svgToPng.ts

@@ -0,0 +1,29 @@
+// 将svg转成png
+export const getSvgPngToSize = (osmd: any) => {
+    if (osmd) {
+      if (osmd.Drawer.Backends.length > 0) {
+        var imgList = []
+        
+        for (var idx = 0, len = osmd.Drawer.Backends.length; idx < len; idx++) {
+          var backend = osmd.Drawer.Backends[idx]
+          var state = backend.ctx.state;
+          var width = backend.ctx.width / state.scale.x;
+          var height = backend.ctx.height / state.scale.y;
+          const textX = width - 120,textY = height - 50;
+          const textDom = `<g><text x="${textX}" y="${textY}" stroke-width="3" fill="#000000" stroke="none" stroke-dasharray="none" font-family="Times New Roman" font-size="36px" font-weight="bold" font-style="none">第${idx+1}页</text></g>`
+          backend.ctx.svg.innerHTML = backend.ctx.svg.innerHTML + textDom;
+          var cont = new XMLSerializer().serializeToString(
+            backend.ctx.svg
+          )
+          imgList.push({
+            img: cont,
+            width: width,
+            height: height,
+          })
+        }
+        return imgList
+      }
+    } else {
+      console.log('没有OSMD')
+    }
+}

+ 5 - 5
src/page-instrument/api.ts

@@ -15,7 +15,6 @@ export const studentQueryUserInfo = async () => {
         phone:data.phone,
         clientType:"TEACHER",
         id:data.id,
-        vipMember: true, // 管乐迷 会员现在在外面判断的 所以这里默认不开启会员验证
         gender:""
       }
       return res
@@ -32,10 +31,10 @@ export const studentQueryUserInfo = async () => {
       const data = res.data
       res.data = {
         instrumentId: "",
+        specialInstrumentIds: [],
         phone:data.phone,
         clientType:"web",
         id:data.id,
-        vipMember: true, // 管乐迷 会员现在在外面判断的 所以这里默认不开启会员验证
         gender:""
       }
       return res
@@ -44,12 +43,13 @@ export const studentQueryUserInfo = async () => {
       const res = await request.get(`/student/queryUserInfo`);
       const data = res.data.student
       res.data = {
-        instrumentId: res.data.instrumentId,
+        instrumentId: res.data.instrumentId ? res.data.instrumentId.split(',')[0] : "",
+        specialInstrumentIds: res.data.instrumentId ? res.data.instrumentId.split(',') : [],
         phone:data.phone,
         clientType:"STUDENT",
         id:data.id,
-        vipMember: true, // 管乐迷 会员现在在外面判断的 所以这里默认不开启会员验证
-        gender:""
+        gender:"",
+        membershipEndTime: data.membershipEndTime
       }
       return res
     }

BIN
src/page-instrument/component/the-music-list/imgs/icon-music-vip.png


BIN
src/page-instrument/component/the-music-list/imgs/searImg.png


+ 4 - 4
src/page-instrument/component/the-music-list/index.module.less

@@ -65,8 +65,8 @@
         }
         >img{
             flex-shrink: 0;
-            width: 16px;
-            height: 16px;
+            width: 14px;
+            height: 14px;
         }
         :global{
             .van-field{
@@ -165,10 +165,10 @@
         flex-grow: 1;
         overflow: hidden;
         .name{
+            line-height: 20px;
             font-weight: 600;
             font-size: 16px;
             color: #333333;
-            line-height: 1;
             white-space: nowrap;
             overflow: hidden;
             text-overflow: ellipsis;
@@ -176,7 +176,7 @@
         .detail{
             display: flex;
             align-items: center;
-            margin-top: 8px;
+            margin-top: 6px;
             height: 14px;
             .usedNum{
                 display: flex;

+ 2 - 3
src/page-instrument/component/the-music-list/index.tsx

@@ -6,10 +6,9 @@ import { followData } from "/src/view/follow-practice";
 import state, {IPlatform} from "/src/state";
 import { evaluatingData } from "/src/view/evaluating";
 import { getQuery } from "/src/utils/queryString";
-
 const query: any = getQuery();
 export const isMusicList = computed(()=>{
-	return !(query.workRecord || query.modelType || state.platform === IPlatform.PC || query.isCbs)
+	return !(query.isHideMusicList || state.isHomeWork || query.modelType || state.platform === IPlatform.PC || query.isCbs)
 })
 export const musicListShow = ref(false)
 export default defineComponent({
@@ -17,7 +16,7 @@ export default defineComponent({
 	setup() {
 		return () => (
 			<>
-				<Popup class={styles.popup} position="left" v-model:show={musicListShow.value} round overlay-style={{background:'rgba(0, 0, 0, 0.3)'}}>
+				<Popup class={styles.popup} position="left" v-model:show={musicListShow.value} round overlay-style={{background:'rgba(0, 0, 0, 0.7)'}}>
 					<div class={[styles.tabs]}>
 						<Tabs>
 							<Tab title="其他曲谱">

+ 19 - 5
src/page-instrument/component/the-music-list/list.tsx

@@ -9,6 +9,7 @@ import searImg from "./imgs/searImg.png"
 import huoimg from "./imgs/huo.png"
 import emptyImg from "./imgs/empty.png"
 import { getQuery } from "/src/utils/queryString";
+import { vipData, isVip } from "../vip"
 
 export default defineComponent({
   name: "TheMusicList-list",
@@ -24,7 +25,7 @@ export default defineComponent({
       name: "",
       page: 1,
       rows: 20,
-      musicalInstrumentId: state.instrumentId,
+      musicalInstrumentId: state.specialPercussionFlag ? state.musicalInstrumentIds.split(",")[0] : (state.isConcert ? "" : state.instrumentId),
       musicSheetCategoriesId: state.bizMusicCategoryId,
       recentFlag: props.recentFlag ? true : null,
       excludeMusicId: props.recentFlag ? null : state.examSongId,
@@ -74,6 +75,16 @@ export default defineComponent({
     });
 
     const openAccomapina = (item: any) => {
+      // 学生端 没有开会员查看会员曲目
+      if(item.paymentType === "VIP" && state.systemType === "student" && !isVip.value){
+        vipData.show = true
+        return
+      }
+      // 学校查看会员曲目
+      if(item.paymentType === "VIP" && state.systemType === "web" && state.isSchool){
+        vipData.show = true
+        return
+      }
       if (item.id === state.examSongId) return;
       // 暂停播放
       togglePlay("paused");
@@ -125,10 +136,13 @@ export default defineComponent({
                 </div>
                 <div class={styles.content}>
                   <p class={styles.name}>{item.musicSheetName}</p>
-                  <div class={styles.detail}>
-                    {/* {item.usedNum && <div class={styles.usedNum}><img src={huoimg}/><div>{formatNumber(item.usedNum)}</div></div>} */}
-                    {item.composer && <p class={styles.author}>{item.composer}</p>}
-                  </div>
+                  {
+                    item.composer &&                   
+                    <div class={styles.detail}>
+                      {/* {item.usedNum && <div class={styles.usedNum}><img src={huoimg}/><div>{formatNumber(item.usedNum)}</div></div>} */}
+                      <p class={styles.author}>{item.composer}</p>
+                    </div>
+                  }
                 </div>
               </div>
             );

+ 33 - 0
src/page-instrument/component/vip/index.module.less

@@ -0,0 +1,33 @@
+.vip{
+  padding: 20px 30px;
+  padding-top: 30px;
+  min-width: 230px;
+  >img{
+    width: 161px;
+    margin: 0 auto 20px;
+    display: block;
+  }
+  >p{
+    margin: 0;
+    font-size: 14px;
+    color: #808080;
+    margin: 0 auto 20px;
+    text-align: center;
+  }
+  .btn{
+    font-size: 16px;
+    height: 40px;
+    line-height: 40px;
+    width: 100%;
+  }
+  &+i{
+    right: 10px;
+    top: 10px;
+  }
+}
+.vipPopup{
+  pointer-events: initial !important;
+  & *{
+    pointer-events: initial !important;
+  }
+}

+ 110 - 0
src/page-instrument/component/vip/index.tsx

@@ -0,0 +1,110 @@
+import { defineComponent, reactive, computed, onMounted, watch } from "vue"
+import { Button, Popup } from "vant"
+import state from "/src/state"
+import TipsIcon from "./tips.png"
+import styles from "./index.module.less"
+import dayjs from "dayjs"
+import { storeData } from "/src/store"
+import { postMessage } from "/src/utils/native-message"
+import { usePageVisibility } from "@vant/use"
+import { studentQueryUserInfo } from "/src/page-instrument/api"
+import { api_back } from "/src/helpers/communication"
+
+export const vipData = reactive({
+   show: false
+})
+
+export const isVip = computed(() => {
+   return dayjs().isBefore(dayjs(storeData.user?.membershipEndTime))
+})
+
+export default defineComponent({
+   name: "vip-popup",
+   setup() {
+      const getContent = computed(() => {
+         if (state.isHomeWork) {
+            return "您还不是团练宝会员,请开通服务后使用该功能"
+         } else if (state.isSchool) {
+            return "VIP曲目暂不可用"
+         } else {
+            return "您尚未开通云练习服务,请联系乐团老师开通"
+         }
+      })
+      onMounted(() => {
+         if (state.isHomeWork && !isVip.value && state.paymentType === "VIP") {
+            vipData.show = true
+         }
+      })
+      function vaildMusicScoreUrl() {
+         const url = window.location.hostname
+         let returnUrl = ""
+         if (/dev/.test(url) || /192.168/.test(url)) {
+            returnUrl = "https://test.gym.lexiaoya.cn"
+         } else if (/test/.test(url)) {
+            // test 环境
+            returnUrl = "https://test.gym.lexiaoya.cn"
+         } else {
+            returnUrl = "https://gym.lexiaoya.cn"
+         }
+         return returnUrl
+      }
+      function hanldeOpen() {
+         if (state.isHomeWork) {
+            postMessage({
+               api: "openWebView",
+               content: {
+                  url: vaildMusicScoreUrl() + `/mdaya/#/member?id=${state.examSongId}`,
+                  orientation: 1
+               }
+            })
+         } else {
+            vipData.show = false
+         }
+      }
+      function handleClose() {
+         if (state.isHomeWork) {
+            api_back()
+         } else {
+            vipData.show = false
+         }
+      }
+      const pageVisibility = usePageVisibility()
+      watch(pageVisibility, value => {
+         if (state.isHomeWork && value === "visible") {
+            if (!isVip.value) {
+               studentQueryUserInfo().then(res => {
+                  if (res.code === 200) {
+                     storeData.user.membershipEndTime = res?.data?.membershipEndTime
+                     if (isVip.value) {
+                        vipData.show = false
+                     }
+                  }
+               })
+            }
+         }
+      })
+      return () => (
+         <>
+            <Popup
+               class={styles.vipPopup}
+               zIndex={2222222222}
+               show={vipData.show}
+               /* 引导页层级和引导页禁止了pointerEvents */
+               overlay-style={{ zIndex: 1111111111, pointerEvents: "initial" }}
+               teleport="body"
+               closeable
+               onClickCloseIcon={handleClose}
+               round
+            >
+               <div class={styles.vip}>
+                  <img src={TipsIcon} />
+                  <p>{getContent.value}</p>
+                  <Button class={styles.btn} round color="#01C1B5" onClick={hanldeOpen}>
+                     {state.isHomeWork ? "开通" : " 确定"}
+                  </Button>
+               </div>
+            </Popup>
+         </>
+      )
+   }
+})

BIN
src/page-instrument/component/vip/tips.png


+ 13 - 9
src/page-instrument/custom-plugins/ExerciseStatistics/index.module.less

@@ -1,7 +1,7 @@
 .exerciseStatistics {
     position: fixed;
-    left: 12px;
-    bottom: 26px;
+    left: 17px;
+    bottom: 28px;
     box-sizing: border-box;
     z-index: 110;
     div {
@@ -21,8 +21,8 @@
     .icon {
         position: relative;
         display: block;
-        width: 30px;
-        height: 30px;
+        width: 37px;
+        height: 37px;
         transition: all var(--animation-time);
         // box-shadow: 0px 2px 4px 0px rgba(2,91,86,0.63);
         filter: drop-shadow(0px 2px 4px rgba(2, 91, 86, 0.4));
@@ -31,14 +31,14 @@
     .btnTietle {
         position: absolute;
         left: -20%;
-        bottom: -26%;
+        bottom: -22%;
         background: linear-gradient(180deg, #FF9941 0%, #FFC174 100%);
         border-radius: 6px;
         box-shadow: 0px 2px 4px 0px rgba(2, 91, 86, 0.4);
-        font-size: 9px;
+        font-size: 11px;
         white-space: nowrap;
         padding: 0 4px;
-        line-height: 12px;
+        line-height: 16px;
         transition: all var(--animation-time);
         transform-origin: center center;
     }
@@ -53,8 +53,8 @@
         padding: 3px;
         background: rgba(0, 73, 68, .4);
         .icon {
-            width: 22px;
-            height: 22px;
+            width: 26px;
+            height: 26px;
             filter:none;
         }
         .btnTietle{
@@ -68,3 +68,7 @@
         }
     }
 }
+
+.hidden {
+    display: none;
+}

+ 12 - 1
src/page-instrument/custom-plugins/ExerciseStatistics/index.tsx

@@ -4,6 +4,8 @@ import iconTime from "./icon-time.png";
 import request from "/src/utils/request";
 import { getSecondRPM } from "/src/utils";
 import state from '/src/state'
+import { headTopData } from "/src/page-instrument/header-top/index";
+import { followData } from "/src/view/follow-practice/index"
 
 // 练习统计
 export default defineComponent({
@@ -41,11 +43,20 @@ export default defineComponent({
                 handleStop()
             }
         })
+		// 监听跟练播放
+		watch(() => state.hasFollowResult, () => {
+			console.log('跟练录音11111',state.hasFollowResult,followData.start)
+            if (followData.practiceStart && state.hasFollowResult){
+                handleStart()
+            } else if (!followData.practiceStart) {
+                handleStop()
+            }
+        })		
 		onMounted(() => {
 			getTime();
 		});
 		return () => (
-			<div class={styles.exerciseStatistics} onClick={() => (data.isHidden = !data.isHidden)}>
+			<div class={[styles.exerciseStatistics, headTopData.modeType !== 'show' && styles.hidden]} onClick={() => (data.isHidden = !data.isHidden)}>
 				<div class={[styles.btnTimeWrap, data.isHidden ? "" : styles.hide]}>
 					<img class={styles.icon} src={iconTime} />
 					<div class={styles.btnTietle}>练习时长</div>

+ 31 - 9
src/page-instrument/custom-plugins/guide-driver/index.less

@@ -150,7 +150,7 @@
 
 .popoverClass5-1 {
   width: 257px;
-  height: 165px;
+  height: 145px;
   background: url("./images/practise/d5-1.png") no-repeat center;
   background-size: contain;
 
@@ -265,6 +265,25 @@
   }
 }
 
+.popoverClass6-end {
+  width: 257px;
+  height: 165px;
+  background: url("./images/practise/d6.png") no-repeat center;
+  background-size: contain;
+  &.popoverClose {
+    .driver-popover-navigation-btns {
+      position: absolute;
+      right: 15px;
+      bottom: -35px;
+      justify-content: end;
+    }
+
+    .driver-popover-prev-btn {
+      margin-left: 14px;
+    }
+  }
+}
+
 .popoverClass8 {
   width: 270px;
   height: 145px;
@@ -274,6 +293,7 @@
     .driver-popover-navigation-btns {
       position: absolute;
       right: 15px;
+      bottom: -35px;
       justify-content: end;
     }
 
@@ -378,6 +398,7 @@
     .driver-popover-navigation-btns {
       position: absolute;
       right: 15px;
+      bottom: -35px;
       justify-content: end;
     }
 
@@ -455,8 +476,8 @@
 }
 
 .popoverClassER2 {
-  width: 261px;
-  height: 226px;
+  width: 260px;
+  height: 160px;
   background: url("./images/evaluating/r2.png") no-repeat center;
   background-size: contain;
 
@@ -468,7 +489,7 @@
 
 .popoverClassER3 {
   width: 261px;
-  height: 249px;
+  height: 181px;
   background: url("./images/evaluating/r3.png") no-repeat center;
   background-size: contain;
 
@@ -480,7 +501,8 @@
 
 .popoverClassER4 {
   width: 327px;
-  height: 246px;
+  min-width: 327px;
+  height: 181px;
   background: url("./images/evaluating/r4.png") no-repeat center;
   background-size: contain;
 
@@ -506,7 +528,7 @@
 }
 
 .popoverClassReport1 {
-  transform: translateY(10px);
+  //transform: translateY(10px);
   width: 270px;
   height: 145px;
   background: url("./images/report/r1.png") no-repeat center;
@@ -519,7 +541,7 @@
 }
 
 .popoverClassReport2 {
-  transform: translateY(10px);
+  //transform: translateY(10px);
   width: 270px;
   height: 145px;
   background: url("./images/report/r2.png") no-repeat center;
@@ -553,7 +575,7 @@
 }
 
 .popoverClassReport3 {
-  transform: translateY(10px);
+  //transform: translateY(10px);
   width: 270px;
   height: 145px;
   background: url("./images/report/r3.png") no-repeat center;
@@ -587,7 +609,7 @@
 }
 
 .popoverClassReport4 {
-  transform: translateY(10px);
+  //transform: translateY(10px);
   width: 270px;
   height: 145px;
   background: url("./images/report/r5.png") no-repeat center;

+ 76 - 36
src/page-instrument/custom-plugins/guide-driver/index.tsx

@@ -21,7 +21,7 @@ type ButtonStatus = {
   playBtnStatus?: Boolean;
   /** 声部状态 */
   subjectStatus?: Boolean;
-  /** 练习模式 */
+  /** 是否显示模式切换 */
   modelTypeStatus?: Boolean;
   /** 播放模式 演唱 演奏 */
   playType?: Boolean;
@@ -33,6 +33,8 @@ type ButtonStatus = {
   originPlayType?: Boolean;
   /** 是否显示原音 */
   originBtnStatus?: Boolean;
+  /** 是否显示切换曲谱列表 */
+  showSwitchList?: Boolean;
 };
 
 /** 练习模式 */
@@ -50,7 +52,7 @@ export const PractiseDriver = defineComponent({
     // 初始化部分引导位置
     const driverInitialPosition = (popover: PopoverDOM, options: { config: Config; state: State }) => {
       options.config.stageRadius = 5;
-      options.config.stagePadding = 8;
+      options.config.stagePadding = 4;
       try {
         const rect = options.state.activeElement?.getBoundingClientRect();
         popover.wrapper.style.marginLeft = -(rect?.width || 0) / 2 + 4 + "px";
@@ -69,9 +71,9 @@ export const PractiseDriver = defineComponent({
       }
 
       // 显示指法
-      if (!state.setting.displayFingering) {
-        length -= 1;
-      }
+      // if (!state.setting.displayFingering) {
+      //   length -= 1;
+      // }
 
       // 声部
       if (!props.statusAll.subjectStatus) {
@@ -83,7 +85,7 @@ export const PractiseDriver = defineComponent({
 
       // pc端不显示标题和模式切换引导
       if (state.platform === IPlatform.PC) {
-        length -= 2;
+        // length -= 2;
       } else {
         // 判断是否有标题
         if (!props.statusAll.backTitle || props.statusAll.titleType === "NONE") {
@@ -94,6 +96,9 @@ export const PractiseDriver = defineComponent({
           length -= 1;
         }
       }
+      if (!props.statusAll.showSwitchList) {
+        length -= 1;
+      }
       console.log(props.statusAll, "statusAll", length, state.setting.displayFingering);
 
       let options: Config = {
@@ -131,21 +136,24 @@ export const PractiseDriver = defineComponent({
           },
         });
       }
-      options.steps?.push({
-        element: ".driver-9",
-        popover: {
-          title: "",
-          description: "",
-          popoverClass: "popoverClass popoverClass9",
-          align: "end",
-          side: "bottom",
-          nextBtnText: `下一步 (2/${length})`,
-          showButtons: ["next"],
-          onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
-            driverInitialPosition(popover, options);
+
+      if (props.statusAll.modelTypeStatus) {
+        options.steps?.push({
+          element: ".driver-9",
+          popover: {
+            title: "",
+            description: "",
+            popoverClass: "popoverClass popoverClass9",
+            align: "end",
+            side: "bottom",
+            nextBtnText: `下一步 (2/${length})`,
+            showButtons: ["next"],
+            onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
+              driverInitialPosition(popover, options);
+            },
           },
-        },
-      });
+        });
+      }
 
       if (props.statusAll.playType) {
         options.steps?.push({
@@ -253,14 +261,21 @@ export const PractiseDriver = defineComponent({
           popover: {
             title: "",
             description: "",
-            popoverClass: "popoverClass popoverClass6",
+            popoverClass: "popoverClass popoverClass6-end popoverClose",
             align: "end",
             side: "bottom",
-            nextBtnText: `下一步 (${options.steps.length + 1}/${length})`, //"下一步6/" + length,
-            showButtons: ["next"],
+            prevBtnText: "再看一遍",
+            doneBtnText: "完成",
+            showButtons: ["next", "previous"],
             onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
               driverInitialPosition(popover, options);
             },
+            onPrevClick: () => {
+              driverObj.drive(0);
+            },
+            onNextClick: () => {
+              onDriverClose();
+            },
           },
         });
       } else {
@@ -335,7 +350,32 @@ export const PractiseDriver = defineComponent({
               onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
                 driverInitialPosition(popover, options);
                 const rect = options.state.activeElement?.getBoundingClientRect();
-                popover.wrapper.style.marginLeft = (rect?.width || 0) / 2 + 4 + "px";
+                popover.wrapper.style.marginLeft = (rect?.width || 0) / 2 + "px";
+              },
+              onPrevClick: () => {
+                driverObj.drive(0);
+              },
+              onNextClick: () => {
+                onDriverClose();
+              },
+            },
+          });
+        } else if (!props.statusAll.showSwitchList) {
+          options.steps?.push({
+            element: ".driver-6",
+            popover: {
+              title: "",
+              description: "",
+              popoverClass: "popoverClass popoverClass6-end popoverClose",
+              align: "end",
+              side: "bottom",
+              prevBtnText: "再看一遍",
+              doneBtnText: "完成",
+              showButtons: ["next", "previous"],
+              onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
+                driverInitialPosition(popover, options);
+                // const rect = options.state.activeElement?.getBoundingClientRect();
+                // popover.wrapper.style.marginLeft = -(rect?.width || 0) / 2 + 4 + "px";
               },
               onPrevClick: () => {
                 driverObj.drive(0);
@@ -380,7 +420,7 @@ export const PractiseDriver = defineComponent({
                 onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
                   driverInitialPosition(popover, options);
                   const rect = options.state.activeElement?.getBoundingClientRect();
-                  popover.wrapper.style.marginLeft = (rect?.width || 0) / 2 + 4 + "px";
+                  popover.wrapper.style.marginLeft = (rect?.width || 0) / 2 + "px";
                 },
                 onPrevClick: () => {
                   driverObj.drive(0);
@@ -488,7 +528,7 @@ export const FollowDriver = defineComponent({
     // 初始化部分引导位置
     const driverInitialPosition = (popover: PopoverDOM, options: { config: Config; state: State }) => {
       options.config.stageRadius = 5;
-      options.config.stagePadding = 8;
+      options.config.stagePadding = 4;
       try {
         const rect = options.state.activeElement?.getBoundingClientRect();
         popover.wrapper.style.marginLeft = -(rect?.width || 0) / 2 + 4 + "px";
@@ -693,7 +733,7 @@ export const EvaluatingDriver = defineComponent({
     // 初始化部分引导位置
     const driverInitialPosition = (popover: PopoverDOM, options: { config: Config; state: State }) => {
       options.config.stageRadius = 5;
-      options.config.stagePadding = 8;
+      options.config.stagePadding = 4;
       try {
         const rect = options.state.activeElement?.getBoundingClientRect();
         popover.wrapper.style.marginLeft = -(rect?.width || 0) / 2 + 4 + "px";
@@ -923,7 +963,7 @@ export const EvaluatingResultDriver = defineComponent({
     // 初始化部分引导位置
     const driverInitialPosition = (popover: PopoverDOM, options: { config: Config; state: State }, position = 1) => {
       options.config.stageRadius = 1000;
-      options.config.stagePadding = 0;
+      options.config.stagePadding = 2;
       try {
         const rect = options.state.activeElement?.getBoundingClientRect();
         popover.wrapper.style.marginLeft = ((rect?.width || 0) / 2) * position + 4 + "px";
@@ -974,7 +1014,7 @@ export const EvaluatingResultDriver = defineComponent({
               showButtons: ["next"],
               onPopoverRender: (popover: PopoverDOM, options: { config: Config; state: State }) => {
                 options.config.stageRadius = 1000;
-                options.config.stagePadding = 0;
+                options.config.stagePadding = 2;
                 try {
                   const rect = options.state.activeElement?.getBoundingClientRect();
                   popover.wrapper.style.marginLeft = (rect?.width || 0) / 2 - 4 + "px";
@@ -1122,7 +1162,7 @@ export const EvaluatingReportDriver = defineComponent({
       options.config.stagePadding = 0;
       try {
         const rect = options.state.activeElement?.getBoundingClientRect();
-        popover.wrapper.style.marginLeft = -(rect?.width || 0) / 2 + 34 + "px";
+        popover.wrapper.style.marginLeft = -(rect?.width || 0) / 2 + 16 + "px";
       } catch {}
     };
 
@@ -1146,7 +1186,7 @@ export const EvaluatingReportDriver = defineComponent({
                 options.config.stagePadding = 0;
                 try {
                   const rect = options.state.activeElement?.getBoundingClientRect();
-                  popover.wrapper.style.marginLeft = ((rect?.width || 0) / 2) * -1 + 34 + "px";
+                  popover.wrapper.style.marginLeft = ((rect?.width || 0) / 2) * -1 + 16 + "px";
                 } catch {}
               },
             },
@@ -1167,7 +1207,7 @@ export const EvaluatingReportDriver = defineComponent({
                 options.config.stagePadding = 5;
                 try {
                   const rect = options.state.activeElement?.getBoundingClientRect();
-                  popover.wrapper.style.marginLeft = ((rect?.width || 0) / 2) * -1 + 34 + "px";
+                  popover.wrapper.style.marginLeft = ((rect?.width || 0) / 2) * -1 + 16 + "px";
                 } catch {}
               },
               onPrevClick: () => {
@@ -1196,7 +1236,7 @@ export const EvaluatingReportDriver = defineComponent({
                 options.config.stagePadding = 0;
                 try {
                   const rect = options.state.activeElement?.getBoundingClientRect();
-                  popover.wrapper.style.marginLeft = ((rect?.width || 0) / 2) * -1 + 34 + "px";
+                  popover.wrapper.style.marginLeft = ((rect?.width || 0) / 2) * -1 + 16 + "px";
                 } catch {}
               },
               onPrevClick: () => {
@@ -1242,7 +1282,7 @@ export const EvaluatingReportDriver = defineComponent({
               options.config.stagePadding = 0;
               try {
                 const rect = options.state.activeElement?.getBoundingClientRect();
-                popover.wrapper.style.marginLeft = ((rect?.width || 0) / 2) * -1 + 34 + "px";
+                popover.wrapper.style.marginLeft = ((rect?.width || 0) / 2) * -1 + 16 + "px";
               } catch {}
             },
           },
@@ -1266,7 +1306,7 @@ export const EvaluatingReportDriver = defineComponent({
                 options.config.stagePadding = 0;
                 try {
                   const rect = options.state.activeElement?.getBoundingClientRect();
-                  popover.wrapper.style.marginLeft = ((rect?.width || 0) / 2) * -1 + 34 + "px";
+                  popover.wrapper.style.marginLeft = ((rect?.width || 0) / 2) * -1 + 16 + "px";
                 } catch {}
               },
             },
@@ -1287,7 +1327,7 @@ export const EvaluatingReportDriver = defineComponent({
                 options.config.stagePadding = 5;
                 try {
                   const rect = options.state.activeElement?.getBoundingClientRect();
-                  popover.wrapper.style.marginLeft = ((rect?.width || 0) / 2) * -1 + 34 + "px";
+                  popover.wrapper.style.marginLeft = ((rect?.width || 0) / 2) * -1 + 16 + "px";
                 } catch {}
               },
               onPrevClick: () => {

+ 6 - 5
src/page-instrument/custom-plugins/helper-model/recommendation/index.module.less

@@ -43,7 +43,7 @@
                     font-family: PingFangSC, PingFang SC;
                     font-weight: 500;
                     font-size: 13px;
-                    color: #B6C4D2;
+                    color: #aaaaaa;
                 }
             }
             .dropdownMenu{
@@ -132,6 +132,7 @@
                         font-size: 14px;
                         color: #131415;
                         caret-color: #01C1B5;
+                        min-height: 80px;
                         &::placeholder {
                             font-weight: 400;
                             font-size: 14px;
@@ -150,8 +151,8 @@
                             margin-right: 0;
                         }
                         .van-uploader__preview-image{
-                            width: 56px;
-                            height: 56px;
+                            width: 54px;
+                            height: 54px;
                             border-radius: 6px;
                         }
                         .van-uploader__preview-delete--shadow{
@@ -173,8 +174,8 @@
                     }
                 }
                 .uploaderbox{
-                    width: 56px;
-                    height: 56px;
+                    width: 54px;
+                    height: 54px;
                     background: #FFFFFF;
                     border-radius: 6px;
                     border: 1px dashed #D9D9D9;

+ 9 - 4
src/page-instrument/custom-plugins/recording-time/index.tsx

@@ -9,14 +9,15 @@ const recordData = reactive({
 	starTime: 0,
 });
 const handleRecord = () => {
-	// 不是练习模式不记录
-	if (state.modeType !== "practise") return;
+	// 不是练习模式不记录,web后台不记录
+	if (state.modeType !== "practise" || state.systemType === 'web') return;
 	let total = Date.now() - recordData.starTime;
 	recordData.starTime = Date.now();
 	if (total < 0) total = 0;
 	const totalTime = total / 1000;
-
-	const body = {
+	const query: any = getQuery();
+	
+	const body: any = {
 		clientType: storeData.user.clientType,
 		musicSheetId: state.examSongId,
 		sysMusicScoreId: state.examSongId,
@@ -26,6 +27,10 @@ const handleRecord = () => {
 		deviceType: browser().android ? "ANDROID" : "IOS",
 		behaviorId: getBehaviorId(),
 	};
+	// 如果是作业模式,需要添加作业id
+	if (query.workRecord || query.evaluatingRecord) {
+		body.lessonDetailId = query.workRecord || query.evaluatingRecord
+	}
 	api_musicPracticeRecordSave(body);
 };
 

BIN
src/page-instrument/custom-plugins/the-vip/icon_bg.png


BIN
src/page-instrument/custom-plugins/the-vip/icon_btn.png


BIN
src/page-instrument/custom-plugins/the-vip/icon_btn_cancel.png


BIN
src/page-instrument/custom-plugins/the-vip/icon_close.png


BIN
src/page-instrument/custom-plugins/the-vip/icon_title.png


+ 0 - 60
src/page-instrument/custom-plugins/the-vip/index.module.less

@@ -1,60 +0,0 @@
-.container {
-    position: relative;
-    width: 278px;
-    height: 252px;
-    background: url('./icon_bg.png') no-repeat;
-    background-size: contain;
-    display: flex;
-    flex-direction: column;
-    padding-top: 126px;
-}
-
-.close {
-    position: absolute;
-    right: 0;
-    top: 30px;
-    width: 24px;
-    height: 24px;
-}
-
-.title {
-    margin-left: 14px;
-    width: 80px;
-    display: block;
-}
-
-.content {
-    position: relative;
-    padding: 0 13px 25px 13px;
-    font-size: 14px;
-    font-weight: 400;
-    color: #333333;
-    line-height: 22px;
-    z-index: 10;
-}
-
-.btns {
-    // width: 159px;
-    margin: 0 auto 23px;
-    display: flex;
-    justify-content: center;
-    font-size: 16px;
-    color: #777;
-    line-height: 22px;
-    text-align: center;
-
-    .btn {
-        width: 101px;
-        height: 37px;
-        cursor: pointer;
-    }
-
-    .btnCancel {
-        margin-right: 10px;
-    }
-
-    img {
-        width: 100%;
-        // margin-bottom: 9px;
-    }
-}

+ 0 - 59
src/page-instrument/custom-plugins/the-vip/index.tsx

@@ -1,59 +0,0 @@
-import { defineComponent } from "vue";
-import icon_title from "./icon_title.png";
-import icon_btn from "./icon_btn.png";
-import icon_btn_cancel from "./icon_btn_cancel.png";
-import icon_close from "./icon_close.png";
-import styles from "./index.module.less";
-import { Popup } from "vant";
-import { api_back, api_goback } from "/src/helpers/communication";
-import { postMessage } from "/src/utils/native-message";
-import { getQuery } from "/src/utils/queryString";
-
-export default defineComponent({
-  name: "TheVip",
-  setup() {
-    const apiUrls = {
-      dev: "https://dev.kt.colexiu.com",
-      test: "https://test.lexiaoya.cn",
-      online: "https://kt.colexiu.com",
-    };
-    let environment: "dev" | "test" | "online" = location.origin.includes("//dev") ? "dev" : location.origin.includes("//test") ? "test" : location.origin.includes("//online") || location.origin.includes("//kt") || location.origin.includes("//mec") ? "online" : "dev";
-    const close = () => {
-      const query = getQuery();
-      if (query.modelType) {
-        api_goback();
-      } else {
-        api_back();
-      }
-    };
-
-    return () => (
-      <Popup teleport="body" closeOnClickOverlay={false} class={["popup-custom"]} show={true}>
-        <div class={styles.container}>
-          {/* <img class={styles.close} src={icon_close} onClick={close} /> */}
-          {/* <img class={styles.title} src={icon_title} /> */}
-          <div class={styles.content}>
-            立即开通<span style={{ color: "#FF5A56" }}>"乐器AI学练工具"</span>服务,解锁更多专属权益,享受全新学习体验!
-          </div>
-          <div class={styles.btns}>
-            <img class={[styles.btn, styles.btnCancel]} src={icon_btn_cancel} onClick={close} />
-            <img
-              class={styles.btn}
-              src={icon_btn}
-              onClick={() => {
-                postMessage({
-                  api: "openWebView",
-                  content: {
-                    url: `${location.origin.includes("192") ? "https://test.lexiaoya.cn" : apiUrls[environment]}/classroom-app/#/member-center`,
-                    orientation: 1,
-                  },
-                });
-              }}
-            />
-            {/* <div onClick={close}>暂不领取</div> */}
-          </div>
-        </div>
-      </Popup>
-    );
-  },
-});

+ 4 - 1
src/page-instrument/custom-plugins/work-home/index.tsx

@@ -4,6 +4,7 @@ import styles from "./index.module.less";
 import { api_lessonTrainingSubmitTraining, api_lessonTrainingTrainingStudentDetail } from "../../api";
 import state, { handleSetSpeed, hanldeDirectSelection, setSection } from "/src/state";
 import { getQuery } from "/src/utils/queryString";
+import { data as workData } from "../work-index"
 
 export default defineComponent({
 	name: "HomeWork",
@@ -43,6 +44,7 @@ export default defineComponent({
 			const workeData = props.workeData;
 			if (workeData.id) {
 				training.times = workeData.times || 0;
+				console.log('作业次数',workeData.trainingTimes)
 				training.trainingTimes = workeData.trainingTimes || 0;
 				training.trainingSpeed = workeData.trainingSpeed;
 				training.start = Number(workeData.start);
@@ -59,6 +61,7 @@ export default defineComponent({
 			const res = await api_lessonTrainingTrainingStudentDetail(props.workeData.id, 'homeWork');
 			if (res?.code === 200) {
 				training.trainingTimes = res.data.trainingTimes || 0;
+				workData.worke.trainingTimes = training.trainingTimes;
 			}
 		};
 
@@ -81,7 +84,7 @@ export default defineComponent({
 				if (state.playState === "play") {
 					training.starTime = Date.now();
 				} else {
-					addHomeworkRecored();
+					// addHomeworkRecored();
 				}
 			}
 		);

+ 1 - 1
src/page-instrument/custom-plugins/work-index/index.tsx

@@ -13,7 +13,7 @@ const workEvaluatRef = ref();
 export const data = reactive({
 	/** 作业类型:练习PRACTICE, 评测EVALUATION */
 	trainingType: "" as "PRACTICE" | "EVALUATION",
-	worke: {},
+	worke: {} as any,
 });
 
 export const HANDLE_WORK_ADD = () => {

Some files were not shown because too many files changed in this diff