hookehuyr

feat(视频播放器): 添加VideoPlayer组件并集成到HomePage

新增VideoPlayer组件以支持视频播放功能,并在HomePage中集成。同时添加了相关依赖video.js和@videojs-player/vue,确保视频播放功能的实现和兼容性。
...@@ -10,10 +10,12 @@ ...@@ -10,10 +10,12 @@
10 "dependencies": { 10 "dependencies": {
11 "@heroicons/vue": "^2.2.0", 11 "@heroicons/vue": "^2.2.0",
12 "@vant/use": "^1.6.0", 12 "@vant/use": "^1.6.0",
13 + "@videojs-player/vue": "^1.0.0",
13 "dayjs": "^1.11.13", 14 "dayjs": "^1.11.13",
14 "swiper": "^11.2.6", 15 "swiper": "^11.2.6",
15 "vant": "^4.9.18", 16 "vant": "^4.9.18",
16 "vconsole": "^3.15.1", 17 "vconsole": "^3.15.1",
18 + "video.js": "^7.21.7",
17 "vue": "^3.5.13", 19 "vue": "^3.5.13",
18 "vue-router": "^4.5.0", 20 "vue-router": "^4.5.0",
19 "weixin-js-sdk": "^1.6.5" 21 "weixin-js-sdk": "^1.6.5"
...@@ -1195,6 +1197,12 @@ ...@@ -1195,6 +1197,12 @@
1195 "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", 1197 "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
1196 "dev": true 1198 "dev": true
1197 }, 1199 },
1200 + "node_modules/@types/video.js": {
1201 + "version": "7.3.58",
1202 + "resolved": "https://registry.npmjs.org/@types/video.js/-/video.js-7.3.58.tgz",
1203 + "integrity": "sha512-1CQjuSrgbv1/dhmcfQ83eVyYbvGyqhTvb2Opxr0QCV+iJ4J6/J+XWQ3Om59WiwCd1MN3rDUHasx5XRrpUtewYQ==",
1204 + "peer": true
1205 + },
1198 "node_modules/@types/web-bluetooth": { 1206 "node_modules/@types/web-bluetooth": {
1199 "version": "0.0.21", 1207 "version": "0.0.21",
1200 "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", 1208 "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz",
...@@ -1214,6 +1222,62 @@ ...@@ -1214,6 +1222,62 @@
1214 "vue": "^3.0.0" 1222 "vue": "^3.0.0"
1215 } 1223 }
1216 }, 1224 },
1225 + "node_modules/@videojs-player/vue": {
1226 + "version": "1.0.0",
1227 + "resolved": "https://registry.npmjs.org/@videojs-player/vue/-/vue-1.0.0.tgz",
1228 + "integrity": "sha512-WonTezRfKu3fYdQLt/ta+nuKH6gMZUv8l40Jke/j4Lae7IqeO/+lLAmBnh3ni88bwR+vkFXIlZ2Ci7VKInIYJg==",
1229 + "peerDependencies": {
1230 + "@types/video.js": "7.x",
1231 + "video.js": "7.x",
1232 + "vue": "3.x"
1233 + }
1234 + },
1235 + "node_modules/@videojs/http-streaming": {
1236 + "version": "2.16.3",
1237 + "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.16.3.tgz",
1238 + "integrity": "sha512-91CJv5PnFBzNBvyEjt+9cPzTK/xoVixARj2g7ZAvItA+5bx8VKdk5RxCz/PP2kdzz9W+NiDUMPkdmTsosmy69Q==",
1239 + "dependencies": {
1240 + "@babel/runtime": "^7.12.5",
1241 + "@videojs/vhs-utils": "3.0.5",
1242 + "aes-decrypter": "3.1.3",
1243 + "global": "^4.4.0",
1244 + "m3u8-parser": "4.8.0",
1245 + "mpd-parser": "^0.22.1",
1246 + "mux.js": "6.0.1",
1247 + "video.js": "^6 || ^7"
1248 + },
1249 + "engines": {
1250 + "node": ">=8",
1251 + "npm": ">=5"
1252 + },
1253 + "peerDependencies": {
1254 + "video.js": "^6 || ^7"
1255 + }
1256 + },
1257 + "node_modules/@videojs/vhs-utils": {
1258 + "version": "3.0.5",
1259 + "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-3.0.5.tgz",
1260 + "integrity": "sha512-PKVgdo8/GReqdx512F+ombhS+Bzogiofy1LgAj4tN8PfdBx3HSS7V5WfJotKTqtOWGwVfSWsrYN/t09/DSryrw==",
1261 + "dependencies": {
1262 + "@babel/runtime": "^7.12.5",
1263 + "global": "^4.4.0",
1264 + "url-toolkit": "^2.2.1"
1265 + },
1266 + "engines": {
1267 + "node": ">=8",
1268 + "npm": ">=5"
1269 + }
1270 + },
1271 + "node_modules/@videojs/xhr": {
1272 + "version": "2.6.0",
1273 + "resolved": "https://registry.npmjs.org/@videojs/xhr/-/xhr-2.6.0.tgz",
1274 + "integrity": "sha512-7J361GiN1tXpm+gd0xz2QWr3xNWBE+rytvo8J3KuggFaLg+U37gZQ2BuPLcnkfGffy2e+ozY70RHC8jt7zjA6Q==",
1275 + "dependencies": {
1276 + "@babel/runtime": "^7.5.5",
1277 + "global": "~4.4.0",
1278 + "is-function": "^1.0.1"
1279 + }
1280 + },
1217 "node_modules/@vitejs/plugin-vue": { 1281 "node_modules/@vitejs/plugin-vue": {
1218 "version": "5.2.3", 1282 "version": "5.2.3",
1219 "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.3.tgz", 1283 "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.3.tgz",
...@@ -1429,6 +1493,14 @@ ...@@ -1429,6 +1493,14 @@
1429 "vue": "^3.5.0" 1493 "vue": "^3.5.0"
1430 } 1494 }
1431 }, 1495 },
1496 + "node_modules/@xmldom/xmldom": {
1497 + "version": "0.8.10",
1498 + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
1499 + "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==",
1500 + "engines": {
1501 + "node": ">=10.0.0"
1502 + }
1503 + },
1432 "node_modules/acorn": { 1504 "node_modules/acorn": {
1433 "version": "8.14.1", 1505 "version": "8.14.1",
1434 "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", 1506 "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
...@@ -1441,6 +1513,17 @@ ...@@ -1441,6 +1513,17 @@
1441 "node": ">=0.4.0" 1513 "node": ">=0.4.0"
1442 } 1514 }
1443 }, 1515 },
1516 + "node_modules/aes-decrypter": {
1517 + "version": "3.1.3",
1518 + "resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.1.3.tgz",
1519 + "integrity": "sha512-VkG9g4BbhMBy+N5/XodDeV6F02chEk9IpgRTq/0bS80y4dzy79VH2Gtms02VXomf3HmyRe3yyJYkJ990ns+d6A==",
1520 + "dependencies": {
1521 + "@babel/runtime": "^7.12.5",
1522 + "@videojs/vhs-utils": "^3.0.5",
1523 + "global": "^4.4.0",
1524 + "pkcs7": "^1.0.4"
1525 + }
1526 + },
1444 "node_modules/ansi-regex": { 1527 "node_modules/ansi-regex": {
1445 "version": "6.1.0", 1528 "version": "6.1.0",
1446 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", 1529 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
...@@ -1855,6 +1938,11 @@ ...@@ -1855,6 +1938,11 @@
1855 "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", 1938 "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
1856 "dev": true 1939 "dev": true
1857 }, 1940 },
1941 + "node_modules/dom-walk": {
1942 + "version": "0.1.2",
1943 + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
1944 + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="
1945 + },
1858 "node_modules/dunder-proto": { 1946 "node_modules/dunder-proto": {
1859 "version": "1.0.1", 1947 "version": "1.0.1",
1860 "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", 1948 "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
...@@ -2229,6 +2317,15 @@ ...@@ -2229,6 +2317,15 @@
2229 "node": ">=10.13.0" 2317 "node": ">=10.13.0"
2230 } 2318 }
2231 }, 2319 },
2320 + "node_modules/global": {
2321 + "version": "4.4.0",
2322 + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz",
2323 + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==",
2324 + "dependencies": {
2325 + "min-document": "^2.19.0",
2326 + "process": "^0.11.10"
2327 + }
2328 + },
2232 "node_modules/globals": { 2329 "node_modules/globals": {
2233 "version": "11.12.0", 2330 "version": "11.12.0",
2234 "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", 2331 "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
...@@ -2289,6 +2386,11 @@ ...@@ -2289,6 +2386,11 @@
2289 "node": ">= 0.4" 2386 "node": ">= 0.4"
2290 } 2387 }
2291 }, 2388 },
2389 + "node_modules/individual": {
2390 + "version": "2.0.0",
2391 + "resolved": "https://registry.npmjs.org/individual/-/individual-2.0.0.tgz",
2392 + "integrity": "sha512-pWt8hBCqJsUWI/HtcfWod7+N9SgAqyPEaF7JQjwzjn5vGrpg6aQ5qeAFQ7dx//UH4J1O+7xqew+gCeeFt6xN/g=="
2393 + },
2292 "node_modules/is-binary-path": { 2394 "node_modules/is-binary-path": {
2293 "version": "2.1.0", 2395 "version": "2.1.0",
2294 "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 2396 "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
...@@ -2334,6 +2436,11 @@ ...@@ -2334,6 +2436,11 @@
2334 "node": ">=8" 2436 "node": ">=8"
2335 } 2437 }
2336 }, 2438 },
2439 + "node_modules/is-function": {
2440 + "version": "1.0.2",
2441 + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz",
2442 + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ=="
2443 + },
2337 "node_modules/is-glob": { 2444 "node_modules/is-glob": {
2338 "version": "4.0.3", 2445 "version": "4.0.3",
2339 "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 2446 "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
...@@ -2415,6 +2522,11 @@ ...@@ -2415,6 +2522,11 @@
2415 "node": ">=6" 2522 "node": ">=6"
2416 } 2523 }
2417 }, 2524 },
2525 + "node_modules/keycode": {
2526 + "version": "2.2.1",
2527 + "resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.1.tgz",
2528 + "integrity": "sha512-Rdgz9Hl9Iv4QKi8b0OlCRQEzp4AgVxyCtz5S/+VIHezDmrDhkp2N2TqBWOLz0/gbeREXOOiI9/4b8BY9uw2vFg=="
2529 + },
2418 "node_modules/lilconfig": { 2530 "node_modules/lilconfig": {
2419 "version": "3.1.3", 2531 "version": "3.1.3",
2420 "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", 2532 "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
...@@ -2459,6 +2571,16 @@ ...@@ -2459,6 +2571,16 @@
2459 "yallist": "^3.0.2" 2571 "yallist": "^3.0.2"
2460 } 2572 }
2461 }, 2573 },
2574 + "node_modules/m3u8-parser": {
2575 + "version": "4.8.0",
2576 + "resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.8.0.tgz",
2577 + "integrity": "sha512-UqA2a/Pw3liR6Df3gwxrqghCP17OpPlQj6RBPLYygf/ZSQ4MoSgvdvhvt35qV+3NaaA0FSZx93Ix+2brT1U7cA==",
2578 + "dependencies": {
2579 + "@babel/runtime": "^7.12.5",
2580 + "@videojs/vhs-utils": "^3.0.5",
2581 + "global": "^4.4.0"
2582 + }
2583 + },
2462 "node_modules/magic-string": { 2584 "node_modules/magic-string": {
2463 "version": "0.30.17", 2585 "version": "0.30.17",
2464 "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", 2586 "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
...@@ -2519,6 +2641,14 @@ ...@@ -2519,6 +2641,14 @@
2519 "node": ">= 0.6" 2641 "node": ">= 0.6"
2520 } 2642 }
2521 }, 2643 },
2644 + "node_modules/min-document": {
2645 + "version": "2.19.0",
2646 + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
2647 + "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==",
2648 + "dependencies": {
2649 + "dom-walk": "^0.1.0"
2650 + }
2651 + },
2522 "node_modules/minimatch": { 2652 "node_modules/minimatch": {
2523 "version": "9.0.5", 2653 "version": "9.0.5",
2524 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", 2654 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
...@@ -2572,6 +2702,20 @@ ...@@ -2572,6 +2702,20 @@
2572 "pathe": "^2.0.1" 2702 "pathe": "^2.0.1"
2573 } 2703 }
2574 }, 2704 },
2705 + "node_modules/mpd-parser": {
2706 + "version": "0.22.1",
2707 + "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.22.1.tgz",
2708 + "integrity": "sha512-fwBebvpyPUU8bOzvhX0VQZgSohncbgYwUyJJoTSNpmy7ccD2ryiCvM7oRkn/xQH5cv73/xU7rJSNCLjdGFor0Q==",
2709 + "dependencies": {
2710 + "@babel/runtime": "^7.12.5",
2711 + "@videojs/vhs-utils": "^3.0.5",
2712 + "@xmldom/xmldom": "^0.8.3",
2713 + "global": "^4.4.0"
2714 + },
2715 + "bin": {
2716 + "mpd-to-m3u8-json": "bin/parse.js"
2717 + }
2718 + },
2575 "node_modules/ms": { 2719 "node_modules/ms": {
2576 "version": "2.1.3", 2720 "version": "2.1.3",
2577 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 2721 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
...@@ -2583,6 +2727,22 @@ ...@@ -2583,6 +2727,22 @@
2583 "resolved": "https://registry.npmjs.org/mutation-observer/-/mutation-observer-1.0.3.tgz", 2727 "resolved": "https://registry.npmjs.org/mutation-observer/-/mutation-observer-1.0.3.tgz",
2584 "integrity": "sha512-M/O/4rF2h776hV7qGMZUH3utZLO/jK7p8rnNgGkjKUw8zCGjRQPxB8z6+5l8+VjRUQ3dNYu4vjqXYLr+U8ZVNA==" 2728 "integrity": "sha512-M/O/4rF2h776hV7qGMZUH3utZLO/jK7p8rnNgGkjKUw8zCGjRQPxB8z6+5l8+VjRUQ3dNYu4vjqXYLr+U8ZVNA=="
2585 }, 2729 },
2730 + "node_modules/mux.js": {
2731 + "version": "6.0.1",
2732 + "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-6.0.1.tgz",
2733 + "integrity": "sha512-22CHb59rH8pWGcPGW5Og7JngJ9s+z4XuSlYvnxhLuc58cA1WqGDQPzuG8I+sPm1/p0CdgpzVTaKW408k5DNn8w==",
2734 + "dependencies": {
2735 + "@babel/runtime": "^7.11.2",
2736 + "global": "^4.4.0"
2737 + },
2738 + "bin": {
2739 + "muxjs-transmux": "bin/transmux.js"
2740 + },
2741 + "engines": {
2742 + "node": ">=8",
2743 + "npm": ">=5"
2744 + }
2745 + },
2586 "node_modules/mz": { 2746 "node_modules/mz": {
2587 "version": "2.7.0", 2747 "version": "2.7.0",
2588 "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", 2748 "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
...@@ -2749,6 +2909,17 @@ ...@@ -2749,6 +2909,17 @@
2749 "node": ">= 6" 2909 "node": ">= 6"
2750 } 2910 }
2751 }, 2911 },
2912 + "node_modules/pkcs7": {
2913 + "version": "1.0.4",
2914 + "resolved": "https://registry.npmjs.org/pkcs7/-/pkcs7-1.0.4.tgz",
2915 + "integrity": "sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ==",
2916 + "dependencies": {
2917 + "@babel/runtime": "^7.5.5"
2918 + },
2919 + "bin": {
2920 + "pkcs7": "bin/cli.js"
2921 + }
2922 + },
2752 "node_modules/pkg-types": { 2923 "node_modules/pkg-types": {
2753 "version": "2.1.0", 2924 "version": "2.1.0",
2754 "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.1.0.tgz", 2925 "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.1.0.tgz",
...@@ -2902,6 +3073,14 @@ ...@@ -2902,6 +3073,14 @@
2902 "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", 3073 "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
2903 "dev": true 3074 "dev": true
2904 }, 3075 },
3076 + "node_modules/process": {
3077 + "version": "0.11.10",
3078 + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
3079 + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
3080 + "engines": {
3081 + "node": ">= 0.6.0"
3082 + }
3083 + },
2905 "node_modules/proxy-from-env": { 3084 "node_modules/proxy-from-env": {
2906 "version": "1.1.0", 3085 "version": "1.1.0",
2907 "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", 3086 "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
...@@ -3076,6 +3255,22 @@ ...@@ -3076,6 +3255,22 @@
3076 "queue-microtask": "^1.2.2" 3255 "queue-microtask": "^1.2.2"
3077 } 3256 }
3078 }, 3257 },
3258 + "node_modules/rust-result": {
3259 + "version": "1.0.0",
3260 + "resolved": "https://registry.npmjs.org/rust-result/-/rust-result-1.0.0.tgz",
3261 + "integrity": "sha512-6cJzSBU+J/RJCF063onnQf0cDUOHs9uZI1oroSGnHOph+CQTIJ5Pp2hK5kEQq1+7yE/EEWfulSNXAQ2jikPthA==",
3262 + "dependencies": {
3263 + "individual": "^2.0.0"
3264 + }
3265 + },
3266 + "node_modules/safe-json-parse": {
3267 + "version": "4.0.0",
3268 + "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-4.0.0.tgz",
3269 + "integrity": "sha512-RjZPPHugjK0TOzFrLZ8inw44s9bKox99/0AZW9o/BEQVrJfhI+fIHMErnPyRa89/yRXUUr93q+tiN6zhoVV4wQ==",
3270 + "dependencies": {
3271 + "rust-result": "^1.0.0"
3272 + }
3273 + },
3079 "node_modules/scule": { 3274 "node_modules/scule": {
3080 "version": "1.3.0", 3275 "version": "1.3.0",
3081 "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz", 3276 "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz",
...@@ -3707,6 +3902,11 @@ ...@@ -3707,6 +3902,11 @@
3707 "browserslist": ">= 4.21.0" 3902 "browserslist": ">= 4.21.0"
3708 } 3903 }
3709 }, 3904 },
3905 + "node_modules/url-toolkit": {
3906 + "version": "2.2.5",
3907 + "resolved": "https://registry.npmjs.org/url-toolkit/-/url-toolkit-2.2.5.tgz",
3908 + "integrity": "sha512-mtN6xk+Nac+oyJ/PrI7tzfmomRVNFIWKUbG8jdYFt52hxbiReFAXIjYskvu64/dvuW71IcB7lV8l0HvZMac6Jg=="
3909 + },
3710 "node_modules/util-deprecate": { 3910 "node_modules/util-deprecate": {
3711 "version": "1.0.2", 3911 "version": "1.0.2",
3712 "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 3912 "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
...@@ -3737,6 +3937,39 @@ ...@@ -3737,6 +3937,39 @@
3737 "mutation-observer": "^1.0.3" 3937 "mutation-observer": "^1.0.3"
3738 } 3938 }
3739 }, 3939 },
3940 + "node_modules/video.js": {
3941 + "version": "7.21.7",
3942 + "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.21.7.tgz",
3943 + "integrity": "sha512-T2s3WFAht7Zjr2OSJamND9x9Dn2O+Z5WuHGdh8jI5SYh5mkMdVTQ7vSRmA5PYpjXJ2ycch6jpMjkJEIEU2xxqw==",
3944 + "dependencies": {
3945 + "@babel/runtime": "^7.12.5",
3946 + "@videojs/http-streaming": "2.16.3",
3947 + "@videojs/vhs-utils": "^3.0.4",
3948 + "@videojs/xhr": "2.6.0",
3949 + "aes-decrypter": "3.1.3",
3950 + "global": "^4.4.0",
3951 + "keycode": "^2.2.0",
3952 + "m3u8-parser": "4.8.0",
3953 + "mpd-parser": "0.22.1",
3954 + "mux.js": "6.0.1",
3955 + "safe-json-parse": "4.0.0",
3956 + "videojs-font": "3.2.0",
3957 + "videojs-vtt.js": "^0.15.5"
3958 + }
3959 + },
3960 + "node_modules/videojs-font": {
3961 + "version": "3.2.0",
3962 + "resolved": "https://registry.npmjs.org/videojs-font/-/videojs-font-3.2.0.tgz",
3963 + "integrity": "sha512-g8vHMKK2/JGorSfqAZQUmYYNnXmfec4MLhwtEFS+mMs2IDY398GLysy6BH6K+aS1KMNu/xWZ8Sue/X/mdQPliA=="
3964 + },
3965 + "node_modules/videojs-vtt.js": {
3966 + "version": "0.15.5",
3967 + "resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.15.5.tgz",
3968 + "integrity": "sha512-yZbBxvA7QMYn15Lr/ZfhhLPrNpI/RmCSCqgIff57GC2gIrV5YfyzLfLyZMj0NnZSAz8syB4N0nHXpZg9MyrMOQ==",
3969 + "dependencies": {
3970 + "global": "^4.3.1"
3971 + }
3972 + },
3740 "node_modules/vite": { 3973 "node_modules/vite": {
3741 "version": "6.2.2", 3974 "version": "6.2.2",
3742 "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.2.tgz", 3975 "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.2.tgz",
......
...@@ -17,10 +17,12 @@ ...@@ -17,10 +17,12 @@
17 "dependencies": { 17 "dependencies": {
18 "@heroicons/vue": "^2.2.0", 18 "@heroicons/vue": "^2.2.0",
19 "@vant/use": "^1.6.0", 19 "@vant/use": "^1.6.0",
20 + "@videojs-player/vue": "^1.0.0",
20 "dayjs": "^1.11.13", 21 "dayjs": "^1.11.13",
21 "swiper": "^11.2.6", 22 "swiper": "^11.2.6",
22 "vant": "^4.9.18", 23 "vant": "^4.9.18",
23 "vconsole": "^3.15.1", 24 "vconsole": "^3.15.1",
25 + "video.js": "^7.21.7",
24 "vue": "^3.5.13", 26 "vue": "^3.5.13",
25 "vue-router": "^4.5.0", 27 "vue-router": "^4.5.0",
26 "weixin-js-sdk": "^1.6.5" 28 "weixin-js-sdk": "^1.6.5"
......
...@@ -39,5 +39,6 @@ declare module 'vue' { ...@@ -39,5 +39,6 @@ declare module 'vue' {
39 VanTab: typeof import('vant/es')['Tab'] 39 VanTab: typeof import('vant/es')['Tab']
40 VanTabs: typeof import('vant/es')['Tabs'] 40 VanTabs: typeof import('vant/es')['Tabs']
41 VanUploader: typeof import('vant/es')['Uploader'] 41 VanUploader: typeof import('vant/es')['Uploader']
42 + VideoPlayer: typeof import('./components/ui/VideoPlayer.vue')['default']
42 } 43 }
43 } 44 }
......
1 +<!--
2 + * @Date: 2025-03-24 15:13:35
3 + * @LastEditors: hookehuyr hookehuyr@gmail.com
4 + * @LastEditTime: 2025-03-24 15:13:37
5 + * @FilePath: /mlaj/src/components/ui/VideoPlayer.vue
6 + * @Description: 文件描述
7 +-->
8 +<template>
9 + <div class="video-player-container">
10 + <video
11 + ref="videoRef"
12 + class="video-js vjs-default-skin"
13 + controls
14 + preload="auto"
15 + width="100%"
16 + height="100%"
17 + >
18 + <source :src="videoUrl" type="video/mp4" />
19 + </video>
20 + </div>
21 +</template>
22 +
23 +<script setup>
24 +import { ref, onMounted, onBeforeUnmount, defineProps, defineEmits } from 'vue'
25 +import videojs from 'video.js'
26 +import 'video.js/dist/video-js.css'
27 +
28 +const props = defineProps({
29 + videoUrl: {
30 + type: String,
31 + required: true
32 + }
33 +})
34 +
35 +const emit = defineEmits(['onPlay', 'onPause'])
36 +const videoRef = ref(null)
37 +let player = null
38 +
39 +onMounted(() => {
40 + player = videojs(videoRef.value, {
41 + fluid: true,
42 + controls: true,
43 + preload: 'auto',
44 + responsive: true
45 + })
46 +
47 + player.on('play', () => {
48 + emit('onPlay')
49 + })
50 +
51 + player.on('pause', () => {
52 + emit('onPause')
53 + })
54 +})
55 +
56 +onBeforeUnmount(() => {
57 + if (player) {
58 + player.dispose()
59 + }
60 +})
61 +
62 +defineExpose({
63 + pause() {
64 + if (player) {
65 + player.pause()
66 + }
67 + }
68 +})
69 +</script>
70 +
71 +<style scoped>
72 +.video-player-container {
73 + width: 100%;
74 + height: 100%;
75 + position: relative;
76 +}
77 +</style>
1 <!-- 1 <!--
2 * @Date: 2025-03-20 19:55:21 2 * @Date: 2025-03-20 19:55:21
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-03-21 09:35:57 4 + * @LastEditTime: 2025-03-24 15:14:00
5 * @FilePath: /mlaj/src/views/HomePage.vue 5 * @FilePath: /mlaj/src/views/HomePage.vue
6 * @Description: 文件描述 6 * @Description: 文件描述
7 --> 7 -->
...@@ -443,30 +443,41 @@ ...@@ -443,30 +443,41 @@
443 <div class="space-y-4"> 443 <div class="space-y-4">
444 <div 444 <div
445 v-for="(item, index) in [ 445 v-for="(item, index) in [
446 - { title: '亲子沟通的艺术', views: '1.2万', duration: '08:25', image: 'https://cdn.ipadbiz.cn/mlaj/images/video-1.jpg' }, 446 + { title: '亲子沟通的艺术', views: '1.2万', duration: '08:25', image: 'https://cdn.ipadbiz.cn/mlaj/images/video-1.jpg', video_url: 'http://vjs.zencdn.net/v/oceans.mp4' },
447 - { title: '如何做好家庭教育', views: '8千', duration: '12:40', image: 'https://cdn.ipadbiz.cn/mlaj/images/video-2.jpg' }, 447 + { title: '如何做好家庭教育', views: '8千', duration: '12:40', image: 'https://cdn.ipadbiz.cn/mlaj/images/video-2.jpg', video_url: 'http://vjs.zencdn.net/v/oceans.mp4' },
448 - { title: '孩子营养餐制作指南', views: '5千', duration: '15:18', image: 'https://cdn.ipadbiz.cn/mlaj/images/video-3.jpg' } 448 + { title: '孩子营养餐制作指南', views: '5千', duration: '15:18', image: 'https://cdn.ipadbiz.cn/mlaj/images/video-3.jpg', video_url: 'http://vjs.zencdn.net/v/oceans.mp4' }
449 ]" 449 ]"
450 :key="index" 450 :key="index"
451 class="relative rounded-xl overflow-hidden shadow-md h-48" 451 class="relative rounded-xl overflow-hidden shadow-md h-48"
452 > 452 >
453 - <img 453 + <template v-if="activeVideoIndex !== index">
454 - :src="item.image" 454 + <img
455 - :alt="item.title" 455 + :src="item.image"
456 - class="w-full h-full object-cover" 456 + :alt="item.title"
457 - @error="handleImageError" 457 + class="w-full h-full object-cover"
458 - /> 458 + @error="handleImageError"
459 - <div class="absolute inset-0 bg-gradient-to-b from-transparent to-black/70 flex flex-col justify-end p-4"> 459 + />
460 - <h4 class="text-white font-medium mb-1">{{ item.title }}</h4> 460 + <div class="absolute inset-0 bg-gradient-to-b from-transparent to-black/70 flex flex-col justify-end p-4">
461 - <div class="flex justify-between items-center"> 461 + <h4 class="text-white font-medium mb-1">{{ item.title }}</h4>
462 - <p class="text-white/80 text-xs">{{ item.views }}次播放 · {{ item.duration }}</p> 462 + <div class="flex justify-between items-center">
463 - <button class="bg-white/20 backdrop-blur-sm p-2 rounded-full"> 463 + <p class="text-white/80 text-xs">{{ item.views }}次播放 · {{ item.duration }}</p>
464 - <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-white" viewBox="0 0 20 20" fill="currentColor"> 464 + <button
465 - <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z" clip-rule="evenodd" /> 465 + class="bg-white/20 backdrop-blur-sm p-2 rounded-full"
466 - </svg> 466 + @click="playVideo(index, item.video_url)"
467 - </button> 467 + >
468 + <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-white" viewBox="0 0 20 20" fill="currentColor">
469 + <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z" clip-rule="evenodd" />
470 + </svg>
471 + </button>
472 + </div>
468 </div> 473 </div>
469 - </div> 474 + </template>
475 + <VideoPlayer
476 + v-else
477 + :video-url="item.video_url"
478 + ref="videoPlayerRefs"
479 + @onPlay="handleVideoPlay(index)"
480 + />
470 </div> 481 </div>
471 </div> 482 </div>
472 </div> 483 </div>
...@@ -486,12 +497,29 @@ import CourseCard from '@/components/ui/CourseCard.vue' ...@@ -486,12 +497,29 @@ import CourseCard from '@/components/ui/CourseCard.vue'
486 import LiveStreamCard from '@/components/ui/LiveStreamCard.vue' 497 import LiveStreamCard from '@/components/ui/LiveStreamCard.vue'
487 import ActivityCard from '@/components/ui/ActivityCard.vue' 498 import ActivityCard from '@/components/ui/ActivityCard.vue'
488 import SummerCampCard from '@/components/ui/SummerCampCard.vue' 499 import SummerCampCard from '@/components/ui/SummerCampCard.vue'
500 +import VideoPlayer from '@/components/ui/VideoPlayer.vue'
489 import { courses, liveStreams, activities, checkInTypes, userRecommendations } from '@/utils/mockData' 501 import { courses, liveStreams, activities, checkInTypes, userRecommendations } from '@/utils/mockData'
490 import { useTitle } from '@vueuse/core' 502 import { useTitle } from '@vueuse/core'
491 import { useAuth } from '@/contexts/auth' 503 import { useAuth } from '@/contexts/auth'
492 import { showToast } from 'vant' 504 import { showToast } from 'vant'
493 import 'vant/lib/toast/style' 505 import 'vant/lib/toast/style'
494 506
507 +const activeVideoIndex = ref(null);
508 +const videoPlayerRefs = ref([]);
509 +
510 +const playVideo = (index, videoUrl) => {
511 + if (activeVideoIndex.value !== null && activeVideoIndex.value !== index) {
512 + videoPlayerRefs.value[activeVideoIndex.value]?.pause();
513 + }
514 + activeVideoIndex.value = index;
515 +};
516 +
517 +const handleVideoPlay = (index) => {
518 + if (activeVideoIndex.value !== null && activeVideoIndex.value !== index) {
519 + videoPlayerRefs.value[activeVideoIndex.value]?.pause();
520 + }
521 +};
522 +
495 const $route = useRoute() 523 const $route = useRoute()
496 const $router = useRouter() 524 const $router = useRouter()
497 useTitle($route.meta.title) 525 useTitle($route.meta.title)
......