Commit 34d9ab96ba84808fb56548f19914fce60b75ec87

Authored by xp.Huang
2 parents fdd6f2c2 478e5b14

Merge branch 'perf/video-player-change' into 'main_dev'

perf: 变更视频组件&&支持h265

See merge request yunteng/thingskit-view!223
... ... @@ -57,7 +57,11 @@
57 57 "vue-router": "4.0.12",
58 58 "vue3-lazyload": "^0.2.5-beta",
59 59 "vue3-sketch-ruler": "^1.3.3",
60   - "vuedraggable": "^4.1.0"
  60 + "vuedraggable": "^4.1.0",
  61 + "xgplayer": "^3.0.14",
  62 + "xgplayer-flv": "^3.0.14",
  63 + "xgplayer-hls": "^3.0.14",
  64 + "xgplayer-mp4": "^3.0.14"
61 65 },
62 66 "devDependencies": {
63 67 "@commitlint/cli": "^17.0.2",
... ...
1   -lockfileVersion: '6.1'
  1 +lockfileVersion: '6.0'
2 2
3 3 settings:
4 4 autoInstallPeers: true
... ... @@ -11,6 +11,9 @@ dependencies:
11 11 '@amap/amap-jsapi-types':
12 12 specifier: ^0.0.8
13 13 version: 0.0.8
  14 + '@fingerprintjs/fingerprintjs':
  15 + specifier: ^3.4.1
  16 + version: 3.4.2
14 17 '@types/color':
15 18 specifier: ^3.0.3
16 19 version: 3.0.3
... ... @@ -41,6 +44,9 @@ dependencies:
41 44 dom-helpers:
42 45 specifier: ^5.2.1
43 46 version: 5.2.1
  47 + echarts-gl:
  48 + specifier: ^2.0.9
  49 + version: 2.0.9(echarts@5.3.3)
44 50 echarts-liquidfill:
45 51 specifier: ^3.1.0
46 52 version: 3.1.0(echarts@5.3.3)
... ... @@ -50,6 +56,9 @@ dependencies:
50 56 echarts-wordcloud:
51 57 specifier: ^2.0.0
52 58 version: 2.0.0(echarts@5.3.3)
  59 + flv.js:
  60 + specifier: ^1.6.2
  61 + version: 1.6.2
53 62 gsap:
54 63 specifier: ^3.11.3
55 64 version: 3.11.3
... ... @@ -89,6 +98,9 @@ dependencies:
89 98 video.js:
90 99 specifier: ^7.20.3
91 100 version: 7.21.4
  101 + videojs-flvjs-es6:
  102 + specifier: ^1.0.1
  103 + version: 1.0.1
92 104 vue:
93 105 specifier: ^3.2.31
94 106 version: 3.2.37
... ... @@ -113,6 +125,18 @@ dependencies:
113 125 vuedraggable:
114 126 specifier: ^4.1.0
115 127 version: 4.1.0(vue@3.2.37)
  128 + xgplayer:
  129 + specifier: ^3.0.14
  130 + version: 3.0.14(core-js@3.36.1)
  131 + xgplayer-flv:
  132 + specifier: ^3.0.14
  133 + version: 3.0.14(core-js@3.36.1)(xgplayer@3.0.14)
  134 + xgplayer-hls:
  135 + specifier: ^3.0.14
  136 + version: 3.0.14(core-js@3.36.1)(xgplayer@3.0.14)
  137 + xgplayer-mp4:
  138 + specifier: ^3.0.14
  139 + version: 3.0.14(core-js@3.36.1)(xgplayer@3.0.14)
116 140
117 141 devDependencies:
118 142 '@commitlint/cli':
... ... @@ -1158,6 +1182,12 @@ packages:
1158 1182 - supports-color
1159 1183 dev: true
1160 1184
  1185 + /@fingerprintjs/fingerprintjs@3.4.2:
  1186 + resolution: {integrity: sha512-3Ncze6JsJpB7BpYhqIgvBpfvEX1jsEKrad5hQBpyRQxtoAp6hx3+R46zqfsuQG4D9egQZ+xftQ0u4LPFMB7Wmg==}
  1187 + dependencies:
  1188 + tslib: 2.6.2
  1189 + dev: false
  1190 +
1161 1191 /@humanwhocodes/config-array@0.9.5:
1162 1192 resolution: {integrity: sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==}
1163 1193 engines: {node: '>=10.10.0'}
... ... @@ -2409,6 +2439,10 @@ packages:
2409 2439 engines: {node: '>=6.0'}
2410 2440 dev: true
2411 2441
  2442 + /claygl@1.3.0:
  2443 + resolution: {integrity: sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ==}
  2444 + dev: false
  2445 +
2412 2446 /clean-css@5.3.2:
2413 2447 resolution: {integrity: sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==}
2414 2448 engines: {node: '>= 10.0'}
... ... @@ -2540,6 +2574,12 @@ packages:
2540 2574 resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
2541 2575 dev: true
2542 2576
  2577 + /concat-typed-array@1.0.2:
  2578 + resolution: {integrity: sha512-aC878bxeWSlrY6h60cCDwBUXpKwovZrB7+C4+VHNO1CIXW2gBLxbQ757jWtOXUscLGgYI8R84N6uy9fTJPe+0g==}
  2579 + engines: {node: '>=0.10.0'}
  2580 + deprecated: 'WARNING: This package has been renamed to typed-array-concat.'
  2581 + dev: false
  2582 +
2543 2583 /connect-history-api-fallback@1.6.0:
2544 2584 resolution: {integrity: sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==}
2545 2585 engines: {node: '>=0.8'}
... ... @@ -2605,6 +2645,11 @@ packages:
2605 2645 safe-buffer: 5.1.2
2606 2646 dev: true
2607 2647
  2648 + /core-js@3.36.1:
  2649 + resolution: {integrity: sha512-BTvUrwxVBezj5SZ3f10ImnX2oRByMxql3EimVqMysepbC9EeMUOpLwdy6Eoili2x6E4kf+ZUB5k/+Jv55alPfA==}
  2650 + requiresBuild: true
  2651 + dev: false
  2652 +
2608 2653 /cosmiconfig-typescript-loader@2.0.1(@types/node@17.0.43)(cosmiconfig@7.0.1)(typescript@4.7.3):
2609 2654 resolution: {integrity: sha512-B9s6sX/omXq7I6gC6+YgLmrBFMJhPWew7ty/X5Tuwtd2zOSgWaUdXjkuVwbe3qqcdETo60+1nSVMekq//LIXVA==}
2610 2655 engines: {node: '>=12', npm: '>=6'}
... ... @@ -2646,6 +2691,10 @@ packages:
2646 2691 which: 2.0.2
2647 2692 dev: true
2648 2693
  2694 + /crypto-es@1.2.7:
  2695 + resolution: {integrity: sha512-UUqiVJ2gUuZFmbFsKmud3uuLcNP2+Opt+5ysmljycFCyhA0+T16XJmo1ev/t5kMChMqWh7IEvURNCqsg+SjZGQ==}
  2696 + dev: false
  2697 +
2649 2698 /crypto-js@4.1.1:
2650 2699 resolution: {integrity: sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==}
2651 2700 dev: false
... ... @@ -2692,6 +2741,20 @@ packages:
2692 2741 resolution: {integrity: sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==}
2693 2742 dev: false
2694 2743
  2744 + /d@1.0.2:
  2745 + resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==}
  2746 + engines: {node: '>=0.12'}
  2747 + dependencies:
  2748 + es5-ext: 0.10.64
  2749 + type: 2.7.2
  2750 + dev: false
  2751 +
  2752 + /danmu.js@1.1.13:
  2753 + resolution: {integrity: sha512-knFd0/cB2HA4FFWiA7eB2suc5vCvoHdqio33FyyCSfP7C+1A+zQcTvnvwfxaZhrxsGj4qaQI2I8XiTqedRaVmg==}
  2754 + dependencies:
  2755 + event-emitter: 0.3.5
  2756 + dev: false
  2757 +
2695 2758 /dargs@7.0.0:
2696 2759 resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==}
2697 2760 engines: {node: '>=8'}
... ... @@ -2765,6 +2828,11 @@ packages:
2765 2828 resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
2766 2829 dev: true
2767 2830
  2831 + /deepmerge@2.2.1:
  2832 + resolution: {integrity: sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==}
  2833 + engines: {node: '>=0.10.0'}
  2834 + dev: false
  2835 +
2768 2836 /deepmerge@4.2.2:
2769 2837 resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==}
2770 2838 engines: {node: '>=0.10.0'}
... ... @@ -2807,6 +2875,10 @@ packages:
2807 2875 engines: {node: '>=0.4.0'}
2808 2876 dev: false
2809 2877
  2878 + /delegate@3.2.0:
  2879 + resolution: {integrity: sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==}
  2880 + dev: false
  2881 +
2810 2882 /detect-file@1.0.0:
2811 2883 resolution: {integrity: sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==}
2812 2884 engines: {node: '>=0.10.0'}
... ... @@ -2900,6 +2972,20 @@ packages:
2900 2972 engines: {node: '>=12'}
2901 2973 dev: true
2902 2974
  2975 + /downloadjs@1.4.7:
  2976 + resolution: {integrity: sha512-LN1gO7+u9xjU5oEScGFKvXhYf7Y/empUIIEAGBs1LzUq/rg5duiDrkuH5A2lQGd5jfMOb9X9usDa2oVXwJ0U/Q==}
  2977 + dev: false
  2978 +
  2979 + /echarts-gl@2.0.9(echarts@5.3.3):
  2980 + resolution: {integrity: sha512-oKeMdkkkpJGWOzjgZUsF41DOh6cMsyrGGXimbjK2l6Xeq/dBQu4ShG2w2Dzrs/1bD27b2pLTGSaUzouY191gzA==}
  2981 + peerDependencies:
  2982 + echarts: ^5.1.2
  2983 + dependencies:
  2984 + claygl: 1.3.0
  2985 + echarts: 5.3.3
  2986 + zrender: 5.3.2
  2987 + dev: false
  2988 +
2903 2989 /echarts-liquidfill@3.1.0(echarts@5.3.3):
2904 2990 resolution: {integrity: sha512-5Dlqs/jTsdTUAsd+K5LPLLTgrbbNORUSBQyk8PSy1Mg2zgHDWm83FmvA4s0ooNepCJojFYRITTQ4GU1UUSKYLw==}
2905 2991 peerDependencies:
... ... @@ -3021,6 +3107,37 @@ packages:
3021 3107 is-symbol: 1.0.4
3022 3108 dev: true
3023 3109
  3110 + /es5-ext@0.10.64:
  3111 + resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==}
  3112 + engines: {node: '>=0.10'}
  3113 + requiresBuild: true
  3114 + dependencies:
  3115 + es6-iterator: 2.0.3
  3116 + es6-symbol: 3.1.4
  3117 + esniff: 2.0.1
  3118 + next-tick: 1.1.0
  3119 + dev: false
  3120 +
  3121 + /es6-iterator@2.0.3:
  3122 + resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==}
  3123 + dependencies:
  3124 + d: 1.0.2
  3125 + es5-ext: 0.10.64
  3126 + es6-symbol: 3.1.4
  3127 + dev: false
  3128 +
  3129 + /es6-promise@4.2.8:
  3130 + resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==}
  3131 + dev: false
  3132 +
  3133 + /es6-symbol@3.1.4:
  3134 + resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==}
  3135 + engines: {node: '>=0.12'}
  3136 + dependencies:
  3137 + d: 1.0.2
  3138 + ext: 1.7.0
  3139 + dev: false
  3140 +
3024 3141 /esbuild@0.11.3:
3025 3142 resolution: {integrity: sha512-BzVRHcCtFepjS9WcqRjqoIxLqgpK21a8J4Zi4msSGxDxiXVO1IbcqT1KjhdDDnJxKfe7bvzZrvMEX+bVO0Elcw==}
3026 3143 hasBin: true
... ... @@ -3265,6 +3382,16 @@ packages:
3265 3382 - supports-color
3266 3383 dev: true
3267 3384
  3385 + /esniff@2.0.1:
  3386 + resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==}
  3387 + engines: {node: '>=0.10'}
  3388 + dependencies:
  3389 + d: 1.0.2
  3390 + es5-ext: 0.10.64
  3391 + event-emitter: 0.3.5
  3392 + type: 2.7.2
  3393 + dev: false
  3394 +
3268 3395 /espree@9.3.2:
3269 3396 resolution: {integrity: sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==}
3270 3397 engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
... ... @@ -3310,6 +3437,17 @@ packages:
3310 3437 engines: {node: '>=0.10.0'}
3311 3438 dev: true
3312 3439
  3440 + /event-emitter@0.3.5:
  3441 + resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==}
  3442 + dependencies:
  3443 + d: 1.0.2
  3444 + es5-ext: 0.10.64
  3445 + dev: false
  3446 +
  3447 + /eventemitter3@4.0.7:
  3448 + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
  3449 + dev: false
  3450 +
3313 3451 /events@3.3.0:
3314 3452 resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
3315 3453 engines: {node: '>=0.8.x'}
... ... @@ -3341,6 +3479,12 @@ packages:
3341 3479 homedir-polyfill: 1.0.3
3342 3480 dev: true
3343 3481
  3482 + /ext@1.7.0:
  3483 + resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==}
  3484 + dependencies:
  3485 + type: 2.7.2
  3486 + dev: false
  3487 +
3344 3488 /extend@3.0.2:
3345 3489 resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
3346 3490 dev: true
... ... @@ -3490,6 +3634,13 @@ packages:
3490 3634 resolution: {integrity: sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==}
3491 3635 dev: true
3492 3636
  3637 + /flv.js@1.6.2:
  3638 + resolution: {integrity: sha512-xre4gUbX1MPtgQRKj2pxJENp/RnaHaxYvy3YToVVCrSmAWUu85b9mug6pTXF6zakUjNP2lFWZ1rkSX7gxhB/2A==}
  3639 + dependencies:
  3640 + es6-promise: 4.2.8
  3641 + webworkify-webpack: 2.1.5
  3642 + dev: false
  3643 +
3493 3644 /follow-redirects@1.15.1:
3494 3645 resolution: {integrity: sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==}
3495 3646 engines: {node: '>=4.0'}
... ... @@ -4590,6 +4741,10 @@ packages:
4590 4741 resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
4591 4742 dev: true
4592 4743
  4744 + /next-tick@1.1.0:
  4745 + resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
  4746 + dev: false
  4747 +
4593 4748 /no-case@3.0.4:
4594 4749 resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==}
4595 4750 dependencies:
... ... @@ -5732,6 +5887,10 @@ packages:
5732 5887 resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==}
5733 5888 dev: true
5734 5889
  5890 + /tslib@2.6.2:
  5891 + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
  5892 + dev: false
  5893 +
5735 5894 /tsutils@3.21.0(typescript@4.6.3):
5736 5895 resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
5737 5896 engines: {node: '>= 6'}
... ... @@ -5774,6 +5933,10 @@ packages:
5774 5933 engines: {node: '>=8'}
5775 5934 dev: true
5776 5935
  5936 + /type@2.7.2:
  5937 + resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==}
  5938 + dev: false
  5939 +
5777 5940 /typescript@4.6.3:
5778 5941 resolution: {integrity: sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==}
5779 5942 engines: {node: '>=4.2.0'}
... ... @@ -5912,6 +6075,10 @@ packages:
5912 6075 videojs-vtt.js: 0.15.4
5913 6076 dev: false
5914 6077
  6078 + /videojs-flvjs-es6@1.0.1:
  6079 + resolution: {integrity: sha512-wAI5ff2tZVW+uftTLyPmS38F4SHmMlxqBFOgXEBqMs2X0N4uIVQK0iCCv5XACXH+oc+mP70D23mJmT8KsoHx0g==}
  6080 + dev: false
  6081 +
5915 6082 /videojs-font@3.2.0:
5916 6083 resolution: {integrity: sha512-g8vHMKK2/JGorSfqAZQUmYYNnXmfec4MLhwtEFS+mMs2IDY398GLysy6BH6K+aS1KMNu/xWZ8Sue/X/mdQPliA==}
5917 6084 dev: false
... ... @@ -6261,6 +6428,10 @@ packages:
6261 6428 - uglify-js
6262 6429 dev: true
6263 6430
  6431 + /webworkify-webpack@2.1.5:
  6432 + resolution: {integrity: sha512-2akF8FIyUvbiBBdD+RoHpoTbHMQF2HwjcxfDvgztAX5YwbZNyrtfUMgvfgFVsgDhDPVTlkbb5vyasqDHfIDPQw==}
  6433 + dev: false
  6434 +
6264 6435 /which-boxed-primitive@1.0.2:
6265 6436 resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
6266 6437 dependencies:
... ... @@ -6308,6 +6479,101 @@ packages:
6308 6479 resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
6309 6480 dev: true
6310 6481
  6482 + /xgplayer-flv@3.0.14(core-js@3.36.1)(xgplayer@3.0.14):
  6483 + resolution: {integrity: sha512-9mSBUbbzkJhFjQOaU8SvnEzDj4Y9tkHsW0IaIxCDi/DlDcHzSubdiuuTVNf1A5cgUSTnFHxwDJtzqVm6FhmTeg==}
  6484 + peerDependencies:
  6485 + core-js: '>=3.12.1'
  6486 + xgplayer: '>=3.0.1'
  6487 + dependencies:
  6488 + core-js: 3.36.1
  6489 + eventemitter3: 4.0.7
  6490 + xgplayer: 3.0.14(core-js@3.36.1)
  6491 + xgplayer-streaming-shared: 3.0.14(core-js@3.36.1)
  6492 + xgplayer-transmuxer: 3.0.14(core-js@3.36.1)
  6493 + dev: false
  6494 +
  6495 + /xgplayer-hls@3.0.14(core-js@3.36.1)(xgplayer@3.0.14):
  6496 + resolution: {integrity: sha512-UiVDiDcIzQ6kiDZitbyXqRx5nX/Pi69S9Vfh5lc+6R8SsA2ZyvxWtGOQ6XfpZyXYHfl56JMbyNObOgMT1iRNLw==}
  6497 + peerDependencies:
  6498 + core-js: '>=3.12.1'
  6499 + xgplayer: 3.0.14
  6500 + dependencies:
  6501 + core-js: 3.36.1
  6502 + eventemitter3: 4.0.7
  6503 + xgplayer: 3.0.14(core-js@3.36.1)
  6504 + xgplayer-streaming-shared: 3.0.14(core-js@3.36.1)
  6505 + xgplayer-transmuxer: 3.0.14(core-js@3.36.1)
  6506 + dev: false
  6507 +
  6508 + /xgplayer-mp4-loader@3.0.14(core-js@3.36.1):
  6509 + resolution: {integrity: sha512-cCPH7I/i+saP5i+vivfnu7Bekxm1sS3JlTzaqX2crUL9a4MfWi/r7Yumqsn52lyQGyb+lGKOsvbHeR3wTwUx1w==}
  6510 + peerDependencies:
  6511 + core-js: '>=3.12.1'
  6512 + dependencies:
  6513 + core-js: 3.36.1
  6514 + eventemitter3: 4.0.7
  6515 + xgplayer-streaming-shared: 3.0.14(core-js@3.36.1)
  6516 + xgplayer-transmuxer: 3.0.14(core-js@3.36.1)
  6517 + dev: false
  6518 +
  6519 + /xgplayer-mp4@3.0.14(core-js@3.36.1)(xgplayer@3.0.14):
  6520 + resolution: {integrity: sha512-EEZ3KtG7JbOBL33P+Uv98PaIft9tI9zw2rfyS7Sip57hT/9tJ2az4qz9qNSRcrrlLTo0DTYGR/JzADu7l/IyUQ==}
  6521 + peerDependencies:
  6522 + core-js: '>=3.12.1'
  6523 + xgplayer: '>=3.0.0'
  6524 + dependencies:
  6525 + concat-typed-array: 1.0.2
  6526 + core-js: 3.36.1
  6527 + deepmerge: 2.2.1
  6528 + eventemitter3: 4.0.7
  6529 + xgplayer: 3.0.14(core-js@3.36.1)
  6530 + xgplayer-mp4-loader: 3.0.14(core-js@3.36.1)
  6531 + xgplayer-streaming-shared: 3.0.14(core-js@3.36.1)
  6532 + xgplayer-transmuxer: 3.0.14(core-js@3.36.1)
  6533 + dev: false
  6534 +
  6535 + /xgplayer-streaming-shared@3.0.14(core-js@3.36.1):
  6536 + resolution: {integrity: sha512-XBXNjnMfFDl15kQfXNgmAkaDqRdN0PhxVFBm7+TezillpTdLmqj+HD90F6BargdZVJ4I20/YHYdb9qBg+hUDhg==}
  6537 + peerDependencies:
  6538 + core-js: '>=3.12.1'
  6539 + dependencies:
  6540 + core-js: 3.36.1
  6541 + eventemitter3: 4.0.7
  6542 + dev: false
  6543 +
  6544 + /xgplayer-subtitles@3.0.14(core-js@3.36.1):
  6545 + resolution: {integrity: sha512-w6H1h+g3kOI477kv2QBRMZe3M/1dHLXttHBwq4LwKTPGVQ19fLIDGwkfn+HeKwe1ocGDaaq96bS+l+BadnP9TA==}
  6546 + peerDependencies:
  6547 + core-js: '>=3.12.1'
  6548 + dependencies:
  6549 + core-js: 3.36.1
  6550 + eventemitter3: 4.0.7
  6551 + dev: false
  6552 +
  6553 + /xgplayer-transmuxer@3.0.14(core-js@3.36.1):
  6554 + resolution: {integrity: sha512-lMS2EwuA6tToCC4NuyJ5Ax0UDaaWU/YuaSkI/Bsj+vHkEzO42vgi2EerSPr91Moz05KhG/+4Vt8qMKUVFjhGTw==}
  6555 + peerDependencies:
  6556 + core-js: '>=3.12.1'
  6557 + dependencies:
  6558 + '@babel/runtime': 7.20.6
  6559 + concat-typed-array: 1.0.2
  6560 + core-js: 3.36.1
  6561 + crypto-es: 1.2.7
  6562 + dev: false
  6563 +
  6564 + /xgplayer@3.0.14(core-js@3.36.1):
  6565 + resolution: {integrity: sha512-TPS77hUIcM1zVx6FSpGG+OzfMwjwxxWihd+YxVx82DQ22QK60v8TXWSZlWISbmS1+fAlFneesvXDjwy60tC37w==}
  6566 + peerDependencies:
  6567 + core-js: '>=3.12.1'
  6568 + dependencies:
  6569 + core-js: 3.36.1
  6570 + danmu.js: 1.1.13
  6571 + delegate: 3.2.0
  6572 + downloadjs: 1.4.7
  6573 + eventemitter3: 4.0.7
  6574 + xgplayer-subtitles: 3.0.14(core-js@3.36.1)
  6575 + dev: false
  6576 +
6311 6577 /y18n@5.0.8:
6312 6578 resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
6313 6579 engines: {node: '>=10'}
... ...
1 1 import { defHttp } from '@/utils/external/http/axios'
2   -import { ConfigurationItemType, DictItem, OrganizationListItem, UploadResponse } from './model'
  2 +import {CameraRecord, ConfigurationItemType, DictItem, OrganizationListItem, UploadResponse} from './model'
3 3 import { PaginationResult } from '/#/external/axios'
4 4 import { isShareMode } from '@/views/share/hook'
5 5
... ... @@ -88,7 +88,7 @@ export const getOrganizationList = (params?: OrganizationListItem) =>
88 88
89 89 //获取视频列表
90 90 export const getVideoList = (params?: object) =>
91   - defHttp.get({
  91 + defHttp.get<{data: CameraRecord[]}>({
92 92 url: Api.VIDEO,
93 93 params
94 94 })
... ...
... ... @@ -54,3 +54,39 @@ export interface ProductAndDevice {
54 54 deviceType: string
55 55 transportType: string
56 56 }
  57 +
  58 +
  59 +export interface CameraRecord {
  60 + id: string;
  61 + creator: string;
  62 + createTime: string;
  63 + updater: string;
  64 + updateTime: string;
  65 + name: string;
  66 + enabled: boolean;
  67 + tenantId: string;
  68 + videoUrl: string;
  69 + brand: string;
  70 + sn: string;
  71 + organizationId: string;
  72 + organizationName: string;
  73 + status: boolean;
  74 + accessMode: number;
  75 + playProtocol: number;
  76 + deviceId?: string;
  77 + channelId?: string;
  78 + params?: {
  79 + channelNo: string;
  80 + deviceId: string;
  81 + };
  82 + videoPlatformDTO?: VideoPlatformDTO;
  83 +}
  84 +
  85 +interface VideoPlatformDTO {
  86 + enabled: boolean;
  87 + type: number;
  88 + host: string;
  89 + appKey: string;
  90 + appSecret: string;
  91 + ssl: number;
  92 +}
... ...
  1 +export {default as XGPlayer} from './src/index.vue'
... ...
  1 +<script setup lang="ts">
  2 +import Player, {Events, IError} from 'xgplayer';
  3 +import {FlvPlugin} from 'xgplayer-flv';
  4 +import Mp4Plugin from 'xgplayer-mp4';
  5 +import {HlsPlugin} from 'xgplayer-hls';
  6 +import {onMounted, shallowRef, computed, unref, toRaw, onUnmounted, ref, watch} from 'vue';
  7 +import PresetPlayer from 'xgplayer';
  8 +import {IPlayerOptions} from 'xgplayer/es/player';
  9 +import 'xgplayer/dist/index.min.css';
  10 +import {StreamType, XGPlayerProps} from './types';
  11 +import {isShareMode} from "@/views/share/hook";
  12 +import {getJwtToken, getShareJwtToken} from "@/utils/external/auth";
  13 +
  14 +const props = withDefaults(defineProps<{
  15 + streamType?: StreamType;
  16 + autoPlay?: boolean;
  17 + url?: string;
  18 + withToken?: boolean;
  19 + config?: Omit<IPlayerOptions, 'url'>;
  20 +}>(), {
  21 + streamType: 'auto',
  22 + autoPlay: true,
  23 + config: () => ({}),
  24 +});
  25 +
  26 +const emits = defineEmits<{
  27 + (eventName: 'ready', player: PresetPlayer): void;
  28 + (eventName: 'onUnmounted', player: PresetPlayer): void;
  29 +}>();
  30 +
  31 +function getStreamTypeByUrl(url = ''): StreamType | undefined {
  32 + if (url.endsWith('.m3u8')) return 'hls';
  33 + else if (url.endsWith('.mp4')) return 'mp4';
  34 + else if (url.endsWith('.flv')) {
  35 + return 'flv';
  36 + } else return;
  37 +}
  38 +
  39 +const getPluginByStreamType = (): IPlayerOptions => {
  40 + let {url, withToken} = props;
  41 + let {streamType} = props;
  42 + streamType = streamType === 'auto' ? getStreamTypeByUrl(url)! : streamType;
  43 +
  44 + const liveConfig = {
  45 + targetLatency: 10,
  46 + maxLatency: 20,
  47 + disconnectTime: 0,
  48 + fetchOptions: withToken
  49 + ? {
  50 + headers: {
  51 + 'X-Authorization': `Bearer ${isShareMode() ? getShareJwtToken() : getJwtToken()}`,
  52 + },
  53 + }
  54 + : {},
  55 + };
  56 + const config: IPlayerOptions = {
  57 + flv: liveConfig,
  58 + hls: liveConfig,
  59 + };
  60 + switch (streamType) {
  61 + case 'hls':
  62 + config.plugins = [HlsPlugin];
  63 + break;
  64 + case 'mp4':
  65 + config.plugins = [Mp4Plugin];
  66 + break;
  67 + case 'flv':
  68 + config.plugins = [FlvPlugin];
  69 + break;
  70 + }
  71 + return config;
  72 +};
  73 +
  74 +const videoElRef = shallowRef<Nullable<HTMLDivElement>>();
  75 +
  76 +const playerRef = shallowRef<Nullable<PresetPlayer>>();
  77 +
  78 +const propsRef = ref<XGPlayerProps>({});
  79 +
  80 +const getPlayerConfig = computed<IPlayerOptions>(() => {
  81 + const {url, autoPlay, config} = props;
  82 +
  83 + const basicConfig: IPlayerOptions = {
  84 + ...config,
  85 + ...propsRef,
  86 + url,
  87 + lang: 'zh',
  88 + isLive: true,
  89 + autoplay: autoPlay,
  90 + autoplayMuted: autoPlay,
  91 + ...getPluginByStreamType(),
  92 + };
  93 + return basicConfig;
  94 +});
  95 +
  96 +function onDecodeError() {
  97 + console.warn('player happend decode error');
  98 + playerRef.value?.switchURL(props.url!);
  99 +}
  100 +
  101 +function initializePlayer() {
  102 + if (unref(playerRef)) {
  103 + playerRef.value?.destroy?.();
  104 + playerRef.value = null;
  105 + }
  106 +
  107 + const config = toRaw(unref(getPlayerConfig));
  108 +
  109 + if (!unref(videoElRef)) return;
  110 +
  111 + const player = (playerRef.value = new Player(Object.assign(config, {el: unref(videoElRef)})));
  112 +
  113 + player.on(Events.READY, () => {
  114 + emits('ready', player);
  115 + });
  116 +
  117 + player.setEventsMiddleware({
  118 + error: (event, callback) => {
  119 + const code = (
  120 + event as unknown as {
  121 + error: MediaError;
  122 + }
  123 + ).error.code;
  124 + if (code === MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED) {
  125 + if (!props.url) {
  126 + return;
  127 + }
  128 + callback();
  129 + return;
  130 + }
  131 +
  132 + if (code === MediaError.MEDIA_ERR_DECODE) {
  133 + // 视频流可以播放 中途解码失败重载
  134 + if (playerRef.value?.isPlaying) {
  135 + onDecodeError();
  136 + }
  137 + return;
  138 + }
  139 +
  140 + callback();
  141 + },
  142 + });
  143 +}
  144 +
  145 +onMounted(() => {
  146 + initializePlayer();
  147 +});
  148 +
  149 +onUnmounted(() => {
  150 + emits('onUnmounted', unref(playerRef)!);
  151 + playerRef.value?.destroy?.();
  152 +});
  153 +
  154 +watch(
  155 + () => props.url,
  156 + () => {
  157 + initializePlayer();
  158 + }
  159 +);
  160 +
  161 +defineExpose({
  162 + getPlayerInstance: () => unref(playerRef),
  163 +});
  164 +</script>
  165 +
  166 +<template>
  167 + <div ref="videoElRef"></div>
  168 +</template>
... ...
  1 +import { IPlayerOptions } from 'xgplayer/es/player';
  2 +
  3 +export type StreamType = 'flv' | 'mp4' | 'hls' | 'auto';
  4 +export interface XGPlayerProps {
  5 + streamType?: StreamType;
  6 + autoPlay?: boolean;
  7 + url?: string;
  8 + withToken?: boolean;
  9 + config?: Omit<IPlayerOptions, 'url'>;
  10 +}
... ...
1   -<template>
2   - <n-spin size="medium" :show="showLoading"
3   - :style="{background: '#000',width: baseSize?.w + 'px', height: baseSize?.h + 'px' }">
4   - <template #description> 视频正在努力加载中...... </template>
5   - <div>
6   - <div ref="playerContainerElRef" class="go-content-box"
7   - :style="{ width: baseSize?.w + 'px', height: baseSize?.h + 'px', background: '#000' }">
8   -
9   - </div>
10   - </div>
11   - </n-spin>
12   -</template>
13   -<script setup lang="ts" name="VideoPlay">
14   -import { onMounted, ref, onUnmounted, watch, unref, PropType, shallowRef } from 'vue'
15   -import videojs from 'video.js'
16   -import 'videojs-flvjs-es6'
17   -import type { VideoJsPlayerOptions } from 'video.js'
18   -import 'video.js/dist/video-js.min.css'
19   -import { getJwtToken, getShareJwtToken } from '@/utils/external/auth'
20   -import { isShareMode } from '@/views/share/hook'
21   -import { getOpenFlvPlayUrl, closeFlvPlay, getVideoControlStart } from '@/api/external/flvPlay'
22   -import { useFingerprint } from '@/utils/external/useFingerprint'
23   -import { GetResult } from '@fingerprintjs/fingerprintjs'
24   -import { AccessModeEnum, VideoPlayerType } from '../config'
25   -import { getVideoUrl } from '@/api/external/common'
26   -
27   -const props = defineProps({
28   - sourceSrc: {
29   - type: String
30   - },
31   - option: {
32   - type: Object
33   - },
34   -
35   - baseSize: {
36   - type: Object as PropType<{ w: number; h: number }>
37   - },
38   - autoPlay: {
39   - type: Boolean
40   - },
41   - name: {
42   - type: String
43   - },
44   - avatar: {
45   - type: String
46   - },
47   - w: {
48   - type: Number,
49   - default: 300
50   - },
51   - h: {
52   - type: Number,
53   - default: 300
54   - },
55   - index: {
56   - type: Number
57   - }
58   -})
59   -
60   -
61   -const { getResult } = useFingerprint()
62   -
63   -const showLoading = ref<boolean>(false)
64   -
65   -const sourceSrc = ref<string | null>(props.sourceSrc || '')
66   -
67   -
68   -// video实例对象
69   -const videoPlayer = shallowRef<videojs.Player | null>(null)
70   -const playerContainerElRef = shallowRef<HTMLElement | null>(null)
71   -
72   -const fingerprintResult = ref<Nullable<GetResult>>(null)
73   -
74   -const isRtspProtocol = (url: string) => {
75   - const reg = /^rtsp:\/\//g
76   - return reg.test(url)
77   -}
78   -
79   -const getVideoTypeByUrl = (url = '') => {
80   - if (!url) return;
81   - try {
82   - const { protocol, pathname } = new URL(url)
83   - if (protocol.startsWith('rtsp:')) return VideoPlayerType.flv
84   - const reg = /[^.]\w*$/
85   - const mathValue = pathname.match(reg) || []
86   - const ext = (mathValue[0] as keyof typeof VideoPlayerType) || 'webm'
87   - const type = VideoPlayerType[ext]
88   - return type ? type : VideoPlayerType.webm
89   - } catch (error) {
90   - console.error(error)
91   - return VideoPlayerType.webm
92   - }
93   -}
94   -
95   -
96   -//options配置
97   -const options: VideoJsPlayerOptions & Recordable = {
98   - language: 'zh-CN', // 设置语言
99   - controls: true, // 是否显示控制条
100   - preload: 'auto', // 预加载
101   - autoplay: props.autoPlay ? true : false, // 是否自动播放
102   - fluid: false, // 自适应宽高
103   - poster: props?.avatar || '',
104   - sources: [],
105   - muted: props.autoPlay ? true : false,
106   - userActions: {
107   - hotkeys: true
108   - },
109   - techOrder: ['html5', 'flvjs'],
110   - flvjs: {
111   - mediaDataSource: {
112   - isLive: true,
113   - cors: true,
114   - withCredentials: false,
115   - hasAudio: false
116   - },
117   - config: {
118   - autoCleanupSourceBuffer: true
119   - }
120   - }
121   -}
122   -
123   -
124   -async function getSource() {
125   - fingerprintResult.value = await getResult()
126   - let src = unref(sourceSrc) || ''
127   - if (isRtspProtocol(unref(sourceSrc)!)) {
128   - src = getOpenFlvPlayUrl(src, unref(fingerprintResult)?.visitorId || '')
129   - }
130   - return [
131   - {
132   - type: getVideoTypeByUrl(src),
133   - src
134   - }
135   - ]
136   -}
137   -
138   -//针对萤石云或者海康威视,根据视频id获取播放流地址
139   -const getVideoUrlById = async (id: string) => {
140   - const res = await getVideoUrl(id)
141   - if (!res) return
142   - const { url } = res.data
143   - return url
144   -}
145   -
146   -//针对gbt28181,根据设备id和通道号获取播放流地址
147   -const getVideoControlList = async (deviceId: string, channelId: string) => {
148   - const {
149   - data: { flv }
150   - } = await getVideoControlStart({
151   - deviceId,
152   - channelId
153   - })
154   - return flv
155   -}
156   -
157   -//针对自定义地址,直接获取地址
158   -const getCustomUrl = (url: string) => {
159   - return url
160   -}
161   -
162   -
163   -function createVideoElement() {
164   - if (!unref(playerContainerElRef)) return
165   - unref(playerContainerElRef)!.innerHTML = ''
166   - const video = document.createElement('video')
167   - video.setAttribute('crossOrigin', 'anonymous')
168   - video.style.setProperty('width', '100%')
169   - video.style.setProperty('height', '100%')
170   - video.classList.add('video-js', 'my-video', 'vjs-theme-city', 'vjs-big-play-centered')
171   - unref(playerContainerElRef)?.appendChild(video)
172   - return video
173   -}
174   -
175   -
176   -// 初始化videojs
177   -const createVideoPlayer = async () => {
178   - if (unref(videoPlayer)) dispose()
179   -
180   - options.sources = await getSource()
181   -
182   - if (isRtspProtocol(unref(sourceSrc) || '')) {
183   - options.flvjs = {
184   - ...(options.flvjs || {}),
185   - config: {
186   - headers: {
187   - 'X-Authorization': `Bearer ${isShareMode() ? getShareJwtToken() : getJwtToken()}`
188   - }
189   - }
190   - }
191   - }
192   - const video = createVideoElement()
193   - if (!video) return
194   -
195   - videoPlayer.value = videojs(video!, options) //fix 修复videojs解决直播延时的问题
196   -
197   - videoPlayer.value?.on('timeupdate', function () {
198   - // 计算表最新推流的时间和现在播放器播放推流的时间
199   - let differTime =
200   - (unref(videoPlayer))!.buffered()?.end(0) -
201   - (unref(videoPlayer))!.currentTime() // 差值小于1.5s时根据1倍速进行播放
202   - if (differTime < 1.5) {
203   - videoPlayer.value?.playbackRate(1)
204   - } // 差值大于1.5s小于10s根据1.2倍速进行播放
205   - if (differTime < 10 && differTime > 1.5) {
206   - videoPlayer.value?.playbackRate(1.2)
207   - } // 差值大于10s时进行重新加载直播流
208   - if (differTime > 10) {
209   - createVideoPlayer()
210   - }
211   - })
212   -}
213   -
214   -const getVideosUrl = async () => {
215   - try {
216   - showLoading.value = true
217   - videoPlayer.value?.src('');
218   - const { option } = props || {}
219   - const { accessMode, id, channelId, deviceId, customUrl } = option || {}
220   - if (accessMode === AccessModeEnum.Streaming) {
221   - return await getVideoUrlById(id)
222   - } else if (accessMode === AccessModeEnum.GBT28181) {
223   - return await getVideoControlList(deviceId, channelId)
224   - } else {
225   - return await getCustomUrl(customUrl)
226   - }
227   - } finally {
228   - showLoading.value = false
229   - }
230   -}
231   -
232   -
233   -watch(() => props.option, async () => {
234   - console.log(props, 'prop')
235   - dispose()
236   - sourceSrc.value = await getVideosUrl()
237   - createVideoPlayer()
238   -})
239   -
240   -
241   -
242   -// 销毁
243   -function dispose() {
244   - unref(videoPlayer)?.dispose()
245   - videoPlayer.value = null
246   -}
247   -
248   -watch(
249   - () => props.autoPlay,
250   - async (newData: boolean) => {
251   - if (newData) {
252   - handleVideoPlay()
253   - } else {
254   - videoPlayer.value?.pause()
255   - }
256   - }
257   -)
258   -
259   -onMounted(async () => {
260   - dispose()
261   - sourceSrc.value = await getVideosUrl()
262   - createVideoPlayer()
263   -})
264   -
265   -onUnmounted(() => {
266   - if (props.sourceSrc) {
267   - closeFlvPlay(props.sourceSrc, unref(fingerprintResult)!.visitorId!)
268   - }
269   - handleVideoDispose()
270   -})
271   -
272   -//播放
273   -const handleVideoPlay = () => videoPlayer.value?.play()
274   -
275   -//暂停和销毁
276   -const handleVideoDispose = () => videoPlayer.value?.dispose() && videoPlayer.value?.pause()
277   -
278   -</script>
279   -
280   -<style lang="scss" scoped>
281   -
282   -.go-content-box {
283   - display: flex;
284   - align-items: center;
285   - justify-content: center;
286   -
287   - .my-video {
288   - width: 100% !important;
289   - height: 100% !important;
290   - position: relative;
291   - }
292   -}
293   -</style>
294   -<style>
295   -.vjs-poster {
296   - background-size: 100% !important;
297   -}
298   -</style>
  1 +<script lang="ts" setup>
  2 +import {XGPlayer} from '@/components/Video'
  3 +import {watch, ref} from "vue";
  4 +import {StreamType} from "@/components/Video/src/types";
  5 +import {getPlayUrl} from "@/packages/components/external/Informations/Mores/SingleCamera/config";
  6 +import {CameraRecord} from "@/api/external/common/model";
  7 +
  8 +;
  9 +
  10 +const props = defineProps<{
  11 + dataset?: any
  12 + width: number
  13 + height: number
  14 +}>()
  15 +
  16 +const loading = ref(false)
  17 +const playUrl = ref<string>()
  18 +const playType = ref<StreamType>()
  19 +
  20 +interface Dataset {
  21 + accessMode: number
  22 + autoPlay: boolean
  23 + channelId?: string
  24 + customUrl?: string
  25 + deviceId?: string
  26 + id?: string
  27 + playProtocol?: number
  28 +}
  29 +
  30 +const handleGetPlayUrl = async (dataset: Dataset) => {
  31 + try {
  32 + loading.value = true
  33 + const {id, channelId, deviceId, accessMode, customUrl, playProtocol} = dataset
  34 + if (!accessMode) return
  35 + const {type, url} = await getPlayUrl({
  36 + id: id,
  37 + accessMode: accessMode,
  38 + playProtocol: playProtocol,
  39 + videoUrl: customUrl,
  40 + params: {
  41 + deviceId: deviceId,
  42 + channelNo: channelId,
  43 + },
  44 + } as unknown as CameraRecord)
  45 + playUrl.value = url
  46 + playType.value = type
  47 + } finally {
  48 + loading.value = false
  49 + }
  50 +}
  51 +
  52 +watch(
  53 + () => props.dataset,
  54 + (newData: Dataset) => {
  55 + handleGetPlayUrl(newData)
  56 + },
  57 + {
  58 + immediate: true
  59 + }
  60 +)
  61 +</script>
  62 +
  63 +<template>
  64 + <NSpin :show="loading" class="player-spin">
  65 + <XGPlayer
  66 + :url="playUrl"
  67 + :stream-type="playType"
  68 + :auto-play="dataset.autoPlay"
  69 + :config="{width: width, height: height, poster: dataset.avatar}"
  70 + />
  71 + </NSpin>
  72 +</template>
  73 +
  74 +<style lang="scss" scoped>
  75 +.player-spin {
  76 + width: 100%;
  77 + height: 100%;
  78 + @include deep() {
  79 + .n-spin-content {
  80 + width: 100%;
  81 + height: 100%;
  82 + }
  83 + }
  84 +}
  85 +
  86 +</style>
... ...
1   -import VideoPlay from './VideoPlay.vue'
2   -
3   -export { VideoPlay as default }
... ... @@ -53,6 +53,7 @@ export interface videoList {
53 53 deviceId: string
54 54 customUrl: string
55 55 params: GBT28181Params
  56 + playProtocol?: number
56 57 }
57 58
58 59 export const option = {
... ...
... ... @@ -120,15 +120,16 @@ const handleUpdateTreeValue = (e: string) => {
120 120 const getVideoLists = async (organizationId: string) => {
121 121 const res = await getVideoList({ organizationId })
122 122 if (!res) return
123   - videoOptions.value = res?.data?.map((item: videoList) => ({
  123 + videoOptions.value = res?.data?.map((item) => ({
124 124 label: item.name,
125 125 value: item.id,
126 126 id: item.id,
127 127 accessMode: item.accessMode,
128 128 customUrl: item.accessMode === AccessModeEnum.ManuallyEnter ? item.videoUrl: '', //参数只给自定义视频流使用
129 129 channelId: item.accessMode === AccessModeEnum.GBT28181 ? item?.params?.channelNo : '', //参数只给gbt28181使用
130   - deviceId: item.accessMode === AccessModeEnum.GBT28181 ? item?.params?.deviceId : '' //参数只给gbt28181使用
131   - }))
  130 + deviceId: item.accessMode === AccessModeEnum.GBT28181 ? item?.params?.deviceId : '', //参数只给gbt28181使用
  131 + playProtocol: item?.playProtocol
  132 + } as any))
132 133 }
133 134
134 135 //针对萤石云或者海康威视,根据视频id获取播放流地址
... ...
... ... @@ -2,17 +2,7 @@
2 2 <div @mouseenter="handleMouseenter" @mouseleave="handleMouseleave" class="banner-box" ref="root">
3 3 <div class="wrapper">
4 4 <div v-for="(item, index) in option.dataset" :key="index" :class="item.className" :style="item.sty">
5   - <VideoPlay
6   - :autoPlay="item.autoPlay"
7   - :option="item"
8   - :name="item.name"
9   - :avatar="item.avatar"
10   - :key="item + index"
11   - :sourceSrc="item.url"
12   - :baseSize="{w,h}"
13   - :index="index"
14   - />
15   - <span class="video-title">{{ item.name }}</span>
  5 + <VideoPlayer :key="item + index" :dataset="item" :width="w" :height="h"/>
16 6 </div>
17 7 </div>
18 8 <a v-show="isShowSvg" href="javascript:;" class="left" @click="changeSlide('left')"></a>
... ... @@ -20,11 +10,10 @@
20 10 </div>
21 11 </template>
22 12 <script setup lang="ts" name="index">
23   -import { PropType, watch, toRefs, shallowReactive, onMounted, ref } from 'vue'
24   -import { CreateComponentType } from '@/packages/index.d'
25   -import 'video.js/dist/video-js.min.css'
26   -import { option as typeOption } from './config'
27   -import VideoPlay from './components'
  13 +import {PropType, watch, toRefs, shallowReactive, onMounted, ref} from 'vue'
  14 +import {CreateComponentType} from '@/packages/index.d'
  15 +import {option as typeOption} from './config'
  16 +import VideoPlayer from "@/packages/components/external/Informations/Mores/Camera/components/VideoPlayer.vue";
28 17
29 18 const props = defineProps({
30 19 chartConfig: {
... ... @@ -35,9 +24,9 @@ const props = defineProps({
35 24
36 25 const isShowSvg = ref(false)
37 26
38   -const { w, h } = toRefs(props.chartConfig.attr)
  27 +const {w, h} = toRefs(props.chartConfig.attr)
39 28
40   -const { autoSwitch, interval } = toRefs(props.chartConfig.option)
  29 +const {autoSwitch, interval} = toRefs(props.chartConfig.option)
41 30
42 31 //暂定 any类型
43 32 const option = shallowReactive<{ ['dataset']: any }>({
... ... @@ -50,15 +39,15 @@ const computedFunc = (initial: number, source: Recordable[]) => {
50 39 if (initial < 0) initial = 0
51 40 if (Array.isArray(source)) {
52 41 let len = source.length,
53   - temp1 = initial - 2 < 0 ? initial - 2 + len : initial - 2,
54   - temp2 = initial - 1 < 0 ? initial - 1 + len : initial - 1,
55   - temp3 = initial,
56   - temp4 = initial + 1 >= len ? initial + 1 - len : initial + 1,
57   - temp5 = initial + 2 >= len ? initial + 2 - len : initial + 2
  42 + temp1 = initial - 2 < 0 ? initial - 2 + len : initial - 2,
  43 + temp2 = initial - 1 < 0 ? initial - 1 + len : initial - 1,
  44 + temp3 = initial,
  45 + temp4 = initial + 1 >= len ? initial + 1 - len : initial + 1,
  46 + temp5 = initial + 2 >= len ? initial + 2 - len : initial + 2
58 47 return source?.map((item: Recordable, index: number) => {
59 48 let transform = `translateX(-50%) scale(0.7)`,
60   - zIndex = 0,
61   - className = 'slide'
  49 + zIndex = 0,
  50 + className = 'slide'
62 51 switch (index) {
63 52 case temp3:
64 53 transform = `translateX(-50%) scale(1)`
... ... @@ -93,23 +82,23 @@ const computedFunc = (initial: number, source: Recordable[]) => {
93 82 }
94 83
95 84 watch(
96   - () => props.chartConfig.option.dataset,
97   - newData => {
98   - option.dataset = newData
99   - },
100   - {
101   - immediate: true,
102   - deep: true
103   - }
  85 + () => props.chartConfig.option.dataset,
  86 + newData => {
  87 + option.dataset = newData
  88 + },
  89 + {
  90 + immediate: true,
  91 + deep: true
  92 + }
104 93 )
105 94
106 95 option.dataset = computedFunc(initial.value, option.dataset)
107 96
108 97 watch(
109   - () => initial.value,
110   - newV => {
111   - option.dataset = computedFunc(newV, option.dataset)
112   - }
  98 + () => initial.value,
  99 + newV => {
  100 + option.dataset = computedFunc(newV, option.dataset)
  101 + }
113 102 )
114 103
115 104 // 处理自动轮播
... ... @@ -155,17 +144,17 @@ function changeSlide(dir: string) {
155 144 }
156 145
157 146 watch(
158   - () => autoSwitch.value,
159   - (newV: boolean) => {
160   - if (newV) {
161   - autoPlay()
162   - } else {
163   - clearInterval(timer)
  147 + () => autoSwitch.value,
  148 + (newV: boolean) => {
  149 + if (newV) {
  150 + autoPlay()
  151 + } else {
  152 + clearInterval(timer)
  153 + }
  154 + },
  155 + {
  156 + immediate: true
164 157 }
165   - },
166   - {
167   - immediate: true
168   - }
169 158 )
170 159
171 160 const handleMouseenter = () => {
... ... @@ -181,6 +170,7 @@ const handleMouseleave = () => (isShowSvg.value = false)
181 170 height: 100%;
182 171 display: flex;
183 172 overflow: hidden;
  173 +
184 174 .slide {
185 175 width: 20%;
186 176 height: 100%;
... ... @@ -200,6 +190,7 @@ const handleMouseleave = () => (isShowSvg.value = false)
200 190 }
201 191 }
202 192 }
  193 +
203 194 .arrow {
204 195 position: absolute;
205 196 top: 50%;
... ... @@ -211,11 +202,13 @@ const handleMouseleave = () => (isShowSvg.value = false)
211 202 background-color: white;
212 203 opacity: 0.5;
213 204 }
  205 +
214 206 a.left {
215 207 @extend .arrow;
216 208 background-image: url('./static/left.svg');
217 209 left: 0px;
218 210 }
  211 +
219 212 a.right {
220 213 @extend .arrow;
221 214 background-image: url('./static/right.svg');
... ...
1   -<template>
2   - <div ref="playerContainerElRef" class="go-content-box"
3   - :style="{ width: baseSize?.w + 'px', height: baseSize?.h + 'px', background: '#000' }">
4   -
5   - </div>
6   -</template>
7   -<script setup lang="ts">
8   -import { ref, onUnmounted, watch, unref, PropType, shallowRef } from 'vue'
9   -import videojs from 'video.js'
10   -import 'videojs-flvjs-es6'
11   -import type { VideoJsPlayerOptions } from 'video.js'
12   -import 'video.js/dist/video-js.min.css'
13   -import { getJwtToken, getShareJwtToken } from '@/utils/external/auth'
14   -import { isShareMode } from '@/views/share/hook'
15   -import { getOpenFlvPlayUrl, closeFlvPlay } from '@/api/external/flvPlay'
16   -import { useFingerprint } from '@/utils/external/useFingerprint'
17   -import { GetResult } from '@fingerprintjs/fingerprintjs'
18   -import { VideoPlayerTypeEnum } from '../config'
19   -
20   -const props = defineProps({
21   - sourceSrc: {
22   - type: String
23   - },
24   - autoPlay: {
25   - type: Boolean
26   - },
27   - name: {
28   - type: String
29   - },
30   - avatar: {
31   - type: String
32   - },
33   - baseSize: {
34   - type: Object as PropType<{ w: number; h: number }>
35   - }
36   -})
37   -
38   -const isRtspProtocol = (url: string) => {
39   - const reg = /^rtsp:\/\//g
40   - return reg.test(url)
41   -}
42   -
43   -const getVideoTypeByUrl = (url = '') => {
44   - if (!url) return;
45   - try {
46   - const { protocol, pathname } = new URL(url)
47   - if (protocol.startsWith('rtsp:')) return VideoPlayerTypeEnum.flv
48   - const reg = /[^.]\w*$/
49   - const mathValue = pathname.match(reg) || []
50   - const ext = (mathValue[0] as keyof typeof VideoPlayerTypeEnum) || 'webm'
51   - const type = VideoPlayerTypeEnum[ext]
52   - return type ? type : VideoPlayerTypeEnum.webm
53   - } catch (error) {
54   - console.error(error)
55   - return VideoPlayerTypeEnum.webm
56   - }
57   -}
58   -
59   -// video实例对象
60   -const videoPlayer = shallowRef<videojs.Player | null>(null)
61   -const playerContainerElRef = shallowRef<HTMLElement | null>(null)
62   -
63   -const fingerprintResult = ref<Nullable<GetResult>>(null)
64   -
65   -//options配置
66   -const options: VideoJsPlayerOptions & Recordable = {
67   - language: 'zh-CN', // 设置语言
68   - controls: true, // 是否显示控制条
69   - autoplay: !!props.autoPlay, // 是否自动播放
70   - fluid: false, // 自适应宽高
71   - poster: props?.avatar || '',
72   - sources: [],
73   - muted: !!props.autoPlay,
74   - userActions: {
75   - hotkeys: true
76   - },
77   - techOrder: ['html5', 'flvjs'],
78   - flvjs: {
79   - mediaDataSource: {
80   - isLive: true,
81   - cors: true,
82   - withCredentials: false,
83   - hasAudio: false
84   - },
85   - config: {
86   - autoCleanupSourceBuffer: true
87   - }
88   - }
89   -}
90   -
91   -const { getResult } = useFingerprint()
92   -
93   -async function getSource() {
94   - fingerprintResult.value = await getResult()
95   - let src = props.sourceSrc || ''
96   - if (isRtspProtocol(props.sourceSrc!)) {
97   - src = getOpenFlvPlayUrl(src, unref(fingerprintResult)?.visitorId || '')
98   - }
99   - return [
100   - {
101   - type: getVideoTypeByUrl(props.sourceSrc),
102   - src
103   - }
104   - ]
105   -}
106   -
107   -function createVideoElement() {
108   - if (!unref(playerContainerElRef)) return
109   - unref(playerContainerElRef)!.innerHTML = ''
110   - const video = document.createElement('video')
111   - video.setAttribute('crossOrigin', 'anonymous')
112   - video.style.setProperty('width', '100%')
113   - video.style.setProperty('height', '100%')
114   - video.classList.add('video-js', 'my-video', 'vjs-theme-city', 'vjs-big-play-centered')
115   - unref(playerContainerElRef)?.appendChild(video)
116   - return video
117   -}
118   -
119   -
120   -// 初始化videojs
121   -const createVideoPlayer = async () => {
122   - if (unref(videoPlayer)) dispose()
123   -
124   - options.sources = await getSource()
125   -
126   - if (isRtspProtocol(props.sourceSrc || '')) {
127   - options.flvjs = {
128   - ...(options.flvjs || {}),
129   - config: {
130   - headers: {
131   - 'X-Authorization': `Bearer ${isShareMode() ? getShareJwtToken() : getJwtToken()}`
132   - }
133   - }
134   - }
135   - }
136   - const video = createVideoElement()
137   - if (!video) return
138   -
139   - videoPlayer.value = videojs(video!, options) //fix 修复videojs解决直播延时的问题
140   -
141   - videoPlayer.value?.on('timeupdate', function () {
142   - // 计算表最新推流的时间和现在播放器播放推流的时间
143   - let differTime =
144   - (unref(videoPlayer))!.buffered()?.end(0) -
145   - (unref(videoPlayer))!.currentTime() // 差值小于1.5s时根据1倍速进行播放
146   - if (differTime < 1.5) {
147   - videoPlayer.value?.playbackRate(1)
148   - } // 差值大于1.5s小于10s根据1.2倍速进行播放
149   - if (differTime < 10 && differTime > 1.5) {
150   - videoPlayer.value?.playbackRate(1.2)
151   - } // 差值大于10s时进行重新加载直播流
152   - if (differTime > 10) {
153   - createVideoPlayer()
154   - }
155   - })
156   -}
157   -
158   -// watch(
159   -// () => props.sourceSrc,
160   -// async () => {
161   -// (props as any ).sourceSrc = ''
162   -// if(!props.sourceSrc) return;
163   -// await nextTick();
164   -// if(unref(fingerprintResult)!.visitorId!) {
165   -// closeFlvPlay(props.sourceSrc!, unref(fingerprintResult)!.visitorId!)
166   -// }
167   -// videoPlayer.value?.src('');
168   -// createVideoPlayer()
169   -
170   -// if (props.sourceSrc) {
171   -// reloadSource({ src: props.sourceSrc, type: getVideoTypeByUrl(props.sourceSrc) })
172   -// }
173   -// }
174   -// )
175   -
176   -watch(
177   - () => props.autoPlay,
178   - async (newData: boolean) => {
179   - if (newData) {
180   - handleVideoPlay()
181   - } else {
182   - videoPlayer.value?.pause()
183   - }
184   - },
185   -)
186   -
187   -// onMounted(() => {
188   -// createVideoPlayer()
189   -// })
190   -
191   -onUnmounted(() => {
192   - if (props.sourceSrc) {
193   - closeFlvPlay(props.sourceSrc, unref(fingerprintResult)!.visitorId!)
194   - }
195   - handleVideoDispose()
196   -})
197   -
198   -
199   -function anewInit() {
200   - createVideoPlayer()
201   -}
202   -
203   -function reloadSource(sources: string | videojs.Tech.SourceObject | videojs.Tech.SourceObject[]) {
204   - if (!unref(videoPlayer)) return
205   - unref(videoPlayer)?.pause()
206   - unref(videoPlayer)?.src(sources)
207   - unref(videoPlayer)?.load()
208   - unref(videoPlayer)?.play()
209   -}
210   -
211   -function dispose() {
212   - unref(videoPlayer)?.dispose()
213   - videoPlayer.value = null
214   -}
215   -
216   -//播放
217   -const handleVideoPlay = () => videoPlayer.value?.play()
218   -
219   -//暂停和销毁
220   -const handleVideoDispose = () => videoPlayer.value?.dispose()
221   -
222   -defineExpose({
223   - dispose,
224   - reloadSource,
225   - anewInit,
226   -})
227   -
228   -</script>
229   -
230   -<style lang="scss" scoped>
231   -.go-content-box {
232   - display: flex;
233   - align-items: center;
234   - justify-content: center;
235   -
236   - .my-video {
237   - width: 100% !important;
238   - height: 100% !important;
239   - position: relative;
240   - }
241   -}
242   -</style>
243   -<style>
244   -.vjs-poster {
245   - background-size: 100% !important;
246   -}
247   -</style>
1   -import VideoPlay from './VideoPlay.vue'
2   -
3   -export { VideoPlay }
... ... @@ -2,6 +2,11 @@ import { PublicConfigClass } from '@/packages/public'
2 2 import { CreateComponentType } from '@/packages/index.d'
3 3 import { SingleCameraConfig } from './index'
4 4 import cloneDeep from 'lodash/cloneDeep'
  5 +import {StreamType} from "@/components/Video/src/types";
  6 +import {useFingerprint} from "@/utils/external/useFingerprint";
  7 +import {getOpenFlvPlayUrl, getVideoControlStart} from "@/api/external/flvPlay";
  8 +import {getVideoUrl} from "@/api/external/common";
  9 +import {CameraRecord} from "@/api/external/common/model";
5 10
6 11 export enum sourceTypeEnum {
7 12 CUSTOM = 'custom',
... ... @@ -13,6 +18,11 @@ export enum sourceTypeNameEnum {
13 18 PLATFORM = '平台获取'
14 19 }
15 20
  21 +export enum FluoriteMideaProtocolEnum {
  22 + HLS = 2,
  23 + FLV = 4,
  24 +}
  25 +
16 26 export enum VideoPlayerTypeEnum {
17 27 m3u8 = 'application/x-mpegURL',
18 28 mp4 = 'video/mp4',
... ... @@ -32,6 +42,7 @@ export interface videoListInterface {
32 42 deviceId: string
33 43 customUrl: string
34 44 params: GBT28181Params
  45 + playProtocol?: number
35 46 }
36 47
37 48 export interface GBT28181Params {
... ... @@ -53,6 +64,7 @@ export interface Dataset {
53 64 deviceId?: string
54 65 id?: string
55 66 value?: string
  67 + playProtocol?: number
56 68 }
57 69
58 70 export const option = {
... ... @@ -70,3 +82,42 @@ export default class Config extends PublicConfigClass implements CreateComponent
70 82 public chartConfig = cloneDeep(SingleCameraConfig)
71 83 public option = cloneDeep(option)
72 84 }
  85 +
  86 +export const isRtspProtocol = (url: string) => {
  87 + const reg = /^rtsp:\/\//g;
  88 + return reg.test(url);
  89 +};
  90 +
  91 +export async function getPlayUrl(
  92 + params: CameraRecord
  93 +): Promise<{ url: string; type: StreamType }> {
  94 + const { accessMode } = params;
  95 + if (accessMode === AccessMode.ManuallyEnter) {
  96 + const { videoUrl } = params;
  97 + if (params.videoUrl) {
  98 + const isRTSPPlay = isRtspProtocol(videoUrl);
  99 +
  100 + if (isRTSPPlay) {
  101 + const { getResult } = useFingerprint();
  102 + const fingerprint = await getResult();
  103 + return { url: getOpenFlvPlayUrl(videoUrl, fingerprint.visitorId), type: 'flv' };
  104 + } else {
  105 + return { url: videoUrl, type: 'auto' };
  106 + }
  107 + }
  108 + } else if (accessMode === AccessMode.GBT28181) {
  109 + const { deviceId, channelNo } = params?.params || {};
  110 + const result = await getVideoControlStart({ channelId: channelNo!, deviceId: deviceId! });
  111 + return { url: result.data.flv, type: 'flv' };
  112 + } else {
  113 + const { id, playProtocol } = params;
  114 + const result = await getVideoUrl(id);
  115 + const type: StreamType =
  116 + playProtocol === FluoriteMideaProtocolEnum.FLV
  117 + ? 'flv'
  118 + : playProtocol === FluoriteMideaProtocolEnum.HLS
  119 + ? 'hls'
  120 + : 'auto';
  121 + return { url: result.data.url, type };
  122 + }
  123 +}
... ...
... ... @@ -97,7 +97,7 @@ const handleUpdateTreeValue = (value: string) => {
97 97 const getVideoLists = async (organizationId: string) => {
98 98 const res = await getVideoList({ organizationId })
99 99 if (!res) return
100   - videoOptions.value = res?.data?.map((item: videoListInterface) => {
  100 + videoOptions.value = res?.data?.map((item) => {
101 101 return {
102 102 label: item.name,
103 103 value: item.id,
... ... @@ -105,8 +105,9 @@ const getVideoLists = async (organizationId: string) => {
105 105 id: item.id,
106 106 accessMode: item.accessMode,
107 107 channelId: item.accessMode === AccessMode.GBT28181 ? item?.params?.channelNo : '', //参数只给gbt28181使用
108   - deviceId: item.accessMode === AccessMode.GBT28181 ? item?.params?.deviceId : '' //参数只给gbt28181使用
109   - }
  108 + deviceId: item.accessMode === AccessMode.GBT28181 ? item?.params?.deviceId : '', //参数只给gbt28181使用
  109 + playProtocol: item?.playProtocol
  110 + } as any
110 111 })
111 112 }
112 113
... ...
1 1 <template>
2 2 <div>
3   - <n-spin size="medium" :show="showLoading" :content-style="{ background: 'red' }">
4   - <template #description> 视频正在努力加载中...... </template>
5   - <div>
6   - <VideoPlay ref="videoPlayerRef" :baseSize="{ w, h }" :sourceSrc="sourceUrl" :autoPlay="option.autoplay"
7   - :avatar="option.poster" />
8   - </div>
  3 + <n-spin size="medium" :show="showLoading" class="player-spin">
  4 + <template #description> 视频正在努力加载中......</template>
  5 + <XGPlayer :url="sourceUrl" :stream-type="playType"
  6 + :config="{width: '100%', height: '100%', poster: option.poster}"
  7 + :auto-play="option.autoplay"/>
9 8 </n-spin>
10 9 </div>
11 10 </template>
12 11 <script setup lang="ts">
13   -import { PropType, toRefs, shallowReactive, watch, ref } from 'vue'
14   -import { CreateComponentType } from '@/packages/index.d'
15   -import { AccessMode, Dataset, option as configOption, sourceTypeEnum } from './config'
16   -import { VideoPlay } from './components'
17   -import { getVideoControlStart } from '@/api/external/flvPlay'
18   -import { getVideoUrl } from '@/api/external/common'
  12 +import {PropType, toRefs, shallowReactive, watch, ref} from 'vue'
  13 +import {CreateComponentType} from '@/packages/index.d'
  14 +import {Dataset, getPlayUrl, option as configOption} from './config'
  15 +import {XGPlayer} from '@/components/Video'
  16 +import {StreamType} from "@/components/Video/src/types";
  17 +import {CameraRecord} from "@/api/external/common/model";
19 18
20 19 const props = defineProps({
21 20 chartConfig: {
... ... @@ -26,9 +25,9 @@ const props = defineProps({
26 25
27 26 const showLoading = ref(false)
28 27
29   -const { w, h } = toRefs(props.chartConfig.attr)
  28 +const {w, h} = toRefs(props.chartConfig.attr)
30 29
31   -const { autoplay, dataset, poster, customVideoUrl } = toRefs(props.chartConfig.option as typeof configOption)
  30 +const {autoplay, dataset, poster, customVideoUrl} = toRefs(props.chartConfig.option as typeof configOption)
32 31
33 32 const option = shallowReactive({
34 33 dataset: configOption.dataset,
... ... @@ -37,87 +36,52 @@ const option = shallowReactive({
37 36 })
38 37
39 38 const sourceUrl = ref('')
40   -const videoPlayerRef = ref<InstanceType<typeof VideoPlay> | null>()
41   -
42   -// 针对萤石云或者海康威视,根据视频id获取播放流地址
43   -const getVideoUrlById = async (id: string) => {
44   - const res = await getVideoUrl(id)
45   - if (!res) return
46   - const { url } = res.data
47   - return url
48   -}
49   -
50   -// 针对gbt28181,根据设备id和通道号获取播放流地址
51   -const getVideoControlList = async (deviceId: string, channelId: string) => {
52   - const {
53   - data: { flv }
54   - } = await getVideoControlStart({
55   - deviceId,
56   - channelId
57   - })
58   - return flv
59   -}
60   -
61   -// 针对自定义地址,直接获取地址
62   -const getCustomUrl = (url: string) => {
63   - return url
64   -}
  39 +const playType = ref<StreamType>()
65 40
66 41
67 42 async function getPlaySource(params: Dataset) {
68 43 try {
69 44 showLoading.value = true
70   -
71   - const { accessMode, id, deviceId, channelId, customUrl } = params
72   - if (accessMode === AccessMode.Streaming && id) {
73   - return await getVideoUrlById(id!)
74   - } else if (accessMode === AccessMode.GBT28181 && deviceId && channelId) {
75   - return await getVideoControlList(deviceId!, channelId!)
76   - } else {
77   - return getCustomUrl(customUrl!)
78   - }
  45 + const {id, channelId, deviceId, accessMode, customUrl, playProtocol} = params
  46 + if (!accessMode) return
  47 + const {type, url} = await getPlayUrl({
  48 + id: id,
  49 + accessMode: accessMode,
  50 + playProtocol: playProtocol,
  51 + videoUrl: customUrl,
  52 + params: {
  53 + deviceId: deviceId,
  54 + channelNo: channelId,
  55 + },
  56 + } as unknown as CameraRecord)
  57 + sourceUrl.value = url
  58 + playType.value = type
79 59 } finally {
80 60 showLoading.value = false
81 61 }
82 62 }
83 63
84 64 watch(
85   - () => dataset?.value,
86   - async (newData) => {
87   - videoPlayerRef.value?.dispose()
88   - sourceUrl.value = await getPlaySource(newData)
89   - videoPlayerRef.value?.anewInit()
90   - },
91   - {
92   - immediate: true
93   - }
94   -)
95   -
96   -watch(
97   - () => customVideoUrl.value,
98   - (newData) => {
99   - if(newData){
100   - videoPlayerRef.value?.dispose()
101   - sourceUrl.value = newData;
102   - videoPlayerRef.value?.anewInit()
  65 + () => dataset?.value,
  66 + async (newData) => {
  67 + getPlaySource(newData)
  68 + },
  69 + {
  70 + immediate: true
103 71 }
104   - },
105   - {
106   - immediate: true
107   - }
108 72 )
109 73
110   -watch(
111   - () => [poster.value, autoplay.value],
112   - newData => {
113   - option.poster = newData.at(-2) as string
114   - option.autoplay = newData.at(-1) as boolean
115   - },
116   - {
117   - immediate: true
118   - }
119   -)
120 74 </script>
121 75
122 76 <style lang="scss" scoped>
  77 +.player-spin {
  78 + width: 100%;
  79 + height: 100%;
  80 + @include deep() {
  81 + .n-spin-content {
  82 + width: 100%;
  83 + height: 100%;
  84 + }
  85 + }
  86 +}
123 87 </style>
... ...