Browse Source

学生端课件播放,音频动效

liushengqiang 1 năm trước cách đây
mục cha
commit
063857eaa1

+ 2 - 0
package.json

@@ -29,6 +29,7 @@
     "dayjs": "^1.11.7",
     "echarts": "^5.4.2",
     "html2canvas": "^1.4.1",
+    "naive-ui": "^2.34.4",
     "numeral": "^2.0.6",
     "plyr": "^3.7.8",
     "qrcode": "^1.5.3",
@@ -38,6 +39,7 @@
     "umi-request": "^1.4.0",
     "vant": "^4.1.2",
     "vconsole": "^3.15.0",
+    "vudio.js": "^1.0.3",
     "vue": "^3.2.47",
     "vue-awesome-swiper": "^5.0.1",
     "vue-router": "^4.1.6",

+ 154 - 1
pnpm-lock.yaml

@@ -22,6 +22,9 @@ dependencies:
   html2canvas:
     specifier: ^1.4.1
     version: 1.4.1
+  naive-ui:
+    specifier: ^2.34.4
+    version: 2.34.4(vue@3.2.47)
   numeral:
     specifier: ^2.0.6
     version: 2.0.6
@@ -49,6 +52,9 @@ dependencies:
   vconsole:
     specifier: ^3.15.0
     version: 3.15.0
+  vudio.js:
+    specifier: ^1.0.3
+    version: 1.0.3
   vue:
     specifier: ^3.2.47
     version: 3.2.47
@@ -1351,6 +1357,26 @@ packages:
       '@babel/helper-validator-identifier': 7.19.1
       to-fast-properties: 2.0.0
 
+  /@css-render/plugin-bem@0.15.12(css-render@0.15.12):
+    resolution: {integrity: sha512-Lq2jSOZn+wYQtsyaFj6QRz2EzAnd3iW5fZeHO1WSXQdVYwvwGX0ZiH3X2JQgtgYLT1yeGtrwrqJdNdMEUD2xTw==}
+    peerDependencies:
+      css-render: ~0.15.12
+    dependencies:
+      css-render: 0.15.12
+    dev: false
+
+  /@css-render/vue3-ssr@0.15.12(vue@3.2.47):
+    resolution: {integrity: sha512-AQLGhhaE0F+rwybRCkKUdzBdTEM/5PZBYy+fSYe1T9z9+yxMuV/k7ZRqa4M69X+EI1W8pa4kc9Iq2VjQkZx4rg==}
+    peerDependencies:
+      vue: ^3.0.11
+    dependencies:
+      vue: 3.2.47
+    dev: false
+
+  /@emotion/hash@0.8.0:
+    resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==}
+    dev: false
+
   /@esbuild/android-arm64@0.17.15:
     resolution: {integrity: sha512-0kOB6Y7Br3KDVgHeg8PRcvfLkq+AccreK///B4Z6fNZGr/tNHX0z2VywCc7PTeWp+bPvjA5WMvNXltHw5QjAIA==}
     engines: {node: '>=12'}
@@ -1640,6 +1666,10 @@ packages:
       '@jridgewell/resolve-uri': 3.1.0
       '@jridgewell/sourcemap-codec': 1.4.14
 
+  /@juggle/resize-observer@3.4.0:
+    resolution: {integrity: sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==}
+    dev: false
+
   /@nodelib/fs.scandir@2.1.5:
     resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
     engines: {node: '>= 8'}
@@ -1709,6 +1739,10 @@ packages:
     resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
     dev: true
 
+  /@types/katex@0.14.0:
+    resolution: {integrity: sha512-+2FW2CcT0K3P+JMR8YG846bmDwplKUTsWgT2ENwdQ1UdVfRk3GQrh6Mi4sTopy30gI8Uau5CEqHTDZ6YvWIUPA==}
+    dev: false
+
   /@types/liftoff@4.0.0:
     resolution: {integrity: sha512-Ny/PJkO6nxWAQnaet8q/oWz15lrfwvdvBpuY4treB0CSsBO1CG0fVuNLngR3m3bepQLd+E4c3Y3DlC2okpUvPw==}
     dependencies:
@@ -1716,6 +1750,16 @@ packages:
       '@types/node': 16.18.23
     dev: true
 
+  /@types/lodash-es@4.17.7:
+    resolution: {integrity: sha512-z0ptr6UI10VlU6l5MYhGwS4mC8DZyYer2mCoyysZtSF7p26zOX8UpbrV0YpNYLGS8K4PUFIyEr62IMFFjveSiQ==}
+    dependencies:
+      '@types/lodash': 4.14.195
+    dev: false
+
+  /@types/lodash@4.14.195:
+    resolution: {integrity: sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==}
+    dev: false
+
   /@types/node@16.18.23:
     resolution: {integrity: sha512-XAMpaw1s1+6zM+jn2tmw8MyaRDIJfXxqmIQIS0HfoGYPuf7dUWeiUKopwq13KFX9lEp1+THGtlaaYx39Nxr58g==}
     dev: true
@@ -2214,6 +2258,10 @@ packages:
     engines: {node: '>=8'}
     dev: true
 
+  /async-validator@4.2.5:
+    resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==}
+    dev: false
+
   /autoprefixer@10.4.14(postcss@8.4.21):
     resolution: {integrity: sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==}
     engines: {node: ^10 || ^12 || >=14}
@@ -2618,6 +2666,13 @@ packages:
       utrie: 1.0.2
     dev: false
 
+  /css-render@0.15.12:
+    resolution: {integrity: sha512-eWzS66patiGkTTik+ipO9qNGZ+uNuGyTmnz6/+EJIiFg8+3yZRpnMwgFo8YdXhQRsiePzehnusrxVvugNjXzbw==}
+    dependencies:
+      '@emotion/hash': 0.8.0
+      csstype: 3.0.11
+    dev: false
+
   /cssesc@3.0.0:
     resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
     engines: {node: '>=4'}
@@ -2627,10 +2682,29 @@ packages:
   /csstype@2.6.21:
     resolution: {integrity: sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==}
 
+  /csstype@3.0.11:
+    resolution: {integrity: sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==}
+    dev: false
+
   /custom-event-polyfill@1.0.7:
     resolution: {integrity: sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w==}
     dev: false
 
+  /date-fns-tz@1.3.8(date-fns@2.30.0):
+    resolution: {integrity: sha512-qwNXUFtMHTTU6CFSFjoJ80W8Fzzp24LntbjFFBgL/faqds4e5mo9mftoRLgr3Vi1trISsg4awSpYVsOQCRnapQ==}
+    peerDependencies:
+      date-fns: '>=2.0.0'
+    dependencies:
+      date-fns: 2.30.0
+    dev: false
+
+  /date-fns@2.30.0:
+    resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==}
+    engines: {node: '>=0.11'}
+    dependencies:
+      '@babel/runtime': 7.21.0
+    dev: false
+
   /dayjs@1.11.7:
     resolution: {integrity: sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==}
     dev: false
@@ -2976,6 +3050,10 @@ packages:
     engines: {node: '>=0.10.0'}
     dev: true
 
+  /evtd@0.2.4:
+    resolution: {integrity: sha512-qaeGN5bx63s/AXgQo8gj6fBkxge+OoLddLniox5qtLAEY5HSnuSlISXVPxnSae1dWblvTh4/HoMIB+mbMsvZzw==}
+    dev: false
+
   /execa@0.8.0:
     resolution: {integrity: sha512-zDWS+Rb1E8BlqqhALSt9kUhss8Qq4nN3iof3gsOdyINksElaPyNBtKUMTR62qhvgVWR0CqCX7sdnKe4MnUbFEA==}
     engines: {node: '>=4'}
@@ -3334,6 +3412,11 @@ packages:
       tslib: 2.5.0
     dev: true
 
+  /highlight.js@11.8.0:
+    resolution: {integrity: sha512-MedQhoqVdr0U6SSnWPzfiadUcDHfN/Wzq25AkXiQv9oiOO/sG0S7XkvpFIqWBl9Yq1UYyYOOVORs5UW2XlPyzg==}
+    engines: {node: '>=12.0.0'}
+    dev: false
+
   /homedir-polyfill@1.0.3:
     resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==}
     engines: {node: '>=0.10.0'}
@@ -3783,7 +3866,6 @@ packages:
 
   /lodash@4.17.21:
     resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
-    dev: true
 
   /log-symbols@4.1.0:
     resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
@@ -3956,6 +4038,32 @@ packages:
     resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==}
     dev: true
 
+  /naive-ui@2.34.4(vue@3.2.47):
+    resolution: {integrity: sha512-aPG8PDfhSzIzn/jSC9y3Jb3Pe2wHJ7F0cFV1EWlbImSrZECeUmoc+fIcOSWbizoztkKfaUAeKwYdMl09MKkj1g==}
+    peerDependencies:
+      vue: ^3.0.0
+    dependencies:
+      '@css-render/plugin-bem': 0.15.12(css-render@0.15.12)
+      '@css-render/vue3-ssr': 0.15.12(vue@3.2.47)
+      '@types/katex': 0.14.0
+      '@types/lodash': 4.14.195
+      '@types/lodash-es': 4.17.7
+      async-validator: 4.2.5
+      css-render: 0.15.12
+      date-fns: 2.30.0
+      date-fns-tz: 1.3.8(date-fns@2.30.0)
+      evtd: 0.2.4
+      highlight.js: 11.8.0
+      lodash: 4.17.21
+      lodash-es: 4.17.21
+      seemly: 0.3.6
+      treemate: 0.3.11
+      vdirs: 0.1.8(vue@3.2.47)
+      vooks: 0.2.12(vue@3.2.47)
+      vue: 3.2.47
+      vueuc: 0.4.51(vue@3.2.47)
+    dev: false
+
   /nanoid@3.3.6:
     resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==}
     engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -4625,6 +4733,10 @@ packages:
     dev: true
     optional: true
 
+  /seemly@0.3.6:
+    resolution: {integrity: sha512-lEV5VB8BUKTo/AfktXJcy+JeXns26ylbMkIUco8CYREsQijuz4mrXres2Q+vMLdwkuLxJdIPQ8IlCIxLYm71Yw==}
+    dev: false
+
   /semver@5.7.1:
     resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==}
     hasBin: true
@@ -4912,6 +5024,10 @@ packages:
       is-number: 7.0.0
     dev: true
 
+  /treemate@0.3.11:
+    resolution: {integrity: sha512-M8RGFoKtZ8dF+iwJfAJTOH/SM4KluKOKRJpjCMhI8bG3qB74zrFoArKZ62ll0Fr3mqkMJiQOmWYkdYgDeITYQg==}
+    dev: false
+
   /tslib@1.14.1:
     resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
     dev: true
@@ -5105,6 +5221,15 @@ packages:
       mutation-observer: 1.0.3
     dev: false
 
+  /vdirs@0.1.8(vue@3.2.47):
+    resolution: {integrity: sha512-H9V1zGRLQZg9b+GdMk8MXDN2Lva0zx72MPahDKc30v+DtwKjfyOSXWRIX4t2mhDubM1H09gPhWeth/BJWPHGUw==}
+    peerDependencies:
+      vue: ^3.0.11
+    dependencies:
+      evtd: 0.2.4
+      vue: 3.2.47
+    dev: false
+
   /vite-plugin-eslint@1.8.1(eslint@8.38.0)(vite@4.2.1):
     resolution: {integrity: sha512-PqdMf3Y2fLO9FsNPmMX+//2BF5SF8nEWspZdgl4kSt7UvHDRHVVfHvxsD7ULYzZrJDGRxR81Nq7TOFgwMnUang==}
     peerDependencies:
@@ -5154,6 +5279,19 @@ packages:
       fsevents: 2.3.2
     dev: true
 
+  /vooks@0.2.12(vue@3.2.47):
+    resolution: {integrity: sha512-iox0I3RZzxtKlcgYaStQYKEzWWGAduMmq+jS7OrNdQo1FgGfPMubGL3uGHOU9n97NIvfFDBGnpSvkWyb/NSn/Q==}
+    peerDependencies:
+      vue: ^3.0.0
+    dependencies:
+      evtd: 0.2.4
+      vue: 3.2.47
+    dev: false
+
+  /vudio.js@1.0.3:
+    resolution: {integrity: sha512-pip5HpUUmRYTKblq9EoDwUaKSTD4O+8LbGpzKYxRt6ZVQLzS/SpmjvsMTb8Wut6DzAn5fYzxifb9xzRZwEI2IQ==}
+    dev: false
+
   /vue-awesome-swiper@5.0.1(swiper@9.3.2)(vue@3.2.47):
     resolution: {integrity: sha512-mWjFJzUqA4lG+DmsmibvMpoiBnl+IH2SSeiiQ3i5M0t1y9FknTxnGT0DsMb2YdJLgjYMEK3sYOWzqgLnZMH8Lg==}
     peerDependencies:
@@ -5244,6 +5382,21 @@ packages:
       '@vue/server-renderer': 3.2.47(vue@3.2.47)
       '@vue/shared': 3.2.47
 
+  /vueuc@0.4.51(vue@3.2.47):
+    resolution: {integrity: sha512-pLiMChM4f+W8czlIClGvGBYo656lc2Y0/mXFSCydcSmnCR1izlKPGMgiYBGjbY9FDkFG8a2HEVz7t0DNzBWbDw==}
+    peerDependencies:
+      vue: ^3.0.11
+    dependencies:
+      '@css-render/vue3-ssr': 0.15.12(vue@3.2.47)
+      '@juggle/resize-observer': 3.4.0
+      css-render: 0.15.12
+      evtd: 0.2.4
+      seemly: 0.3.6
+      vdirs: 0.1.8(vue@3.2.47)
+      vooks: 0.2.12(vue@3.2.47)
+      vue: 3.2.47
+    dev: false
+
   /wcwidth@1.0.1:
     resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
     dependencies:

BIN
public/favicon.ico


+ 4 - 4
src/common/images/icon_start.svg

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="106px" height="30px" viewBox="0 0 106 30" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<svg width="107px" height="30px" viewBox="0 0 107 30" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
     <title>按钮/小按钮/橙</title>
     <defs>
         <linearGradient x1="15.3622126%" y1="47.2035312%" x2="89.7647319%" y2="52.9528289%" id="linearGradient-1">
@@ -31,9 +31,9 @@
         </filter>
     </defs>
     <g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <g id="小酷Ai-2备份-2" transform="translate(-672.000000, -292.000000)">
-            <g id="编组-8" transform="translate(503.000000, 52.000000)">
-                <g id="编组-2" transform="translate(169.000000, 240.000000)">
+        <g id="小酷Ai-" transform="translate(-672.000000, -296.000000)">
+            <g id="编组-8" transform="translate(429.000000, 52.000000)">
+                <g id="编组-2" transform="translate(243.035036, 244.000000)">
                     <g id="button-normal">
                         <use fill="url(#linearGradient-1)" xlink:href="#path-3"></use>
                         <use fill="url(#linearGradient-2)" xlink:href="#path-3"></use>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/common/images/index.json


+ 1 - 0
src/shims-vue.d.ts

@@ -3,3 +3,4 @@ declare module '*.vue' {
   const component: DefineComponent<{}, {}, any>;
   export default component;
 }
+declare module 'vudio.js';

BIN
src/views/co-ai/image/1.png


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 20
src/views/co-ai/image/1.svg


BIN
src/views/co-ai/image/2.png


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 19
src/views/co-ai/image/2.svg


BIN
src/views/co-ai/image/3.png


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 20
src/views/co-ai/image/3.svg


BIN
src/views/co-ai/image/4.png


+ 0 - 21
src/views/co-ai/image/icon_leftBg.svg

@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg width="117px" height="297px" viewBox="0 0 117 297" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
-    <title>蒙版备份</title>
-    <defs>
-        <linearGradient x1="43.5893735%" y1="100%" x2="57.5983913%" y2="18.0655582%" id="linearGradient-1">
-            <stop stop-color="#43B2FF" offset="0%"></stop>
-            <stop stop-color="#159AF7" offset="100%"></stop>
-        </linearGradient>
-        <linearGradient x1="42.9740198%" y1="3.0851473%" x2="56.7925564%" y2="89.619475%" id="linearGradient-2">
-            <stop stop-color="#FFFFFF" offset="0%"></stop>
-            <stop stop-color="#FFFFFF" stop-opacity="0.333539629" offset="100%"></stop>
-        </linearGradient>
-        <path d="M21,1 L95,1 C106.59798,1 116,10.4020203 116,22 L116,275 C116,286.59798 106.59798,296 95,296 L21,296 C9.954305,296 1,287.045695 1,276 L1,21 C1,9.954305 9.954305,1 21,1 Z" id="path-3"></path>
-    </defs>
-    <g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <mask id="mask-4" fill="white">
-            <use xlink:href="#path-3"></use>
-        </mask>
-        <use id="蒙版备份" stroke="url(#linearGradient-2)" stroke-width="2" fill="url(#linearGradient-1)" xlink:href="#path-3"></use>
-    </g>
-</svg>

+ 8 - 3
src/views/co-ai/index.module.less

@@ -166,13 +166,18 @@
         background: linear-gradient(180deg, #FFFFFF 0%, #BFE1FF 100%);
         transform: scale(1.05);
         box-shadow: 0px 2px 4px 0px rgba(73, 159, 228, 1);
+        :global{
+            .van-notice-bar{
+                color: #1CACF1 !important;
+            }
+        }
     }
 
     .musicAvtor {
         display: block;
-        width: 8.2vw;
-        height: 8.2vw;
-        border-radius: 8Px;
+        width: 7.2vw;
+        height: 7.2vw;
+        border-radius: 10Px;
         object-fit: cover;
         flex-shrink: 0;
         margin-right: 1vw;

+ 2 - 10
src/views/co-ai/index.tsx

@@ -7,20 +7,12 @@ import icon_back from './image/icon_back.svg';
 import icon_down from '@/common/images/icon_down.svg';
 import icon_jianpu from '@/common/images/icon_jianpu.svg';
 import icon_jianpuActive from '@/common/images/icon_jianpuActive.svg';
-import icon_start from '@/common/images/icon_start.svg';
-import icon_1 from './image/1.svg';
-import icon_2 from './image/2.svg';
-import icon_3 from './image/3.svg';
-import png_1 from './image/1.png';
-import png_2 from './image/2.png';
-import png_3 from './image/3.png';
-import png_4 from './image/4.png';
+import icons from '@/common/images/index.json';
 import { postMessage, promisefiyPostMessage } from '@/helpers/native-message';
 import { rows } from './data.json';
 export default defineComponent({
   name: 'co-ai',
   setup() {
-    const icons = [icon_1, icon_2, icon_3];
     const types = [
       { src: 'https://daya.ks3-cn-beijing.ksyuncs.com/16880147803671.png' },
       { src: 'https://daya.ks3-cn-beijing.ksyuncs.com/16880147833062.png' },
@@ -186,7 +178,7 @@ export default defineComponent({
                 onClick={() => (data.isShowJianpu = !data.isShowJianpu)}
               />
               <img src={icon_down} onClick={handleSave} />
-              <img src={icon_start} onClick={() => handleGoto()} />
+              <img src={icons.icon_start} onClick={() => handleGoto()} />
             </div>
           </div>
         </div>

+ 133 - 0
src/views/courseware-play/component/audio-item/index.module.less

@@ -0,0 +1,133 @@
+.videoWrap {
+    position: relative;
+    width: 100%;
+    height: 100%;
+}
+.content{
+    height: 100%;
+    padding: 8% 20px;
+}
+.contentWrap{
+    height: 100%;
+    canvas{
+        width: 100%;
+        height: 100%;
+    }
+}
+
+.controls {
+    position: absolute;
+    left: 0;
+    bottom: 0;
+    right: 0;
+    height: 80px;
+    background: linear-gradient(0deg, rgba(0, 0, 0, 0.5), transparent);
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    transition: all 0.5s;
+
+    &.hide{
+        transform: translateY(100%);
+    }
+
+    .time {
+        display: flex;
+        justify-content: space-between;
+        width: 100%;
+        color: #fff;
+        font-size: 10px;
+        padding: 4px 20px;
+    }
+
+    .slider {
+        width: 100%;
+        padding: 0 20px;
+        :global {
+            .n-slider{
+                --n-handle-size: 13px !important;
+                --n-fill-color: var(--van-primary-color) !important;
+                --n-fill-color-hover: var(--van-primary-color) !important;
+            }
+            .van-loading {
+                width: 100%;
+                height: 100%;
+            }
+        }
+    }
+
+    .actions {
+        display: flex;
+        width: 100%;
+        color: #fff;
+        font-size: 12px;
+        padding: 0 20px;
+        align-items: center;
+
+        .actionWrap {
+            display: flex;
+        }
+
+        .actionBtn {
+            display: flex;
+            width: 38px;
+            height: 38px;
+            padding: 4px 0;
+            background: transparent;
+        }
+
+        .actionBtn>img {
+            width: 100%;
+            height: 100%;
+        }
+
+        :global {
+            .van-loading__circular {
+                width: 100%;
+                height: 100%;
+            }
+        }
+
+        .playIcon {
+            display: none;
+        }
+
+        .btnPlay img:nth-child(2) {
+            display: block;
+        }
+
+        .btnPause img:nth-child(3) {
+            display: block;
+        }
+
+        .btnPlay,
+        .btnPause {
+            :global {
+                .van-loading {
+                    display: none;
+                }
+            }
+        }
+        .loopBtn{
+            :global{
+                .loop{
+                    display: block;
+                }
+                .loopActive{
+                    display: none;
+                }
+            }
+        }
+        .loopBtn.active{
+            :global{
+                .loop{
+                    display: none;
+                }
+                .loopActive{
+                    display: block;
+                }
+            }
+        }
+
+    }
+}

+ 178 - 0
src/views/courseware-play/component/audio-item/index.tsx

@@ -0,0 +1,178 @@
+import { defineComponent, reactive, toRefs, watch } from 'vue';
+import { ref } from 'vue';
+import styles from './index.module.less';
+
+import iconLoop from '../../image/icon-loop.svg';
+import iconLoopActive from '../../image/icon-loop-active.svg';
+import iconplay from '../../image/icon-play.svg';
+import iconpause from '../../image/icon-pause.svg';
+import { NSlider } from 'naive-ui';
+import Vudio from 'vudio.js';
+import { getSecondRPM } from '@/helpers/utils';
+
+export default defineComponent({
+  name: 'video-play',
+  props: {
+    item: {
+      type: Object,
+      default: () => {
+        return {};
+      }
+    },
+    show: {
+      type: Boolean,
+      default: false
+    },
+    showModel: {
+      type: Boolean,
+      default: false
+    },
+    isEmtry: {
+      type: Boolean,
+      default: false
+    }
+  },
+  emits: ['loadedmetadata', 'togglePlay', 'ended', 'reset'],
+  setup(props, { emit }) {
+    const { item, isEmtry } = toRefs(props);
+    const data = reactive({
+      timer: null as any,
+      currentTime: 0,
+      duration: 0,
+      loop: false,
+      playState: 'pause' as 'play' | 'pause',
+      vudio: null as any
+    });
+    const canvasRef: any = ref();
+    const audioRef: any = ref();
+    const contetRef = ref();
+
+    watch(
+      () => props.show,
+      val => {
+        if (val) {
+          onToggleAudio();
+        } else {
+          audioRef.value.pause();
+        }
+      }
+    );
+
+    // 切换音频播放
+    const onToggleAudio = () => {
+      if (audioRef.value.paused) {
+        onInit(audioRef.value, canvasRef.value);
+        audioRef.value.play();
+        data.playState = 'play';
+      } else {
+        audioRef.value.pause();
+        data.playState = 'pause';
+      }
+    };
+
+    const onInit = (audio: undefined, canvas: undefined) => {
+      if (!data.vudio) {
+        const rect = contetRef.value.getBoundingClientRect() || {
+          width: 200,
+          height: 200
+        };
+        data.vudio = new Vudio(audio, canvas, {
+          effect: 'waveform',
+          accuracy: 256,
+          width: rect.width,
+          height: rect.height,
+          waveform: {
+            maxHeight: 200,
+            color: [
+              [0, '#44D1FF'],
+              [0.5, '#44D1FF'],
+              [0.5, '#198CFE'],
+              [1, '#198CFE']
+            ],
+            prettify: false
+          }
+        });
+        data.vudio.dance();
+      }
+    };
+    /** 加载成功 */
+    const onLoadedmetadata = () => {
+      data.duration = audioRef.value.duration;
+      // if (data.isFirst) {
+      //   data.isFirst = false;
+      //   return;
+      // }
+      // if (props.playState === 'play'){
+      //     audioRef.value.play();
+      // }
+    };
+
+    /** 改变播放时间 */
+    const handleChangeTime = (val: number) => {
+      // audioRef.value.pause();
+      data.currentTime = val;
+      clearTimeout(data.timer);
+      data.timer = setTimeout(() => {
+        audioRef.value.currentTime = val;
+        // audioRef.value.play();
+        data.timer = null;
+      }, 300);
+    };
+
+    /** 播放结束 */
+    const onEnded = () => {
+      data.playState = 'pause';
+      emit('ended');
+    };
+    return () => (
+      <div class={styles.videoWrap}>
+        <div class={styles.content}>
+          <div ref={contetRef} class={styles.contentWrap}>
+            <canvas ref={canvasRef}></canvas>
+            <audio
+              src={isEmtry.value ? '' : item.value.content}
+              ref={audioRef}
+              loop={data.loop}
+              onLoadedmetadata={onLoadedmetadata}
+              onTimeupdate={() => {
+                if (data.timer) return;
+                data.currentTime = audioRef.value.currentTime;
+              }}
+              onEnded={onEnded}
+              crossorigin="anonymous"
+              playsinline="false"></audio>
+          </div>
+        </div>
+
+        <div class={[styles.controls, props.showModel ? '' : styles.hide]}>
+          <div class={styles.time}>
+            <div>{getSecondRPM(data.currentTime)}</div>
+            <div>{getSecondRPM(data.duration)}</div>
+          </div>
+          <div class={styles.slider}>
+            <NSlider
+              tooltip={false}
+              step={0.01}
+              class={styles.timeProgress}
+              value={data.currentTime}
+              max={data.duration}
+              onUpdate:value={val => handleChangeTime(val)}
+            />
+          </div>
+          <div
+            class={styles.actions}
+            onClick={(e: Event) => e.stopPropagation()}>
+            <div class={styles.actionBtn} onClick={() => onToggleAudio()}>
+              <img src={data.playState === 'pause' ? iconplay : iconpause} />
+            </div>
+            <div
+              class={styles.actionBtn}
+              onClick={() => (data.loop = !data.loop)}>
+              <img src={data.loop ? iconLoopActive : iconLoop} />
+            </div>
+          </div>
+        </div>
+      </div>
+    );
+  }
+});

BIN
src/views/courseware-play/image/tick.mp3


+ 31 - 14
src/views/courseware-play/index.tsx

@@ -31,6 +31,7 @@ import playLoadData from './datas/data.json';
 import { usePageVisibility, useRect } from '@vant/use';
 import VideoPlay from './component/video-play';
 import Tool, { ToolItem, ToolType } from './component/tool';
+import AudioItem from './component/audio-item';
 
 export default defineComponent({
   name: 'CoursewarePlay',
@@ -156,24 +157,26 @@ export default defineComponent({
           title: '其多列',
           type: 'VIDEO',
           content:
-            'https://gyt.ks3-cn-beijing.ksyuncs.com/courseware/1687838624636.mp4',
-          url: 'https://daya.ks3-cn-beijing.ksyun.com/202306/TiLloDA.jpg'
+            'https://gyt.ks3-cn-beijing.ksyuncs.com/courseware/1687844560120.mp4',
+          url: 'https://gyt.ks3-cn-beijing.ksyuncs.com/courseware/1687844640957.png'
         },
         {
-          id: '2',
-          name: '知识 音的高低',
-          title: '知识 音的高低',
-          type: 'IMG',
-          content: 'https://daya.ks3-cn-beijing.ksyun.com/202306/TiLlteU.png',
-          url: 'https://daya.ks3-cn-beijing.ksyun.com/202306/TiLlteU.png'
+          id: '5',
+          name: '歌曲表演 大鹿',
+          title: '歌曲表演 大鹿',
+          type: 'AUDIO',
+          content:
+            'https://cloud-coach.ks3-cn-beijing.ksyuncs.com/1686819360752.mp3',
+          url: 'https://gyt.ks3-cn-beijing.ksyuncs.com/courseware/1687916228530.png'
         },
         {
-          id: '3',
-          name: '欣赏 永远在童话里',
-          title: '欣赏 永远在童话里',
+          id: '2',
+          name: '其多列',
+          title: '其多列',
           type: 'IMG',
-          content: 'https://daya.ks3-cn-beijing.ksyun.com/202306/TiLlxJ0.png',
-          url: 'https://daya.ks3-cn-beijing.ksyun.com/202306/TiLlxJ0.png'
+          content:
+            'https://gyt.ks3-cn-beijing.ksyuncs.com/courseware/1688007481564.jpg',
+          url: 'https://gyt.ks3-cn-beijing.ksyuncs.com/courseware/1688007481564.jpg'
         },
         {
           id: '4',
@@ -191,7 +194,7 @@ export default defineComponent({
           ...m,
           iframeRef: null,
           videoEle: null,
-          autoPlay: index === 0, //加载完成是否自动播放
+          autoPlay: false, //加载完成是否自动播放
           isprepare: false, // 视频是否加载完成
           isRender: false // 是否渲染了
         };
@@ -557,6 +560,20 @@ export default defineComponent({
                       </>
                     ) : m.type === 'IMG' ? (
                       <img src={m.content} />
+                    ) : m.type === 'AUDIO' ? (
+                      <AudioItem
+                        item={m}
+                        show={popupData.activeIndex === mIndex}
+                        showModel={activeData.model}
+                        isEmtry={isEmtry}
+                        onEnded={() => {
+                          const _index = popupData.activeIndex + 1;
+                          console.log("🚀 ~ _index:", _index)
+                          if (_index < data.itemList.length) {
+                            handleSwipeChange(_index);
+                          }
+                        }}
+                      />
                     ) : (
                       <MusicScore
                         activeModel={activeData.model}

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác