hookehuyr

feat(视频上传): 新增视频上传功能及相关组件

新增视频上传页面、弹窗组件及视频播放器自动播放配置。添加相关依赖以支持视频上传功能。
...@@ -9,6 +9,10 @@ ...@@ -9,6 +9,10 @@
9 "version": "0.0.0", 9 "version": "0.0.0",
10 "dependencies": { 10 "dependencies": {
11 "@heroicons/vue": "^2.2.0", 11 "@heroicons/vue": "^2.2.0",
12 + "@uppy/core": "^4.4.3",
13 + "@uppy/dashboard": "^4.3.2",
14 + "@uppy/vue": "^2.1.1",
15 + "@uppy/xhr-upload": "^4.3.3",
12 "@vant/touch-emulator": "^1.4.0", 16 "@vant/touch-emulator": "^1.4.0",
13 "@vant/use": "^1.6.0", 17 "@vant/use": "^1.6.0",
14 "@videojs-player/vue": "^1.0.0", 18 "@videojs-player/vue": "^1.0.0",
...@@ -1192,12 +1196,22 @@ ...@@ -1192,12 +1196,22 @@
1192 "win32" 1196 "win32"
1193 ] 1197 ]
1194 }, 1198 },
1199 + "node_modules/@transloadit/prettier-bytes": {
1200 + "version": "0.3.5",
1201 + "resolved": "https://registry.npmjs.org/@transloadit/prettier-bytes/-/prettier-bytes-0.3.5.tgz",
1202 + "integrity": "sha512-xF4A3d/ZyX2LJWeQZREZQw+qFX4TGQ8bGVP97OLRt6sPO6T0TNHBFTuRHOJh7RNmYOBmQ9MHxpolD9bXihpuVA=="
1203 + },
1195 "node_modules/@types/estree": { 1204 "node_modules/@types/estree": {
1196 "version": "1.0.6", 1205 "version": "1.0.6",
1197 "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", 1206 "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
1198 "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", 1207 "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
1199 "dev": true 1208 "dev": true
1200 }, 1209 },
1210 + "node_modules/@types/retry": {
1211 + "version": "0.12.2",
1212 + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz",
1213 + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow=="
1214 + },
1201 "node_modules/@types/video.js": { 1215 "node_modules/@types/video.js": {
1202 "version": "7.3.58", 1216 "version": "7.3.58",
1203 "resolved": "https://registry.npmjs.org/@types/video.js/-/video.js-7.3.58.tgz", 1217 "resolved": "https://registry.npmjs.org/@types/video.js/-/video.js-7.3.58.tgz",
...@@ -1210,6 +1224,220 @@ ...@@ -1210,6 +1224,220 @@
1210 "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", 1224 "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==",
1211 "dev": true 1225 "dev": true
1212 }, 1226 },
1227 + "node_modules/@uppy/companion-client": {
1228 + "version": "4.4.1",
1229 + "resolved": "https://registry.npmjs.org/@uppy/companion-client/-/companion-client-4.4.1.tgz",
1230 + "integrity": "sha512-ardMacShsfzaIbqHEH48YlpzWZkBj1qhAj0Dvn3r31p9d0HA5xFUvAdLYrZ6ezKvZ0RcDbf0SB5qCrQMkjscXQ==",
1231 + "dependencies": {
1232 + "@uppy/utils": "^6.1.1",
1233 + "namespace-emitter": "^2.0.1",
1234 + "p-retry": "^6.1.0"
1235 + },
1236 + "peerDependencies": {
1237 + "@uppy/core": "^4.4.1"
1238 + }
1239 + },
1240 + "node_modules/@uppy/core": {
1241 + "version": "4.4.3",
1242 + "resolved": "https://registry.npmjs.org/@uppy/core/-/core-4.4.3.tgz",
1243 + "integrity": "sha512-Ma/v9+u0xYoxFcTajBpe0TUHI0Vjw2IKgB0AUNevhgFsBRgA03nL5n8Fac8TrC0QjPkYu7h0n2xf2EgzvyxAQA==",
1244 + "dependencies": {
1245 + "@transloadit/prettier-bytes": "^0.3.4",
1246 + "@uppy/store-default": "^4.2.0",
1247 + "@uppy/utils": "^6.1.2",
1248 + "lodash": "^4.17.21",
1249 + "mime-match": "^1.0.2",
1250 + "namespace-emitter": "^2.0.1",
1251 + "nanoid": "^5.0.9",
1252 + "preact": "^10.5.13"
1253 + }
1254 + },
1255 + "node_modules/@uppy/core/node_modules/nanoid": {
1256 + "version": "5.1.5",
1257 + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.5.tgz",
1258 + "integrity": "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==",
1259 + "funding": [
1260 + {
1261 + "type": "github",
1262 + "url": "https://github.com/sponsors/ai"
1263 + }
1264 + ],
1265 + "bin": {
1266 + "nanoid": "bin/nanoid.js"
1267 + },
1268 + "engines": {
1269 + "node": "^18 || >=20"
1270 + }
1271 + },
1272 + "node_modules/@uppy/dashboard": {
1273 + "version": "4.3.2",
1274 + "resolved": "https://registry.npmjs.org/@uppy/dashboard/-/dashboard-4.3.2.tgz",
1275 + "integrity": "sha512-6cikgcY/TMy+Fq/v03QI1BNocfm1kOxii3kuUaxnz1SFGeuZ/55+C7KKL7SP/IdeoVwH7KV+550HThT0uwIQEw==",
1276 + "dependencies": {
1277 + "@transloadit/prettier-bytes": "^0.3.4",
1278 + "@uppy/informer": "^4.2.1",
1279 + "@uppy/provider-views": "^4.4.2",
1280 + "@uppy/status-bar": "^4.1.2",
1281 + "@uppy/thumbnail-generator": "^4.1.1",
1282 + "@uppy/utils": "^6.1.2",
1283 + "classnames": "^2.2.6",
1284 + "lodash": "^4.17.21",
1285 + "memoize-one": "^6.0.0",
1286 + "nanoid": "^5.0.9",
1287 + "preact": "^10.5.13",
1288 + "shallow-equal": "^3.0.0"
1289 + },
1290 + "peerDependencies": {
1291 + "@uppy/core": "^4.4.2"
1292 + }
1293 + },
1294 + "node_modules/@uppy/dashboard/node_modules/nanoid": {
1295 + "version": "5.1.5",
1296 + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.5.tgz",
1297 + "integrity": "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==",
1298 + "funding": [
1299 + {
1300 + "type": "github",
1301 + "url": "https://github.com/sponsors/ai"
1302 + }
1303 + ],
1304 + "bin": {
1305 + "nanoid": "bin/nanoid.js"
1306 + },
1307 + "engines": {
1308 + "node": "^18 || >=20"
1309 + }
1310 + },
1311 + "node_modules/@uppy/informer": {
1312 + "version": "4.2.1",
1313 + "resolved": "https://registry.npmjs.org/@uppy/informer/-/informer-4.2.1.tgz",
1314 + "integrity": "sha512-0en8Py47pl6RMDrgUfqFoF807W5kK5AKVJNT1SkTsLiGg5anmTIMuvmNG3k6LN4cn9P/rKyEHSdGcoBBUj9u7Q==",
1315 + "dependencies": {
1316 + "@uppy/utils": "^6.1.1",
1317 + "preact": "^10.5.13"
1318 + },
1319 + "peerDependencies": {
1320 + "@uppy/core": "^4.4.1"
1321 + }
1322 + },
1323 + "node_modules/@uppy/provider-views": {
1324 + "version": "4.4.2",
1325 + "resolved": "https://registry.npmjs.org/@uppy/provider-views/-/provider-views-4.4.2.tgz",
1326 + "integrity": "sha512-YGrPJuydrksmMCjvo7Ty7/lDLNo/Y8zsOgWgWmVbXB0V5aRvqY49LeKY8HDlOXclKmn6dl5CeQFf7p46txRNGQ==",
1327 + "dependencies": {
1328 + "@uppy/utils": "^6.1.2",
1329 + "classnames": "^2.2.6",
1330 + "nanoid": "^5.0.9",
1331 + "p-queue": "^8.0.0",
1332 + "preact": "^10.5.13"
1333 + },
1334 + "peerDependencies": {
1335 + "@uppy/core": "^4.4.2"
1336 + }
1337 + },
1338 + "node_modules/@uppy/provider-views/node_modules/nanoid": {
1339 + "version": "5.1.5",
1340 + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.5.tgz",
1341 + "integrity": "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==",
1342 + "funding": [
1343 + {
1344 + "type": "github",
1345 + "url": "https://github.com/sponsors/ai"
1346 + }
1347 + ],
1348 + "bin": {
1349 + "nanoid": "bin/nanoid.js"
1350 + },
1351 + "engines": {
1352 + "node": "^18 || >=20"
1353 + }
1354 + },
1355 + "node_modules/@uppy/status-bar": {
1356 + "version": "4.1.2",
1357 + "resolved": "https://registry.npmjs.org/@uppy/status-bar/-/status-bar-4.1.2.tgz",
1358 + "integrity": "sha512-Z2fDXItoE940uMo3kwdDo4ZFPjTk5GY6y/C/G5+tSl6nL/IaDtWo5iVbAKHIH4s9SIRwCBgllEhxbmEPhuK7eA==",
1359 + "dependencies": {
1360 + "@transloadit/prettier-bytes": "^0.3.4",
1361 + "@uppy/utils": "^6.1.2",
1362 + "classnames": "^2.2.6",
1363 + "preact": "^10.5.13"
1364 + },
1365 + "peerDependencies": {
1366 + "@uppy/core": "^4.4.2"
1367 + }
1368 + },
1369 + "node_modules/@uppy/store-default": {
1370 + "version": "4.2.0",
1371 + "resolved": "https://registry.npmjs.org/@uppy/store-default/-/store-default-4.2.0.tgz",
1372 + "integrity": "sha512-PieFVa8yTvRHIqsNKfpO/yaJw5Ae/hT7uT58ryw7gvCBY5bHrNWxH5N0XFe8PFHMpLpLn8v3UXGx9ib9QkB6+Q=="
1373 + },
1374 + "node_modules/@uppy/thumbnail-generator": {
1375 + "version": "4.1.1",
1376 + "resolved": "https://registry.npmjs.org/@uppy/thumbnail-generator/-/thumbnail-generator-4.1.1.tgz",
1377 + "integrity": "sha512-65znkGNgVTbVte51IKOhgxOpHGSwYj9Qik2jF2ZBocMbhBY4gPkWFwqMrKQBfddA9KbUa4jVe1psxhAQTzYgiA==",
1378 + "dependencies": {
1379 + "@uppy/utils": "^6.1.1",
1380 + "exifr": "^7.0.0"
1381 + },
1382 + "peerDependencies": {
1383 + "@uppy/core": "^4.4.1"
1384 + }
1385 + },
1386 + "node_modules/@uppy/utils": {
1387 + "version": "6.1.2",
1388 + "resolved": "https://registry.npmjs.org/@uppy/utils/-/utils-6.1.2.tgz",
1389 + "integrity": "sha512-PCrw6v51M6p3hlrlB2INmcocen4Dyjun1SobjVZRBkg4wutQE8ihZfSrH5ZE8UXFelufhtO16wlaZMi0EHk84w==",
1390 + "dependencies": {
1391 + "lodash": "^4.17.21",
1392 + "preact": "^10.5.13"
1393 + }
1394 + },
1395 + "node_modules/@uppy/vue": {
1396 + "version": "2.1.1",
1397 + "resolved": "https://registry.npmjs.org/@uppy/vue/-/vue-2.1.1.tgz",
1398 + "integrity": "sha512-svmkqO3QObuPOyVE0ttTFcwjrjzsxiDGgqau0tuV27FNO0/50GGzrJcBOy+P7kkZhQ23qEBltScQzOc75s7uUQ==",
1399 + "dependencies": {
1400 + "shallow-equal": "^3.0.0"
1401 + },
1402 + "peerDependencies": {
1403 + "@uppy/core": "^4.4.1",
1404 + "@uppy/dashboard": "^4.3.1",
1405 + "@uppy/drag-drop": "^4.1.1",
1406 + "@uppy/file-input": "^4.1.1",
1407 + "@uppy/progress-bar": "^4.2.1",
1408 + "@uppy/status-bar": "^4.1.1",
1409 + "vue": ">=3.0.0"
1410 + },
1411 + "peerDependenciesMeta": {
1412 + "@uppy/dashboard": {
1413 + "optional": true
1414 + },
1415 + "@uppy/drag-drop": {
1416 + "optional": true
1417 + },
1418 + "@uppy/file-input": {
1419 + "optional": true
1420 + },
1421 + "@uppy/progress-bar": {
1422 + "optional": true
1423 + },
1424 + "@uppy/status-bar": {
1425 + "optional": true
1426 + }
1427 + }
1428 + },
1429 + "node_modules/@uppy/xhr-upload": {
1430 + "version": "4.3.3",
1431 + "resolved": "https://registry.npmjs.org/@uppy/xhr-upload/-/xhr-upload-4.3.3.tgz",
1432 + "integrity": "sha512-I7RVppwTvLRlVfoW5piMxcZKzWF42E6CwYFQ42d2LzizrkG4tVLQkQrTZlw85za3nhcSrX3o/d1eNx3pzLmsdw==",
1433 + "dependencies": {
1434 + "@uppy/companion-client": "^4.4.1",
1435 + "@uppy/utils": "^6.1.2"
1436 + },
1437 + "peerDependencies": {
1438 + "@uppy/core": "^4.4.2"
1439 + }
1440 + },
1213 "node_modules/@vant/popperjs": { 1441 "node_modules/@vant/popperjs": {
1214 "version": "1.3.0", 1442 "version": "1.3.0",
1215 "resolved": "https://registry.npmjs.org/@vant/popperjs/-/popperjs-1.3.0.tgz", 1443 "resolved": "https://registry.npmjs.org/@vant/popperjs/-/popperjs-1.3.0.tgz",
...@@ -1798,6 +2026,11 @@ ...@@ -1798,6 +2026,11 @@
1798 "node": ">= 6" 2026 "node": ">= 6"
1799 } 2027 }
1800 }, 2028 },
2029 + "node_modules/classnames": {
2030 + "version": "2.5.1",
2031 + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
2032 + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="
2033 + },
1801 "node_modules/color-convert": { 2034 "node_modules/color-convert": {
1802 "version": "2.0.1", 2035 "version": "2.0.1",
1803 "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 2036 "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
...@@ -2103,6 +2336,16 @@ ...@@ -2103,6 +2336,16 @@
2103 "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 2336 "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
2104 "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" 2337 "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
2105 }, 2338 },
2339 + "node_modules/eventemitter3": {
2340 + "version": "5.0.1",
2341 + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
2342 + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="
2343 + },
2344 + "node_modules/exifr": {
2345 + "version": "7.1.3",
2346 + "resolved": "https://registry.npmjs.org/exifr/-/exifr-7.1.3.tgz",
2347 + "integrity": "sha512-g/aje2noHivrRSLbAUtBPWFbxKdKhgj/xr1vATDdUXPOFYJlQ62Ft0oy+72V6XLIpDJfHs6gXLbBLAolqOXYRw=="
2348 + },
2106 "node_modules/exsolve": { 2349 "node_modules/exsolve": {
2107 "version": "1.0.4", 2350 "version": "1.0.4",
2108 "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.4.tgz", 2351 "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.4.tgz",
...@@ -2459,6 +2702,17 @@ ...@@ -2459,6 +2702,17 @@
2459 "node": ">=0.10.0" 2702 "node": ">=0.10.0"
2460 } 2703 }
2461 }, 2704 },
2705 + "node_modules/is-network-error": {
2706 + "version": "1.1.0",
2707 + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz",
2708 + "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==",
2709 + "engines": {
2710 + "node": ">=16"
2711 + },
2712 + "funding": {
2713 + "url": "https://github.com/sponsors/sindresorhus"
2714 + }
2715 + },
2462 "node_modules/is-number": { 2716 "node_modules/is-number": {
2463 "version": "7.0.0", 2717 "version": "7.0.0",
2464 "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 2718 "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
...@@ -2568,6 +2822,11 @@ ...@@ -2568,6 +2822,11 @@
2568 "url": "https://github.com/sponsors/antfu" 2822 "url": "https://github.com/sponsors/antfu"
2569 } 2823 }
2570 }, 2824 },
2825 + "node_modules/lodash": {
2826 + "version": "4.17.21",
2827 + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
2828 + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
2829 + },
2571 "node_modules/lru-cache": { 2830 "node_modules/lru-cache": {
2572 "version": "5.1.1", 2831 "version": "5.1.1",
2573 "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", 2832 "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
...@@ -2604,6 +2863,11 @@ ...@@ -2604,6 +2863,11 @@
2604 "node": ">= 0.4" 2863 "node": ">= 0.4"
2605 } 2864 }
2606 }, 2865 },
2866 + "node_modules/memoize-one": {
2867 + "version": "6.0.0",
2868 + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
2869 + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
2870 + },
2607 "node_modules/merge2": { 2871 "node_modules/merge2": {
2608 "version": "1.4.1", 2872 "version": "1.4.1",
2609 "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 2873 "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
...@@ -2635,6 +2899,14 @@ ...@@ -2635,6 +2899,14 @@
2635 "node": ">= 0.6" 2899 "node": ">= 0.6"
2636 } 2900 }
2637 }, 2901 },
2902 + "node_modules/mime-match": {
2903 + "version": "1.0.2",
2904 + "resolved": "https://registry.npmjs.org/mime-match/-/mime-match-1.0.2.tgz",
2905 + "integrity": "sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==",
2906 + "dependencies": {
2907 + "wildcard": "^1.1.0"
2908 + }
2909 + },
2638 "node_modules/mime-types": { 2910 "node_modules/mime-types": {
2639 "version": "2.1.35", 2911 "version": "2.1.35",
2640 "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 2912 "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
...@@ -2760,6 +3032,11 @@ ...@@ -2760,6 +3032,11 @@
2760 "thenify-all": "^1.0.0" 3032 "thenify-all": "^1.0.0"
2761 } 3033 }
2762 }, 3034 },
3035 + "node_modules/namespace-emitter": {
3036 + "version": "2.0.1",
3037 + "resolved": "https://registry.npmjs.org/namespace-emitter/-/namespace-emitter-2.0.1.tgz",
3038 + "integrity": "sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g=="
3039 + },
2763 "node_modules/nanoid": { 3040 "node_modules/nanoid": {
2764 "version": "3.3.11", 3041 "version": "3.3.11",
2765 "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", 3042 "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
...@@ -2831,6 +3108,48 @@ ...@@ -2831,6 +3108,48 @@
2831 "url": "https://github.com/sponsors/ljharb" 3108 "url": "https://github.com/sponsors/ljharb"
2832 } 3109 }
2833 }, 3110 },
3111 + "node_modules/p-queue": {
3112 + "version": "8.1.0",
3113 + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-8.1.0.tgz",
3114 + "integrity": "sha512-mxLDbbGIBEXTJL0zEx8JIylaj3xQ7Z/7eEVjcF9fJX4DBiH9oqe+oahYnlKKxm0Ci9TlWTyhSHgygxMxjIB2jw==",
3115 + "dependencies": {
3116 + "eventemitter3": "^5.0.1",
3117 + "p-timeout": "^6.1.2"
3118 + },
3119 + "engines": {
3120 + "node": ">=18"
3121 + },
3122 + "funding": {
3123 + "url": "https://github.com/sponsors/sindresorhus"
3124 + }
3125 + },
3126 + "node_modules/p-retry": {
3127 + "version": "6.2.1",
3128 + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz",
3129 + "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==",
3130 + "dependencies": {
3131 + "@types/retry": "0.12.2",
3132 + "is-network-error": "^1.0.0",
3133 + "retry": "^0.13.1"
3134 + },
3135 + "engines": {
3136 + "node": ">=16.17"
3137 + },
3138 + "funding": {
3139 + "url": "https://github.com/sponsors/sindresorhus"
3140 + }
3141 + },
3142 + "node_modules/p-timeout": {
3143 + "version": "6.1.4",
3144 + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.4.tgz",
3145 + "integrity": "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==",
3146 + "engines": {
3147 + "node": ">=14.16"
3148 + },
3149 + "funding": {
3150 + "url": "https://github.com/sponsors/sindresorhus"
3151 + }
3152 + },
2834 "node_modules/package-json-from-dist": { 3153 "node_modules/package-json-from-dist": {
2835 "version": "1.0.1", 3154 "version": "1.0.1",
2836 "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", 3155 "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
...@@ -3079,6 +3398,15 @@ ...@@ -3079,6 +3398,15 @@
3079 "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", 3398 "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
3080 "dev": true 3399 "dev": true
3081 }, 3400 },
3401 + "node_modules/preact": {
3402 + "version": "10.26.4",
3403 + "resolved": "https://registry.npmjs.org/preact/-/preact-10.26.4.tgz",
3404 + "integrity": "sha512-KJhO7LBFTjP71d83trW+Ilnjbo+ySsaAgCfXOXUlmGzJ4ygYPWmysm77yg4emwfmoz3b22yvH5IsVFHbhUaH5w==",
3405 + "funding": {
3406 + "type": "opencollective",
3407 + "url": "https://opencollective.com/preact"
3408 + }
3409 + },
3082 "node_modules/process": { 3410 "node_modules/process": {
3083 "version": "0.11.10", 3411 "version": "0.11.10",
3084 "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", 3412 "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
...@@ -3190,6 +3518,14 @@ ...@@ -3190,6 +3518,14 @@
3190 "url": "https://github.com/sponsors/ljharb" 3518 "url": "https://github.com/sponsors/ljharb"
3191 } 3519 }
3192 }, 3520 },
3521 + "node_modules/retry": {
3522 + "version": "0.13.1",
3523 + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
3524 + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==",
3525 + "engines": {
3526 + "node": ">= 4"
3527 + }
3528 + },
3193 "node_modules/reusify": { 3529 "node_modules/reusify": {
3194 "version": "1.1.0", 3530 "version": "1.1.0",
3195 "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", 3531 "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
...@@ -3292,6 +3628,11 @@ ...@@ -3292,6 +3628,11 @@
3292 "semver": "bin/semver.js" 3628 "semver": "bin/semver.js"
3293 } 3629 }
3294 }, 3630 },
3631 + "node_modules/shallow-equal": {
3632 + "version": "3.1.0",
3633 + "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-3.1.0.tgz",
3634 + "integrity": "sha512-pfVOw8QZIXpMbhBWvzBISicvToTiM5WBF1EeAUZDDSb5Dt29yl4AYbyywbJFSEsRUMr7gJaxqCdr4L3tQf9wVg=="
3635 + },
3295 "node_modules/shebang-command": { 3636 "node_modules/shebang-command": {
3296 "version": "2.0.0", 3637 "version": "2.0.0",
3297 "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 3638 "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
...@@ -4107,6 +4448,11 @@ ...@@ -4107,6 +4448,11 @@
4107 "node": ">= 8" 4448 "node": ">= 8"
4108 } 4449 }
4109 }, 4450 },
4451 + "node_modules/wildcard": {
4452 + "version": "1.1.2",
4453 + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-1.1.2.tgz",
4454 + "integrity": "sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng=="
4455 + },
4110 "node_modules/wrap-ansi": { 4456 "node_modules/wrap-ansi": {
4111 "version": "8.1.0", 4457 "version": "8.1.0",
4112 "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", 4458 "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
......
...@@ -24,6 +24,7 @@ declare module 'vue' { ...@@ -24,6 +24,7 @@ declare module 'vue' {
24 SearchBar: typeof import('./components/ui/SearchBar.vue')['default'] 24 SearchBar: typeof import('./components/ui/SearchBar.vue')['default']
25 SummerCampCard: typeof import('./components/ui/SummerCampCard.vue')['default'] 25 SummerCampCard: typeof import('./components/ui/SummerCampCard.vue')['default']
26 TermsPopup: typeof import('./components/ui/TermsPopup.vue')['default'] 26 TermsPopup: typeof import('./components/ui/TermsPopup.vue')['default']
27 + UploadVideoPopup: typeof import('./components/ui/UploadVideoPopup.vue')['default']
27 VanButton: typeof import('vant/es')['Button'] 28 VanButton: typeof import('vant/es')['Button']
28 VanCellGroup: typeof import('vant/es')['CellGroup'] 29 VanCellGroup: typeof import('vant/es')['CellGroup']
29 VanCheckbox: typeof import('vant/es')['Checkbox'] 30 VanCheckbox: typeof import('vant/es')['Checkbox']
...@@ -33,6 +34,7 @@ declare module 'vue' { ...@@ -33,6 +34,7 @@ declare module 'vue' {
33 VanIcon: typeof import('vant/es')['Icon'] 34 VanIcon: typeof import('vant/es')['Icon']
34 VanImage: typeof import('vant/es')['Image'] 35 VanImage: typeof import('vant/es')['Image']
35 VanList: typeof import('vant/es')['List'] 36 VanList: typeof import('vant/es')['List']
37 + VanNavBar: typeof import('vant/es')['NavBar']
36 VanPickerGroup: typeof import('vant/es')['PickerGroup'] 38 VanPickerGroup: typeof import('vant/es')['PickerGroup']
37 VanPopup: typeof import('vant/es')['Popup'] 39 VanPopup: typeof import('vant/es')['Popup']
38 VanProgress: typeof import('vant/es')['Progress'] 40 VanProgress: typeof import('vant/es')['Progress']
......
1 +<template>
2 + <van-popup
3 + v-model:show="show"
4 + position="bottom"
5 + :style="{ height: '100%' }"
6 + >
7 + <div class="upload-video-popup">
8 + <van-nav-bar
9 + title="上传视频"
10 + left-text="取消"
11 + right-text="提交"
12 + @click-left="onCancel"
13 + @click-right="onSubmit"
14 + />
15 +
16 + <div class="upload-content">
17 + <van-uploader
18 + :max-count="1"
19 + :max-size="maxSize"
20 + :before-read="beforeRead"
21 + :after-read="afterRead"
22 + accept="video/*"
23 + @oversize="onOversize"
24 + >
25 + <van-button icon="plus" type="primary">上传视频</van-button>
26 + </van-uploader>
27 +
28 + <div v-if="uploadProgress > 0 && uploadProgress < 100" class="progress">
29 + <van-progress :percentage="uploadProgress" :show-pivot="true" />
30 + </div>
31 +
32 + <div v-if="videoUrl" class="video-preview">
33 + <VideoPlayer :video-url="videoUrl" :autoplay="false" />
34 + </div>
35 + </div>
36 + </div>
37 + </van-popup>
38 +</template>
39 +
40 +<script setup>
41 +import { ref, defineProps, defineEmits, watch } from 'vue';
42 +import { showToast } from 'vant';
43 +import VideoPlayer from '@/components/ui/VideoPlayer.vue';
44 +import { v4 as uuidv4 } from 'uuid';
45 +
46 +const props = defineProps({
47 + modelValue: {
48 + type: Boolean,
49 + required: true
50 + }
51 +});
52 +
53 +const emit = defineEmits(['update:modelValue', 'submit', 'cancel']);
54 +
55 +const show = ref(false);
56 +
57 +watch(() => props.modelValue, (newVal) => {
58 + show.value = newVal;
59 + if (newVal) {
60 + // 重置所有状态
61 + videoUrl.value = '';
62 + videoId.value = '';
63 + videoName.value = '';
64 + uploadProgress.value = 0;
65 + }
66 +});
67 +
68 +watch(show, (newVal) => {
69 + emit('update:modelValue', newVal);
70 +});
71 +
72 +const videoUrl = ref('');
73 +const videoId = ref('');
74 +const videoName = ref('');
75 +const uploadProgress = ref(0);
76 +const maxSize = 100 * 1024 * 1024; // 100MB
77 +
78 +const beforeRead = (file) => {
79 + if (!file.type.includes('video/')) {
80 + showToast('请上传视频文件');
81 + return false;
82 + }
83 + return true;
84 +};
85 +
86 +const afterRead = async (file) => {
87 + const formData = new FormData();
88 + formData.append('file', file.file);
89 +
90 + try {
91 + // 模拟上传进度
92 + const timer = setInterval(() => {
93 + uploadProgress.value += 10;
94 + if (uploadProgress.value >= 100) {
95 + clearInterval(timer);
96 + // 模拟上传成功后的视频URL
97 + videoUrl.value = URL.createObjectURL(file.file);
98 + videoId.value = uuidv4();
99 + videoName.value = file.file.name;
100 + }
101 + }, 300);
102 +
103 + // TODO: 实际的上传逻辑
104 + // const response = await uploadVideo(formData);
105 + // videoUrl.value = response.data.url;
106 + // videoId.value = uuidv4();
107 + // videoName.value = file.file.name;
108 + } catch (error) {
109 + showToast('上传失败');
110 + console.error('Upload error:', error);
111 + }
112 +};
113 +
114 +const onOversize = () => {
115 + showToast('文件大小不能超过100MB');
116 +};
117 +
118 +const onSubmit = () => {
119 + if (!videoUrl.value || !videoId.value) {
120 + showToast('请先上传视频');
121 + return;
122 + }
123 + emit('submit', {
124 + url: videoUrl.value,
125 + id: videoId.value,
126 + name: videoName.value
127 + });
128 + emit('update:modelValue', false);
129 +};
130 +
131 +const onCancel = () => {
132 + emit('cancel');
133 + emit('update:modelValue', false);
134 +};
135 +</script>
136 +
137 +<style scoped>
138 +.upload-video-popup {
139 + display: flex;
140 + flex-direction: column;
141 + height: 100%;
142 +}
143 +
144 +.upload-content {
145 + flex: 1;
146 + padding: 16px;
147 + overflow-y: auto;
148 +}
149 +
150 +.progress {
151 + margin: 16px 0;
152 +}
153 +
154 +.video-preview {
155 + margin-top: 16px;
156 + width: 100%;
157 + max-width: 600px;
158 +}
159 +</style>
...@@ -28,6 +28,11 @@ const props = defineProps({ ...@@ -28,6 +28,11 @@ const props = defineProps({
28 type: String, 28 type: String,
29 required: true, 29 required: true,
30 }, 30 },
31 + autoplay: {
32 + type: Boolean,
33 + required: false,
34 + default: true,
35 + },
31 }); 36 });
32 37
33 const emit = defineEmits(["onPlay", "onPause"]); 38 const emit = defineEmits(["onPlay", "onPause"]);
...@@ -39,7 +44,7 @@ const videoOptions = computed(() => ({ ...@@ -39,7 +44,7 @@ const videoOptions = computed(() => ({
39 controls: true, 44 controls: true,
40 preload: "auto", 45 preload: "auto",
41 responsive: true, 46 responsive: true,
42 - autoplay: true, 47 + autoplay: props.autoplay,
43 sources: [ 48 sources: [
44 { 49 {
45 src: props.videoUrl, 50 src: props.videoUrl,
...@@ -68,7 +73,10 @@ const handleMounted = (payload) => { ...@@ -68,7 +73,10 @@ const handleMounted = (payload) => {
68 state.value = payload.state; 73 state.value = payload.state;
69 player.value = payload.player; 74 player.value = payload.player;
70 if (player.value) { 75 if (player.value) {
76 + // TAG: 自动播放
77 + if (props.autoplay) {
71 player.value.play(); 78 player.value.play();
79 + }
72 if (!wxInfo().isPc) { 80 if (!wxInfo().isPc) {
73 // 添加touchstart事件监听 81 // 添加touchstart事件监听
74 player.value.on('touchstart', (event) => { 82 player.value.on('touchstart', (event) => {
......
1 /* 1 /*
2 * @Date: 2025-03-20 20:36:36 2 * @Date: 2025-03-20 20:36:36
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-03-21 17:58:10 4 + * @LastEditTime: 2025-03-25 09:55:59
5 * @FilePath: /mlaj/src/router/index.js 5 * @FilePath: /mlaj/src/router/index.js
6 * @Description: 文件描述 6 * @Description: 文件描述
7 */ 7 */
...@@ -175,6 +175,12 @@ const routes = [ ...@@ -175,6 +175,12 @@ const routes = [
175 component: () => import('../views/test.vue'), 175 component: () => import('../views/test.vue'),
176 meta: { title: 'test' }, 176 meta: { title: 'test' },
177 }, 177 },
178 + {
179 + path: '/upload_video',
180 + name: 'upload_video',
181 + component: () => import('../views/upload_video.vue'),
182 + meta: { title: 'upload_video' },
183 + },
178 ...checkinRoutes, 184 ...checkinRoutes,
179 ] 185 ]
180 186
......
1 <!-- 1 <!--
2 * @Date: 2025-03-24 13:04:21 2 * @Date: 2025-03-24 13:04:21
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-03-24 14:05:18 4 + * @LastEditTime: 2025-03-25 09:56:14
5 * @FilePath: /mlaj/src/views/profile/SettingsPage.vue 5 * @FilePath: /mlaj/src/views/profile/SettingsPage.vue
6 * @Description: 用户设置页面 6 * @Description: 用户设置页面
7 --> 7 -->
...@@ -53,6 +53,17 @@ ...@@ -53,6 +53,17 @@
53 <ChevronRightIcon class="w-5 h-5 text-gray-400" /> 53 <ChevronRightIcon class="w-5 h-5 text-gray-400" />
54 </div> 54 </div>
55 </div> 55 </div>
56 +
57 + <!-- 视频上传 -->
58 + <div class="p-4" @click="router.push('/upload_video')">
59 + <div class="flex items-center justify-between">
60 + <div>
61 + <h3 class="text-base font-medium text-gray-900">视频上传</h3>
62 + <p class="text-sm text-gray-500">视频上传</p>
63 + </div>
64 + <ChevronRightIcon class="w-5 h-5 text-gray-400" />
65 + </div>
66 + </div>
56 </div> 67 </div>
57 </FrostedGlass> 68 </FrostedGlass>
58 </div> 69 </div>
......
1 +<template>
2 + <div class="upload-video-container">
3 + <van-button icon="plus" type="primary" @click="showUploadPopup = true">上传视频</van-button>
4 +
5 + <div class="video-list">
6 + <div v-for="video in videos" :key="video.id" class="video-preview">
7 + <VideoPlayer :video-url="video.url" :autoplay="false" />
8 + <div class="video-info">
9 + <span class="video-name">{{ video.name }}</span>
10 + <van-button icon="delete" type="danger" size="small" class="delete-btn" @click="deleteVideo(video.id)">删除</van-button>
11 + </div>
12 + </div>
13 + </div>
14 +
15 + <UploadVideoPopup
16 + v-model="showUploadPopup"
17 + @submit="onVideoUploaded"
18 + @cancel="showUploadPopup = false"
19 + />
20 + </div>
21 +</template>
22 +
23 +<script setup>
24 +import { ref } from 'vue';
25 +import VideoPlayer from '@/components/ui/VideoPlayer.vue';
26 +import UploadVideoPopup from '@/components/ui/UploadVideoPopup.vue';
27 +
28 +const showUploadPopup = ref(false);
29 +const videos = ref([]);
30 +
31 +const onVideoUploaded = (videoInfo) => {
32 + videos.value.push(videoInfo);
33 +};
34 +
35 +const deleteVideo = (id) => {
36 + const index = videos.value.findIndex(video => video.id === id);
37 + if (index !== -1) {
38 + const newVideos = [...videos.value];
39 + newVideos.splice(index, 1);
40 + videos.value = newVideos;
41 + }
42 +};
43 +</script>
44 +
45 +<style scoped>
46 +.upload-video-container {
47 + padding: 16px;
48 +}
49 +
50 +.video-list {
51 + margin-top: 16px;
52 + display: grid;
53 + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
54 + gap: 16px;
55 +}
56 +
57 +.video-preview {
58 + position: relative;
59 + width: 100%;
60 +}
61 +
62 +.delete-btn {
63 + position: absolute;
64 + top: 8px;
65 + right: 8px;
66 + z-index: 1;
67 +}
68 +</style>