Commit a699aedcfbdf42359c72a6ca0029aa5fea7b0146
Merge branch 'main_dev' into 'main'
Main dev See merge request yunteng/thingskit-view!232
Showing
25 changed files
with
909 additions
and
828 deletions
| @@ -57,7 +57,11 @@ | @@ -57,7 +57,11 @@ | ||
| 57 | "vue-router": "4.0.12", | 57 | "vue-router": "4.0.12", |
| 58 | "vue3-lazyload": "^0.2.5-beta", | 58 | "vue3-lazyload": "^0.2.5-beta", |
| 59 | "vue3-sketch-ruler": "^1.3.3", | 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 | "devDependencies": { | 66 | "devDependencies": { |
| 63 | "@commitlint/cli": "^17.0.2", | 67 | "@commitlint/cli": "^17.0.2", |
| 1 | -lockfileVersion: '6.1' | 1 | +lockfileVersion: '6.0' |
| 2 | 2 | ||
| 3 | settings: | 3 | settings: |
| 4 | autoInstallPeers: true | 4 | autoInstallPeers: true |
| @@ -11,6 +11,9 @@ dependencies: | @@ -11,6 +11,9 @@ dependencies: | ||
| 11 | '@amap/amap-jsapi-types': | 11 | '@amap/amap-jsapi-types': |
| 12 | specifier: ^0.0.8 | 12 | specifier: ^0.0.8 |
| 13 | version: 0.0.8 | 13 | version: 0.0.8 |
| 14 | + '@fingerprintjs/fingerprintjs': | ||
| 15 | + specifier: ^3.4.1 | ||
| 16 | + version: 3.4.2 | ||
| 14 | '@types/color': | 17 | '@types/color': |
| 15 | specifier: ^3.0.3 | 18 | specifier: ^3.0.3 |
| 16 | version: 3.0.3 | 19 | version: 3.0.3 |
| @@ -41,6 +44,9 @@ dependencies: | @@ -41,6 +44,9 @@ dependencies: | ||
| 41 | dom-helpers: | 44 | dom-helpers: |
| 42 | specifier: ^5.2.1 | 45 | specifier: ^5.2.1 |
| 43 | version: 5.2.1 | 46 | version: 5.2.1 |
| 47 | + echarts-gl: | ||
| 48 | + specifier: ^2.0.9 | ||
| 49 | + version: 2.0.9(echarts@5.3.3) | ||
| 44 | echarts-liquidfill: | 50 | echarts-liquidfill: |
| 45 | specifier: ^3.1.0 | 51 | specifier: ^3.1.0 |
| 46 | version: 3.1.0(echarts@5.3.3) | 52 | version: 3.1.0(echarts@5.3.3) |
| @@ -50,6 +56,9 @@ dependencies: | @@ -50,6 +56,9 @@ dependencies: | ||
| 50 | echarts-wordcloud: | 56 | echarts-wordcloud: |
| 51 | specifier: ^2.0.0 | 57 | specifier: ^2.0.0 |
| 52 | version: 2.0.0(echarts@5.3.3) | 58 | version: 2.0.0(echarts@5.3.3) |
| 59 | + flv.js: | ||
| 60 | + specifier: ^1.6.2 | ||
| 61 | + version: 1.6.2 | ||
| 53 | gsap: | 62 | gsap: |
| 54 | specifier: ^3.11.3 | 63 | specifier: ^3.11.3 |
| 55 | version: 3.11.3 | 64 | version: 3.11.3 |
| @@ -89,6 +98,9 @@ dependencies: | @@ -89,6 +98,9 @@ dependencies: | ||
| 89 | video.js: | 98 | video.js: |
| 90 | specifier: ^7.20.3 | 99 | specifier: ^7.20.3 |
| 91 | version: 7.21.4 | 100 | version: 7.21.4 |
| 101 | + videojs-flvjs-es6: | ||
| 102 | + specifier: ^1.0.1 | ||
| 103 | + version: 1.0.1 | ||
| 92 | vue: | 104 | vue: |
| 93 | specifier: ^3.2.31 | 105 | specifier: ^3.2.31 |
| 94 | version: 3.2.37 | 106 | version: 3.2.37 |
| @@ -113,6 +125,18 @@ dependencies: | @@ -113,6 +125,18 @@ dependencies: | ||
| 113 | vuedraggable: | 125 | vuedraggable: |
| 114 | specifier: ^4.1.0 | 126 | specifier: ^4.1.0 |
| 115 | version: 4.1.0(vue@3.2.37) | 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 | devDependencies: | 141 | devDependencies: |
| 118 | '@commitlint/cli': | 142 | '@commitlint/cli': |
| @@ -1158,6 +1182,12 @@ packages: | @@ -1158,6 +1182,12 @@ packages: | ||
| 1158 | - supports-color | 1182 | - supports-color |
| 1159 | dev: true | 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 | /@humanwhocodes/config-array@0.9.5: | 1191 | /@humanwhocodes/config-array@0.9.5: |
| 1162 | resolution: {integrity: sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==} | 1192 | resolution: {integrity: sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==} |
| 1163 | engines: {node: '>=10.10.0'} | 1193 | engines: {node: '>=10.10.0'} |
| @@ -2409,6 +2439,10 @@ packages: | @@ -2409,6 +2439,10 @@ packages: | ||
| 2409 | engines: {node: '>=6.0'} | 2439 | engines: {node: '>=6.0'} |
| 2410 | dev: true | 2440 | dev: true |
| 2411 | 2441 | ||
| 2442 | + /claygl@1.3.0: | ||
| 2443 | + resolution: {integrity: sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ==} | ||
| 2444 | + dev: false | ||
| 2445 | + | ||
| 2412 | /clean-css@5.3.2: | 2446 | /clean-css@5.3.2: |
| 2413 | resolution: {integrity: sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==} | 2447 | resolution: {integrity: sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==} |
| 2414 | engines: {node: '>= 10.0'} | 2448 | engines: {node: '>= 10.0'} |
| @@ -2540,6 +2574,12 @@ packages: | @@ -2540,6 +2574,12 @@ packages: | ||
| 2540 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} | 2574 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} |
| 2541 | dev: true | 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 | /connect-history-api-fallback@1.6.0: | 2583 | /connect-history-api-fallback@1.6.0: |
| 2544 | resolution: {integrity: sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==} | 2584 | resolution: {integrity: sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==} |
| 2545 | engines: {node: '>=0.8'} | 2585 | engines: {node: '>=0.8'} |
| @@ -2605,6 +2645,11 @@ packages: | @@ -2605,6 +2645,11 @@ packages: | ||
| 2605 | safe-buffer: 5.1.2 | 2645 | safe-buffer: 5.1.2 |
| 2606 | dev: true | 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 | /cosmiconfig-typescript-loader@2.0.1(@types/node@17.0.43)(cosmiconfig@7.0.1)(typescript@4.7.3): | 2653 | /cosmiconfig-typescript-loader@2.0.1(@types/node@17.0.43)(cosmiconfig@7.0.1)(typescript@4.7.3): |
| 2609 | resolution: {integrity: sha512-B9s6sX/omXq7I6gC6+YgLmrBFMJhPWew7ty/X5Tuwtd2zOSgWaUdXjkuVwbe3qqcdETo60+1nSVMekq//LIXVA==} | 2654 | resolution: {integrity: sha512-B9s6sX/omXq7I6gC6+YgLmrBFMJhPWew7ty/X5Tuwtd2zOSgWaUdXjkuVwbe3qqcdETo60+1nSVMekq//LIXVA==} |
| 2610 | engines: {node: '>=12', npm: '>=6'} | 2655 | engines: {node: '>=12', npm: '>=6'} |
| @@ -2646,6 +2691,10 @@ packages: | @@ -2646,6 +2691,10 @@ packages: | ||
| 2646 | which: 2.0.2 | 2691 | which: 2.0.2 |
| 2647 | dev: true | 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 | /crypto-js@4.1.1: | 2698 | /crypto-js@4.1.1: |
| 2650 | resolution: {integrity: sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==} | 2699 | resolution: {integrity: sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==} |
| 2651 | dev: false | 2700 | dev: false |
| @@ -2692,6 +2741,20 @@ packages: | @@ -2692,6 +2741,20 @@ packages: | ||
| 2692 | resolution: {integrity: sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==} | 2741 | resolution: {integrity: sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==} |
| 2693 | dev: false | 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 | /dargs@7.0.0: | 2758 | /dargs@7.0.0: |
| 2696 | resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==} | 2759 | resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==} |
| 2697 | engines: {node: '>=8'} | 2760 | engines: {node: '>=8'} |
| @@ -2765,6 +2828,11 @@ packages: | @@ -2765,6 +2828,11 @@ packages: | ||
| 2765 | resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} | 2828 | resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} |
| 2766 | dev: true | 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 | /deepmerge@4.2.2: | 2836 | /deepmerge@4.2.2: |
| 2769 | resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==} | 2837 | resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==} |
| 2770 | engines: {node: '>=0.10.0'} | 2838 | engines: {node: '>=0.10.0'} |
| @@ -2807,6 +2875,10 @@ packages: | @@ -2807,6 +2875,10 @@ packages: | ||
| 2807 | engines: {node: '>=0.4.0'} | 2875 | engines: {node: '>=0.4.0'} |
| 2808 | dev: false | 2876 | dev: false |
| 2809 | 2877 | ||
| 2878 | + /delegate@3.2.0: | ||
| 2879 | + resolution: {integrity: sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==} | ||
| 2880 | + dev: false | ||
| 2881 | + | ||
| 2810 | /detect-file@1.0.0: | 2882 | /detect-file@1.0.0: |
| 2811 | resolution: {integrity: sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==} | 2883 | resolution: {integrity: sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==} |
| 2812 | engines: {node: '>=0.10.0'} | 2884 | engines: {node: '>=0.10.0'} |
| @@ -2900,6 +2972,20 @@ packages: | @@ -2900,6 +2972,20 @@ packages: | ||
| 2900 | engines: {node: '>=12'} | 2972 | engines: {node: '>=12'} |
| 2901 | dev: true | 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 | /echarts-liquidfill@3.1.0(echarts@5.3.3): | 2989 | /echarts-liquidfill@3.1.0(echarts@5.3.3): |
| 2904 | resolution: {integrity: sha512-5Dlqs/jTsdTUAsd+K5LPLLTgrbbNORUSBQyk8PSy1Mg2zgHDWm83FmvA4s0ooNepCJojFYRITTQ4GU1UUSKYLw==} | 2990 | resolution: {integrity: sha512-5Dlqs/jTsdTUAsd+K5LPLLTgrbbNORUSBQyk8PSy1Mg2zgHDWm83FmvA4s0ooNepCJojFYRITTQ4GU1UUSKYLw==} |
| 2905 | peerDependencies: | 2991 | peerDependencies: |
| @@ -3021,6 +3107,37 @@ packages: | @@ -3021,6 +3107,37 @@ packages: | ||
| 3021 | is-symbol: 1.0.4 | 3107 | is-symbol: 1.0.4 |
| 3022 | dev: true | 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 | /esbuild@0.11.3: | 3141 | /esbuild@0.11.3: |
| 3025 | resolution: {integrity: sha512-BzVRHcCtFepjS9WcqRjqoIxLqgpK21a8J4Zi4msSGxDxiXVO1IbcqT1KjhdDDnJxKfe7bvzZrvMEX+bVO0Elcw==} | 3142 | resolution: {integrity: sha512-BzVRHcCtFepjS9WcqRjqoIxLqgpK21a8J4Zi4msSGxDxiXVO1IbcqT1KjhdDDnJxKfe7bvzZrvMEX+bVO0Elcw==} |
| 3026 | hasBin: true | 3143 | hasBin: true |
| @@ -3265,6 +3382,16 @@ packages: | @@ -3265,6 +3382,16 @@ packages: | ||
| 3265 | - supports-color | 3382 | - supports-color |
| 3266 | dev: true | 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 | /espree@9.3.2: | 3395 | /espree@9.3.2: |
| 3269 | resolution: {integrity: sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==} | 3396 | resolution: {integrity: sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==} |
| 3270 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} | 3397 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} |
| @@ -3310,6 +3437,17 @@ packages: | @@ -3310,6 +3437,17 @@ packages: | ||
| 3310 | engines: {node: '>=0.10.0'} | 3437 | engines: {node: '>=0.10.0'} |
| 3311 | dev: true | 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 | /events@3.3.0: | 3451 | /events@3.3.0: |
| 3314 | resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} | 3452 | resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} |
| 3315 | engines: {node: '>=0.8.x'} | 3453 | engines: {node: '>=0.8.x'} |
| @@ -3341,6 +3479,12 @@ packages: | @@ -3341,6 +3479,12 @@ packages: | ||
| 3341 | homedir-polyfill: 1.0.3 | 3479 | homedir-polyfill: 1.0.3 |
| 3342 | dev: true | 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 | /extend@3.0.2: | 3488 | /extend@3.0.2: |
| 3345 | resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} | 3489 | resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} |
| 3346 | dev: true | 3490 | dev: true |
| @@ -3490,6 +3634,13 @@ packages: | @@ -3490,6 +3634,13 @@ packages: | ||
| 3490 | resolution: {integrity: sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==} | 3634 | resolution: {integrity: sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==} |
| 3491 | dev: true | 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 | /follow-redirects@1.15.1: | 3644 | /follow-redirects@1.15.1: |
| 3494 | resolution: {integrity: sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==} | 3645 | resolution: {integrity: sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==} |
| 3495 | engines: {node: '>=4.0'} | 3646 | engines: {node: '>=4.0'} |
| @@ -4590,6 +4741,10 @@ packages: | @@ -4590,6 +4741,10 @@ packages: | ||
| 4590 | resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} | 4741 | resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} |
| 4591 | dev: true | 4742 | dev: true |
| 4592 | 4743 | ||
| 4744 | + /next-tick@1.1.0: | ||
| 4745 | + resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} | ||
| 4746 | + dev: false | ||
| 4747 | + | ||
| 4593 | /no-case@3.0.4: | 4748 | /no-case@3.0.4: |
| 4594 | resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} | 4749 | resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} |
| 4595 | dependencies: | 4750 | dependencies: |
| @@ -5732,6 +5887,10 @@ packages: | @@ -5732,6 +5887,10 @@ packages: | ||
| 5732 | resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} | 5887 | resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} |
| 5733 | dev: true | 5888 | dev: true |
| 5734 | 5889 | ||
| 5890 | + /tslib@2.6.2: | ||
| 5891 | + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} | ||
| 5892 | + dev: false | ||
| 5893 | + | ||
| 5735 | /tsutils@3.21.0(typescript@4.6.3): | 5894 | /tsutils@3.21.0(typescript@4.6.3): |
| 5736 | resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} | 5895 | resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} |
| 5737 | engines: {node: '>= 6'} | 5896 | engines: {node: '>= 6'} |
| @@ -5774,6 +5933,10 @@ packages: | @@ -5774,6 +5933,10 @@ packages: | ||
| 5774 | engines: {node: '>=8'} | 5933 | engines: {node: '>=8'} |
| 5775 | dev: true | 5934 | dev: true |
| 5776 | 5935 | ||
| 5936 | + /type@2.7.2: | ||
| 5937 | + resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==} | ||
| 5938 | + dev: false | ||
| 5939 | + | ||
| 5777 | /typescript@4.6.3: | 5940 | /typescript@4.6.3: |
| 5778 | resolution: {integrity: sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==} | 5941 | resolution: {integrity: sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==} |
| 5779 | engines: {node: '>=4.2.0'} | 5942 | engines: {node: '>=4.2.0'} |
| @@ -5912,6 +6075,10 @@ packages: | @@ -5912,6 +6075,10 @@ packages: | ||
| 5912 | videojs-vtt.js: 0.15.4 | 6075 | videojs-vtt.js: 0.15.4 |
| 5913 | dev: false | 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 | /videojs-font@3.2.0: | 6082 | /videojs-font@3.2.0: |
| 5916 | resolution: {integrity: sha512-g8vHMKK2/JGorSfqAZQUmYYNnXmfec4MLhwtEFS+mMs2IDY398GLysy6BH6K+aS1KMNu/xWZ8Sue/X/mdQPliA==} | 6083 | resolution: {integrity: sha512-g8vHMKK2/JGorSfqAZQUmYYNnXmfec4MLhwtEFS+mMs2IDY398GLysy6BH6K+aS1KMNu/xWZ8Sue/X/mdQPliA==} |
| 5917 | dev: false | 6084 | dev: false |
| @@ -6261,6 +6428,10 @@ packages: | @@ -6261,6 +6428,10 @@ packages: | ||
| 6261 | - uglify-js | 6428 | - uglify-js |
| 6262 | dev: true | 6429 | dev: true |
| 6263 | 6430 | ||
| 6431 | + /webworkify-webpack@2.1.5: | ||
| 6432 | + resolution: {integrity: sha512-2akF8FIyUvbiBBdD+RoHpoTbHMQF2HwjcxfDvgztAX5YwbZNyrtfUMgvfgFVsgDhDPVTlkbb5vyasqDHfIDPQw==} | ||
| 6433 | + dev: false | ||
| 6434 | + | ||
| 6264 | /which-boxed-primitive@1.0.2: | 6435 | /which-boxed-primitive@1.0.2: |
| 6265 | resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} | 6436 | resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} |
| 6266 | dependencies: | 6437 | dependencies: |
| @@ -6308,6 +6479,101 @@ packages: | @@ -6308,6 +6479,101 @@ packages: | ||
| 6308 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} | 6479 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} |
| 6309 | dev: true | 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 | /y18n@5.0.8: | 6577 | /y18n@5.0.8: |
| 6312 | resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} | 6578 | resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} |
| 6313 | engines: {node: '>=10'} | 6579 | engines: {node: '>=10'} |
| 1 | import { defHttp } from '@/utils/external/http/axios' | 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 | import { PaginationResult } from '/#/external/axios' | 3 | import { PaginationResult } from '/#/external/axios' |
| 4 | import { isShareMode } from '@/views/share/hook' | 4 | import { isShareMode } from '@/views/share/hook' |
| 5 | 5 | ||
| @@ -88,7 +88,7 @@ export const getOrganizationList = (params?: OrganizationListItem) => | @@ -88,7 +88,7 @@ export const getOrganizationList = (params?: OrganizationListItem) => | ||
| 88 | 88 | ||
| 89 | //获取视频列表 | 89 | //获取视频列表 |
| 90 | export const getVideoList = (params?: object) => | 90 | export const getVideoList = (params?: object) => |
| 91 | - defHttp.get({ | 91 | + defHttp.get<{data: CameraRecord[]}>({ |
| 92 | url: Api.VIDEO, | 92 | url: Api.VIDEO, |
| 93 | params | 93 | params |
| 94 | }) | 94 | }) |
| @@ -54,3 +54,39 @@ export interface ProductAndDevice { | @@ -54,3 +54,39 @@ export interface ProductAndDevice { | ||
| 54 | deviceType: string | 54 | deviceType: string |
| 55 | transportType: string | 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 | +} |
src/components/Video/index.ts
0 → 100644
| 1 | +export {default as XGPlayer} from './src/index.vue' |
src/components/Video/src/index.vue
0 → 100644
| 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> |
src/components/Video/src/types.ts
0 → 100644
| 1 | -import { ref, toRefs, toRaw, watch } from 'vue' | 1 | +import {ref, toRefs, toRaw, watch} from 'vue' |
| 2 | import type VChart from 'vue-echarts' | 2 | import type VChart from 'vue-echarts' |
| 3 | -import { useChartDataPondFetch } from '@/hooks/' | ||
| 4 | -import { CreateComponentType, ChartFrameEnum, CreateComponentGroupType } from '@/packages/index.d' | ||
| 5 | -import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' | ||
| 6 | -import { isPreview, intervalUnitHandle } from '@/utils' | ||
| 7 | -import { setOption } from '@/packages/public/chart' | ||
| 8 | -import { useChartDataSocket } from './useChartDataSocket' | ||
| 9 | -import { customRequest } from '@/api/external/customRequest' | ||
| 10 | -import { useFilterFn } from './useFilterFn' | ||
| 11 | -import { RequestContentTypeEnum } from '@/enums/external/httpEnum' | 3 | +import {useChartDataPondFetch} from '@/hooks/' |
| 4 | +import {CreateComponentType, ChartFrameEnum, CreateComponentGroupType} from '@/packages/index.d' | ||
| 5 | +import {useChartEditStore} from '@/store/modules/chartEditStore/chartEditStore' | ||
| 6 | +import {isPreview, intervalUnitHandle} from '@/utils' | ||
| 7 | +import {setOption} from '@/packages/public/chart' | ||
| 8 | +import {useChartDataSocket} from './useChartDataSocket' | ||
| 9 | +import {customRequest} from '@/api/external/customRequest' | ||
| 10 | +import {useFilterFn} from './useFilterFn' | ||
| 11 | +import {RequestContentTypeEnum} from '@/enums/external/httpEnum' | ||
| 12 | +import dayjs from 'dayjs' | ||
| 13 | + | ||
| 12 | 14 | ||
| 13 | // 获取类型 | 15 | // 获取类型 |
| 14 | type ChartEditStoreType = typeof useChartEditStore | 16 | type ChartEditStoreType = typeof useChartEditStore |
| @@ -20,111 +22,125 @@ type ChartEditStoreType = typeof useChartEditStore | @@ -20,111 +22,125 @@ type ChartEditStoreType = typeof useChartEditStore | ||
| 20 | * @param updateCallback 自定义更新函数 | 22 | * @param updateCallback 自定义更新函数 |
| 21 | */ | 23 | */ |
| 22 | export const useChartDataFetch = ( | 24 | export const useChartDataFetch = ( |
| 23 | - targetComponent: CreateComponentType, | ||
| 24 | - useChartEditStore: ChartEditStoreType, | ||
| 25 | - updateCallback?: (...args: any) => any | 25 | + targetComponent: CreateComponentType, |
| 26 | + useChartEditStore: ChartEditStoreType, | ||
| 27 | + updateCallback?: (...args: any) => any | ||
| 26 | ) => { | 28 | ) => { |
| 27 | - const vChartRef = ref<typeof VChart | null>(null) | ||
| 28 | - let fetchInterval: any = 0 | 29 | + const vChartRef = ref<typeof VChart | null>(null) |
| 30 | + let fetchInterval: any = 0 | ||
| 29 | 31 | ||
| 30 | - // 组件类型 | ||
| 31 | - const { chartFrame } = targetComponent.chartConfig | 32 | + // 组件类型 |
| 33 | + const {chartFrame} = targetComponent.chartConfig | ||
| 32 | 34 | ||
| 33 | - // eCharts 组件配合 vChart 库更新方式 | ||
| 34 | - const echartsUpdateHandle = (dataset: any) => { | ||
| 35 | - if (chartFrame === ChartFrameEnum.ECHARTS) { | ||
| 36 | - if (vChartRef.value) { | ||
| 37 | - setOption(vChartRef.value, { dataset: dataset }) | ||
| 38 | - } | 35 | + // eCharts 组件配合 vChart 库更新方式 |
| 36 | + const echartsUpdateHandle = (dataset: any) => { | ||
| 37 | + if (chartFrame === ChartFrameEnum.ECHARTS) { | ||
| 38 | + if (vChartRef.value) { | ||
| 39 | + setOption(vChartRef.value, {dataset: dataset}) | ||
| 40 | + } | ||
| 41 | + } | ||
| 39 | } | 42 | } |
| 40 | - } | ||
| 41 | 43 | ||
| 42 | - const requestIntervalFn = () => { | ||
| 43 | - const chartEditStore = useChartEditStore() | ||
| 44 | - if ((targetComponent.request.requestContentType as RequestContentTypeEnum) === RequestContentTypeEnum.WEB_SOCKET) return | 44 | + const requestIntervalFn = () => { |
| 45 | + const chartEditStore = useChartEditStore() | ||
| 46 | + if ((targetComponent.request.requestContentType as RequestContentTypeEnum) === RequestContentTypeEnum.WEB_SOCKET) return | ||
| 45 | 47 | ||
| 46 | - // 全局数据 | ||
| 47 | - const { | ||
| 48 | - requestOriginUrl, | ||
| 49 | - requestIntervalUnit: globalUnit, | ||
| 50 | - requestInterval: globalRequestInterval | ||
| 51 | - } = toRefs(chartEditStore.getRequestGlobalConfig) | 48 | + // 全局数据 |
| 49 | + const { | ||
| 50 | + requestOriginUrl, | ||
| 51 | + requestIntervalUnit: globalUnit, | ||
| 52 | + requestInterval: globalRequestInterval | ||
| 53 | + } = toRefs(chartEditStore.getRequestGlobalConfig) | ||
| 52 | 54 | ||
| 53 | - // 目标组件 | ||
| 54 | - const { | ||
| 55 | - requestUrl, | ||
| 56 | - requestIntervalUnit: targetUnit, | ||
| 57 | - requestInterval: targetInterval | ||
| 58 | - } = toRefs(targetComponent.request) | 55 | + // 目标组件 |
| 56 | + const { | ||
| 57 | + requestUrl, | ||
| 58 | + requestIntervalUnit: targetUnit, | ||
| 59 | + requestInterval: targetInterval | ||
| 60 | + } = toRefs(targetComponent.request) | ||
| 59 | 61 | ||
| 60 | - try { | ||
| 61 | - // 处理地址 | ||
| 62 | - if (requestUrl?.value) { | ||
| 63 | - // requestOriginUrl 允许为空 | ||
| 64 | - const completePath = requestOriginUrl && requestOriginUrl.value + requestUrl.value | ||
| 65 | - if (!completePath) return | 62 | + try { |
| 63 | + // 处理地址 | ||
| 64 | + if (requestUrl?.value) { | ||
| 65 | + // requestOriginUrl 允许为空 | ||
| 66 | + const completePath = requestOriginUrl && requestOriginUrl.value + requestUrl.value | ||
| 67 | + if (!completePath) return | ||
| 66 | 68 | ||
| 67 | - clearInterval(fetchInterval) | 69 | + clearInterval(fetchInterval) |
| 68 | 70 | ||
| 69 | - const fetchFn = async () => { | ||
| 70 | - const res = await customRequest(toRaw(targetComponent.request)) | ||
| 71 | - if (res) { | ||
| 72 | - try { | ||
| 73 | - const filter = targetComponent.filter | ||
| 74 | - const { value } = useFilterFn(filter, res) | ||
| 75 | - echartsUpdateHandle(value) | ||
| 76 | - // 更新回调函数 | ||
| 77 | - if (updateCallback) { | ||
| 78 | - updateCallback(value, targetComponent.request)//为了处理设备最新数据轮播列表,这里传过去当前组件的信息 | ||
| 79 | - } | ||
| 80 | - } catch (error) { | ||
| 81 | - console.error(error) | ||
| 82 | - } | ||
| 83 | - } | ||
| 84 | - } | 71 | + const fetchFn = async () => { |
| 72 | + let startTsValue = null | ||
| 73 | + let endTsValue = null | ||
| 74 | + const {requestParams} = toRaw(targetComponent.request) | ||
| 75 | + const {Params} = requestParams | ||
| 76 | + const {entityType, startTs, endTs} = Params | ||
| 77 | + let days = Math.ceil(((endTs as unknown as number) - (startTs as unknown as number)) / (1 * 60 * 60 * 24 * 1000)) | ||
| 78 | + if (entityType === 'DEVICE') { | ||
| 79 | + days = days <= 2 ? 1 : days<= 8 ? 7 : 30 | ||
| 80 | + startTsValue = dayjs().subtract(days - 1, 'day').startOf('day').valueOf() | ||
| 81 | + startTsValue = dayjs(startTsValue).startOf('day').valueOf() | ||
| 82 | + endTsValue = dayjs().endOf('day').valueOf() | ||
| 83 | + ;(toRaw(targetComponent.request).requestParams.Params.startTs as unknown as number) = startTsValue as number | ||
| 84 | + ;(toRaw(targetComponent.request).requestParams.Params.endTs as unknown as number) = endTsValue | ||
| 85 | + } | ||
| 86 | + const res = await customRequest(toRaw(targetComponent.request)) | ||
| 87 | + if (res) { | ||
| 88 | + try { | ||
| 89 | + const filter = targetComponent.filter | ||
| 90 | + const {value} = useFilterFn(filter, res) | ||
| 91 | + echartsUpdateHandle(value) | ||
| 92 | + // 更新回调函数 | ||
| 93 | + if (updateCallback) { | ||
| 94 | + updateCallback(value, targetComponent.request)//为了处理设备最新数据轮播列表,这里传过去当前组件的信息 | ||
| 95 | + } | ||
| 96 | + } catch (error) { | ||
| 97 | + console.error(error) | ||
| 98 | + } | ||
| 99 | + } | ||
| 100 | + } | ||
| 85 | 101 | ||
| 86 | - // 普通初始化与组件交互处理监听 | ||
| 87 | - watch( | ||
| 88 | - () => targetComponent.request, | ||
| 89 | - () => { | ||
| 90 | - fetchFn() | ||
| 91 | - }, | ||
| 92 | - { | ||
| 93 | - immediate: true, | ||
| 94 | - deep: true | ||
| 95 | - } | ||
| 96 | - ) | 102 | + // 普通初始化与组件交互处理监听 |
| 103 | + watch( | ||
| 104 | + () => targetComponent.request, | ||
| 105 | + () => { | ||
| 106 | + fetchFn() | ||
| 107 | + }, | ||
| 108 | + { | ||
| 109 | + immediate: true, | ||
| 110 | + deep: true | ||
| 111 | + } | ||
| 112 | + ) | ||
| 97 | 113 | ||
| 98 | - // 定时时间 | ||
| 99 | - const time = targetInterval && targetInterval.value ? targetInterval.value : globalRequestInterval.value | ||
| 100 | - // 单位 | ||
| 101 | - const unit = targetInterval && targetInterval.value ? targetUnit.value : globalUnit.value | ||
| 102 | - // 开启轮询 | ||
| 103 | - if (time) fetchInterval = setInterval(fetchFn, intervalUnitHandle(time, unit)) | ||
| 104 | - } | ||
| 105 | - // eslint-disable-next-line no-empty | ||
| 106 | - } catch (error) { | ||
| 107 | - console.log(error) | 114 | + // 定时时间 |
| 115 | + const time = targetInterval && targetInterval.value ? targetInterval.value : globalRequestInterval.value | ||
| 116 | + // 单位 | ||
| 117 | + const unit = targetInterval && targetInterval.value ? targetUnit.value : globalUnit.value | ||
| 118 | + // 开启轮询 | ||
| 119 | + if (time) fetchInterval = setInterval(fetchFn, intervalUnitHandle(time, unit)) | ||
| 120 | + } | ||
| 121 | + // eslint-disable-next-line no-empty | ||
| 122 | + } catch (error) { | ||
| 123 | + console.log(error) | ||
| 124 | + } | ||
| 108 | } | 125 | } |
| 109 | - } | ||
| 110 | 126 | ||
| 111 | - if (isPreview()) { | ||
| 112 | - requestIntervalFn() | ||
| 113 | - const chartEditStore = useChartEditStore() | ||
| 114 | - const { initial } = useChartDataSocket() | ||
| 115 | - /** | ||
| 116 | - * 支持分组也可以接受ws | ||
| 117 | - * 如果是分组并且绑定了ws | ||
| 118 | - */ | ||
| 119 | - chartEditStore.getComponentList?.forEach((item:CreateComponentType | CreateComponentGroupType)=>{ | ||
| 120 | - if(item.isGroup){ | ||
| 121 | - if(item.request.requestUrl?.includes('ws')){ | ||
| 122 | - initial(item, useChartEditStore, updateCallback) | ||
| 123 | - } | ||
| 124 | - } | ||
| 125 | - }) | ||
| 126 | - // | ||
| 127 | - initial(targetComponent, useChartEditStore, updateCallback) | ||
| 128 | - } | ||
| 129 | - return { vChartRef } | 127 | + if (isPreview()) { |
| 128 | + requestIntervalFn() | ||
| 129 | + const chartEditStore = useChartEditStore() | ||
| 130 | + const {initial} = useChartDataSocket() | ||
| 131 | + /** | ||
| 132 | + * 支持分组也可以接受ws | ||
| 133 | + * 如果是分组并且绑定了ws | ||
| 134 | + */ | ||
| 135 | + chartEditStore.getComponentList?.forEach((item: CreateComponentType | CreateComponentGroupType) => { | ||
| 136 | + if (item.isGroup) { | ||
| 137 | + if (item.request.requestUrl?.includes('ws')) { | ||
| 138 | + initial(item, useChartEditStore, updateCallback) | ||
| 139 | + } | ||
| 140 | + } | ||
| 141 | + }) | ||
| 142 | + // | ||
| 143 | + initial(targetComponent, useChartEditStore, updateCallback) | ||
| 144 | + } | ||
| 145 | + return {vChartRef} | ||
| 130 | } | 146 | } |
| @@ -45,11 +45,12 @@ export const lineSeriesItem = { | @@ -45,11 +45,12 @@ export const lineSeriesItem = { | ||
| 45 | 45 | ||
| 46 | export const option = { | 46 | export const option = { |
| 47 | tooltip: { | 47 | tooltip: { |
| 48 | - show: true, | ||
| 49 | trigger: 'axis', | 48 | trigger: 'axis', |
| 50 | axisPointer: { | 49 | axisPointer: { |
| 51 | - show: true, | ||
| 52 | - type: 'shadow' | 50 | + type: 'cross', |
| 51 | + crossStyle: { | ||
| 52 | + color: '#999' | ||
| 53 | + } | ||
| 53 | } | 54 | } |
| 54 | }, | 55 | }, |
| 55 | legend: { | 56 | legend: { |
| @@ -62,17 +62,30 @@ const option = computed(() => { | @@ -62,17 +62,30 @@ const option = computed(() => { | ||
| 62 | // dataset 无法变更条数的补丁 | 62 | // dataset 无法变更条数的补丁 |
| 63 | watch( | 63 | watch( |
| 64 | () => props.chartConfig.option.dataset, | 64 | () => props.chartConfig.option.dataset, |
| 65 | - (newData: { dimensions: any }, oldData) => { | 65 | + (newData: any, oldData) => { |
| 66 | try { | 66 | try { |
| 67 | if (!isObject(newData) || !('dimensions' in newData)) return | 67 | if (!isObject(newData) || !('dimensions' in newData)) return |
| 68 | - if (Array.isArray(newData?.dimensions)) { | ||
| 69 | - const seriesArr = [] | ||
| 70 | - for (let i = 0; i < newData.dimensions.length - 1; i++) { | ||
| 71 | - seriesArr.push(cloneDeep(barSeriesItem),cloneDeep(lineSeriesItem)) | 68 | + if (Array.isArray((newData as any)?.dimensions)) { |
| 69 | + const seriesArr: typeof barSeriesItem[] = [] | ||
| 70 | + // 对oldData进行判断,防止传入错误数据之后对旧维度判断产生干扰 | ||
| 71 | + // 此处计算的是dimensions的Y轴维度,若是dimensions.length为0或1,则默认为1,排除X轴维度干扰 | ||
| 72 | + const oldDimensions = | ||
| 73 | + Array.isArray(oldData?.dimensions) && oldData.dimensions.length >= 1 ? oldData.dimensions.length : 1 | ||
| 74 | + const newDimensions = (newData as any).dimensions.length >= 1 ? (newData as any).dimensions.length : 1 | ||
| 75 | + const dimensionsGap = newDimensions - oldDimensions | ||
| 76 | + if (dimensionsGap < 0) { | ||
| 77 | + props.chartConfig.option.series.splice(newDimensions - 1) | ||
| 78 | + } else if (dimensionsGap > 0) { | ||
| 79 | + if (!oldData || !oldData?.dimensions || !Array.isArray(oldData?.dimensions) || !oldData?.dimensions.length) { | ||
| 80 | + props.chartConfig.option.series = [] | ||
| 81 | + } | ||
| 82 | + for (let i = 0; i < dimensionsGap; i++) { | ||
| 83 | + seriesArr.push(cloneDeep(barSeriesItem)) | ||
| 84 | + } | ||
| 85 | + props.chartConfig.option.series.push(...seriesArr) | ||
| 72 | } | 86 | } |
| 73 | - useEchartsMapLegend(props.chartConfig, seriesArr) | 87 | + useEchartsMapLegend(props.chartConfig, props.chartConfig.option.series) |
| 74 | replaceMergeArr.value = ['series'] | 88 | replaceMergeArr.value = ['series'] |
| 75 | - props.chartConfig.option.series = seriesArr | ||
| 76 | nextTick(() => { | 89 | nextTick(() => { |
| 77 | replaceMergeArr.value = [] | 90 | replaceMergeArr.value = [] |
| 78 | }) | 91 | }) |
| @@ -240,6 +240,7 @@ const defaultTypeUpdate = (v: string) => { | @@ -240,6 +240,7 @@ const defaultTypeUpdate = (v: string) => { | ||
| 240 | } | 240 | } |
| 241 | 241 | ||
| 242 | const shortCutSelect = (value: number) => { | 242 | const shortCutSelect = (value: number) => { |
| 243 | + console.log(value) | ||
| 243 | startTs.value = Date.now() - value | 244 | startTs.value = Date.now() - value |
| 244 | endTs.value = Date.now() | 245 | endTs.value = Date.now() |
| 245 | props.optionData.dataset = [startTs.value, endTs.value] as any | 246 | props.optionData.dataset = [startTs.value, endTs.value] as any |
src/packages/components/external/Informations/Mores/Camera/components/VideoPlay.vue
deleted
100644 → 0
| 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> |
| @@ -53,6 +53,7 @@ export interface videoList { | @@ -53,6 +53,7 @@ export interface videoList { | ||
| 53 | deviceId: string | 53 | deviceId: string |
| 54 | customUrl: string | 54 | customUrl: string |
| 55 | params: GBT28181Params | 55 | params: GBT28181Params |
| 56 | + playProtocol?: number | ||
| 56 | } | 57 | } |
| 57 | 58 | ||
| 58 | export const option = { | 59 | export const option = { |
| @@ -120,15 +120,16 @@ const handleUpdateTreeValue = (e: string) => { | @@ -120,15 +120,16 @@ const handleUpdateTreeValue = (e: string) => { | ||
| 120 | const getVideoLists = async (organizationId: string) => { | 120 | const getVideoLists = async (organizationId: string) => { |
| 121 | const res = await getVideoList({ organizationId }) | 121 | const res = await getVideoList({ organizationId }) |
| 122 | if (!res) return | 122 | if (!res) return |
| 123 | - videoOptions.value = res?.data?.map((item: videoList) => ({ | 123 | + videoOptions.value = res?.data?.map((item) => ({ |
| 124 | label: item.name, | 124 | label: item.name, |
| 125 | value: item.id, | 125 | value: item.id, |
| 126 | id: item.id, | 126 | id: item.id, |
| 127 | accessMode: item.accessMode, | 127 | accessMode: item.accessMode, |
| 128 | customUrl: item.accessMode === AccessModeEnum.ManuallyEnter ? item.videoUrl: '', //参数只给自定义视频流使用 | 128 | customUrl: item.accessMode === AccessModeEnum.ManuallyEnter ? item.videoUrl: '', //参数只给自定义视频流使用 |
| 129 | channelId: item.accessMode === AccessModeEnum.GBT28181 ? item?.params?.channelNo : '', //参数只给gbt28181使用 | 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 | //针对萤石云或者海康威视,根据视频id获取播放流地址 | 135 | //针对萤石云或者海康威视,根据视频id获取播放流地址 |
| @@ -2,17 +2,7 @@ | @@ -2,17 +2,7 @@ | ||
| 2 | <div @mouseenter="handleMouseenter" @mouseleave="handleMouseleave" class="banner-box" ref="root"> | 2 | <div @mouseenter="handleMouseenter" @mouseleave="handleMouseleave" class="banner-box" ref="root"> |
| 3 | <div class="wrapper"> | 3 | <div class="wrapper"> |
| 4 | <div v-for="(item, index) in option.dataset" :key="index" :class="item.className" :style="item.sty"> | 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 | </div> | 6 | </div> |
| 17 | </div> | 7 | </div> |
| 18 | <a v-show="isShowSvg" href="javascript:;" class="left" @click="changeSlide('left')"></a> | 8 | <a v-show="isShowSvg" href="javascript:;" class="left" @click="changeSlide('left')"></a> |
| @@ -20,11 +10,10 @@ | @@ -20,11 +10,10 @@ | ||
| 20 | </div> | 10 | </div> |
| 21 | </template> | 11 | </template> |
| 22 | <script setup lang="ts" name="index"> | 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 | const props = defineProps({ | 18 | const props = defineProps({ |
| 30 | chartConfig: { | 19 | chartConfig: { |
| @@ -35,9 +24,9 @@ const props = defineProps({ | @@ -35,9 +24,9 @@ const props = defineProps({ | ||
| 35 | 24 | ||
| 36 | const isShowSvg = ref(false) | 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 | //暂定 any类型 | 31 | //暂定 any类型 |
| 43 | const option = shallowReactive<{ ['dataset']: any }>({ | 32 | const option = shallowReactive<{ ['dataset']: any }>({ |
| @@ -50,15 +39,15 @@ const computedFunc = (initial: number, source: Recordable[]) => { | @@ -50,15 +39,15 @@ const computedFunc = (initial: number, source: Recordable[]) => { | ||
| 50 | if (initial < 0) initial = 0 | 39 | if (initial < 0) initial = 0 |
| 51 | if (Array.isArray(source)) { | 40 | if (Array.isArray(source)) { |
| 52 | let len = source.length, | 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 | return source?.map((item: Recordable, index: number) => { | 47 | return source?.map((item: Recordable, index: number) => { |
| 59 | let transform = `translateX(-50%) scale(0.7)`, | 48 | let transform = `translateX(-50%) scale(0.7)`, |
| 60 | - zIndex = 0, | ||
| 61 | - className = 'slide' | 49 | + zIndex = 0, |
| 50 | + className = 'slide' | ||
| 62 | switch (index) { | 51 | switch (index) { |
| 63 | case temp3: | 52 | case temp3: |
| 64 | transform = `translateX(-50%) scale(1)` | 53 | transform = `translateX(-50%) scale(1)` |
| @@ -93,23 +82,23 @@ const computedFunc = (initial: number, source: Recordable[]) => { | @@ -93,23 +82,23 @@ const computedFunc = (initial: number, source: Recordable[]) => { | ||
| 93 | } | 82 | } |
| 94 | 83 | ||
| 95 | watch( | 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 | option.dataset = computedFunc(initial.value, option.dataset) | 95 | option.dataset = computedFunc(initial.value, option.dataset) |
| 107 | 96 | ||
| 108 | watch( | 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,17 +144,17 @@ function changeSlide(dir: string) { | ||
| 155 | } | 144 | } |
| 156 | 145 | ||
| 157 | watch( | 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 | const handleMouseenter = () => { | 160 | const handleMouseenter = () => { |
| @@ -181,6 +170,7 @@ const handleMouseleave = () => (isShowSvg.value = false) | @@ -181,6 +170,7 @@ const handleMouseleave = () => (isShowSvg.value = false) | ||
| 181 | height: 100%; | 170 | height: 100%; |
| 182 | display: flex; | 171 | display: flex; |
| 183 | overflow: hidden; | 172 | overflow: hidden; |
| 173 | + | ||
| 184 | .slide { | 174 | .slide { |
| 185 | width: 20%; | 175 | width: 20%; |
| 186 | height: 100%; | 176 | height: 100%; |
| @@ -200,6 +190,7 @@ const handleMouseleave = () => (isShowSvg.value = false) | @@ -200,6 +190,7 @@ const handleMouseleave = () => (isShowSvg.value = false) | ||
| 200 | } | 190 | } |
| 201 | } | 191 | } |
| 202 | } | 192 | } |
| 193 | + | ||
| 203 | .arrow { | 194 | .arrow { |
| 204 | position: absolute; | 195 | position: absolute; |
| 205 | top: 50%; | 196 | top: 50%; |
| @@ -211,11 +202,13 @@ const handleMouseleave = () => (isShowSvg.value = false) | @@ -211,11 +202,13 @@ const handleMouseleave = () => (isShowSvg.value = false) | ||
| 211 | background-color: white; | 202 | background-color: white; |
| 212 | opacity: 0.5; | 203 | opacity: 0.5; |
| 213 | } | 204 | } |
| 205 | + | ||
| 214 | a.left { | 206 | a.left { |
| 215 | @extend .arrow; | 207 | @extend .arrow; |
| 216 | background-image: url('./static/left.svg'); | 208 | background-image: url('./static/left.svg'); |
| 217 | left: 0px; | 209 | left: 0px; |
| 218 | } | 210 | } |
| 211 | + | ||
| 219 | a.right { | 212 | a.right { |
| 220 | @extend .arrow; | 213 | @extend .arrow; |
| 221 | background-image: url('./static/right.svg'); | 214 | background-image: url('./static/right.svg'); |
| 1 | <template> | 1 | <template> |
| 2 | - <collapse-item name="数据源(option配置里的内容)" :expanded="true"> | 2 | + <collapse-item name="数据源(option配置里的内容,注意去除末尾分号)" :expanded="true"> |
| 3 | <monaco-editor v-model:modelValue="optionData.dataset" width="400px" height="480px" language="json" /> | 3 | <monaco-editor v-model:modelValue="optionData.dataset" width="400px" height="480px" language="json" /> |
| 4 | </collapse-item> | 4 | </collapse-item> |
| 5 | </template> | 5 | </template> |
src/packages/components/external/Informations/Mores/SingleCamera/components/VideoPlay.vue
deleted
100644 → 0
| 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> |
| @@ -2,6 +2,11 @@ import { PublicConfigClass } from '@/packages/public' | @@ -2,6 +2,11 @@ import { PublicConfigClass } from '@/packages/public' | ||
| 2 | import { CreateComponentType } from '@/packages/index.d' | 2 | import { CreateComponentType } from '@/packages/index.d' |
| 3 | import { SingleCameraConfig } from './index' | 3 | import { SingleCameraConfig } from './index' |
| 4 | import cloneDeep from 'lodash/cloneDeep' | 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 | export enum sourceTypeEnum { | 11 | export enum sourceTypeEnum { |
| 7 | CUSTOM = 'custom', | 12 | CUSTOM = 'custom', |
| @@ -13,6 +18,11 @@ export enum sourceTypeNameEnum { | @@ -13,6 +18,11 @@ export enum sourceTypeNameEnum { | ||
| 13 | PLATFORM = '平台获取' | 18 | PLATFORM = '平台获取' |
| 14 | } | 19 | } |
| 15 | 20 | ||
| 21 | +export enum FluoriteMideaProtocolEnum { | ||
| 22 | + HLS = 2, | ||
| 23 | + FLV = 4, | ||
| 24 | +} | ||
| 25 | + | ||
| 16 | export enum VideoPlayerTypeEnum { | 26 | export enum VideoPlayerTypeEnum { |
| 17 | m3u8 = 'application/x-mpegURL', | 27 | m3u8 = 'application/x-mpegURL', |
| 18 | mp4 = 'video/mp4', | 28 | mp4 = 'video/mp4', |
| @@ -32,6 +42,7 @@ export interface videoListInterface { | @@ -32,6 +42,7 @@ export interface videoListInterface { | ||
| 32 | deviceId: string | 42 | deviceId: string |
| 33 | customUrl: string | 43 | customUrl: string |
| 34 | params: GBT28181Params | 44 | params: GBT28181Params |
| 45 | + playProtocol?: number | ||
| 35 | } | 46 | } |
| 36 | 47 | ||
| 37 | export interface GBT28181Params { | 48 | export interface GBT28181Params { |
| @@ -53,6 +64,7 @@ export interface Dataset { | @@ -53,6 +64,7 @@ export interface Dataset { | ||
| 53 | deviceId?: string | 64 | deviceId?: string |
| 54 | id?: string | 65 | id?: string |
| 55 | value?: string | 66 | value?: string |
| 67 | + playProtocol?: number | ||
| 56 | } | 68 | } |
| 57 | 69 | ||
| 58 | export const option = { | 70 | export const option = { |
| @@ -70,3 +82,42 @@ export default class Config extends PublicConfigClass implements CreateComponent | @@ -70,3 +82,42 @@ export default class Config extends PublicConfigClass implements CreateComponent | ||
| 70 | public chartConfig = cloneDeep(SingleCameraConfig) | 82 | public chartConfig = cloneDeep(SingleCameraConfig) |
| 71 | public option = cloneDeep(option) | 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 } | undefined> { | ||
| 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,7 +97,7 @@ const handleUpdateTreeValue = (value: string) => { | ||
| 97 | const getVideoLists = async (organizationId: string) => { | 97 | const getVideoLists = async (organizationId: string) => { |
| 98 | const res = await getVideoList({ organizationId }) | 98 | const res = await getVideoList({ organizationId }) |
| 99 | if (!res) return | 99 | if (!res) return |
| 100 | - videoOptions.value = res?.data?.map((item: videoListInterface) => { | 100 | + videoOptions.value = res?.data?.map((item) => { |
| 101 | return { | 101 | return { |
| 102 | label: item.name, | 102 | label: item.name, |
| 103 | value: item.id, | 103 | value: item.id, |
| @@ -105,8 +105,9 @@ const getVideoLists = async (organizationId: string) => { | @@ -105,8 +105,9 @@ const getVideoLists = async (organizationId: string) => { | ||
| 105 | id: item.id, | 105 | id: item.id, |
| 106 | accessMode: item.accessMode, | 106 | accessMode: item.accessMode, |
| 107 | channelId: item.accessMode === AccessMode.GBT28181 ? item?.params?.channelNo : '', //参数只给gbt28181使用 | 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 | <template> | 1 | <template> |
| 2 | <div> | 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 | + <XGPlayer :url="sourceUrl" :stream-type="playType" | ||
| 5 | + :config="{width: '100%', height: '100%', poster: option.poster}" | ||
| 6 | + :auto-play="option.autoplay"/> | ||
| 9 | </n-spin> | 7 | </n-spin> |
| 10 | </div> | 8 | </div> |
| 11 | </template> | 9 | </template> |
| 12 | <script setup lang="ts"> | 10 | <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' | 11 | +import {PropType, toRefs, shallowReactive, watch, ref} from 'vue' |
| 12 | +import {CreateComponentType} from '@/packages/index.d' | ||
| 13 | +import {Dataset, getPlayUrl, option as configOption} from './config' | ||
| 14 | +import {XGPlayer} from '@/components/Video' | ||
| 15 | +import {StreamType} from "@/components/Video/src/types"; | ||
| 16 | +import {CameraRecord} from "@/api/external/common/model"; | ||
| 19 | 17 | ||
| 20 | const props = defineProps({ | 18 | const props = defineProps({ |
| 21 | chartConfig: { | 19 | chartConfig: { |
| @@ -26,9 +24,9 @@ const props = defineProps({ | @@ -26,9 +24,9 @@ const props = defineProps({ | ||
| 26 | 24 | ||
| 27 | const showLoading = ref(false) | 25 | const showLoading = ref(false) |
| 28 | 26 | ||
| 29 | -const { w, h } = toRefs(props.chartConfig.attr) | 27 | +const {w, h} = toRefs(props.chartConfig.attr) |
| 30 | 28 | ||
| 31 | -const { autoplay, dataset, poster, customVideoUrl } = toRefs(props.chartConfig.option as typeof configOption) | 29 | +const {autoplay, dataset, poster, customVideoUrl} = toRefs(props.chartConfig.option as typeof configOption) |
| 32 | 30 | ||
| 33 | const option = shallowReactive({ | 31 | const option = shallowReactive({ |
| 34 | dataset: configOption.dataset, | 32 | dataset: configOption.dataset, |
| @@ -37,87 +35,47 @@ const option = shallowReactive({ | @@ -37,87 +35,47 @@ const option = shallowReactive({ | ||
| 37 | }) | 35 | }) |
| 38 | 36 | ||
| 39 | const sourceUrl = ref('') | 37 | 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 | -} | 38 | +const playType = ref<StreamType>() |
| 65 | 39 | ||
| 66 | 40 | ||
| 67 | async function getPlaySource(params: Dataset) { | 41 | async function getPlaySource(params: Dataset) { |
| 68 | - try { | ||
| 69 | - 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 | - } | ||
| 79 | - } finally { | ||
| 80 | - showLoading.value = false | ||
| 81 | - } | 42 | + const {id, channelId, deviceId, accessMode, customUrl, playProtocol} = params |
| 43 | + if (!accessMode) return | ||
| 44 | + const {type, url} = await getPlayUrl({ | ||
| 45 | + id: id, | ||
| 46 | + accessMode: accessMode, | ||
| 47 | + playProtocol: playProtocol, | ||
| 48 | + videoUrl: customUrl, | ||
| 49 | + params: { | ||
| 50 | + deviceId: deviceId, | ||
| 51 | + channelNo: channelId, | ||
| 52 | + }, | ||
| 53 | + } as unknown as CameraRecord) || {} | ||
| 54 | + sourceUrl.value = url! | ||
| 55 | + playType.value = type | ||
| 82 | } | 56 | } |
| 83 | 57 | ||
| 84 | watch( | 58 | 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() | 59 | + () => dataset?.value, |
| 60 | + async (newData) => { | ||
| 61 | + getPlaySource(newData) | ||
| 62 | + }, | ||
| 63 | + { | ||
| 64 | + immediate: true | ||
| 103 | } | 65 | } |
| 104 | - }, | ||
| 105 | - { | ||
| 106 | - immediate: true | ||
| 107 | - } | ||
| 108 | ) | 66 | ) |
| 109 | 67 | ||
| 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 | </script> | 68 | </script> |
| 121 | 69 | ||
| 122 | <style lang="scss" scoped> | 70 | <style lang="scss" scoped> |
| 71 | +.player-spin { | ||
| 72 | + width: 100%; | ||
| 73 | + height: 100%; | ||
| 74 | + @include deep() { | ||
| 75 | + .n-spin-content { | ||
| 76 | + width: 100%; | ||
| 77 | + height: 100%; | ||
| 78 | + } | ||
| 79 | + } | ||
| 80 | +} | ||
| 123 | </style> | 81 | </style> |
| 1 | <script lang="ts" setup> | 1 | <script lang="ts" setup> |
| 2 | -import { NFormItem, NGi, NGrid, NSelect, NDatePicker, NInputNumber } from 'naive-ui'; | ||
| 3 | -import { defaultIntervalOptions, aggergationOptions } from '../DynamicForm/timeInterval' | ||
| 4 | -import { unref, computed, ref, watch } from 'vue'; | ||
| 5 | -import { isObject } from '@/utils/external/is'; | 2 | +import {NFormItem, NGi, NGrid, NSelect, NDatePicker, NInputNumber} from 'naive-ui'; |
| 3 | +import {defaultIntervalOptions, aggergationOptions} from '../DynamicForm/timeInterval' | ||
| 4 | +import {unref, computed, ref, watch} from 'vue'; | ||
| 5 | +import {isObject} from '@/utils/external/is'; | ||
| 6 | +import dayjs from "dayjs"; | ||
| 6 | 7 | ||
| 7 | interface Value { | 8 | interface Value { |
| 8 | agg?: Nullable<string> | 9 | agg?: Nullable<string> |
| @@ -13,12 +14,12 @@ interface Value { | @@ -13,12 +14,12 @@ interface Value { | ||
| 13 | } | 14 | } |
| 14 | 15 | ||
| 15 | const props = withDefaults( | 16 | const props = withDefaults( |
| 16 | - defineProps<{ | ||
| 17 | - value?: Value | ||
| 18 | - }>(), | ||
| 19 | - { | ||
| 20 | - value: () => ({}) | ||
| 21 | - } | 17 | + defineProps<{ |
| 18 | + value?: Value | ||
| 19 | + }>(), | ||
| 20 | + { | ||
| 21 | + value: () => ({}) | ||
| 22 | + } | ||
| 22 | ) | 23 | ) |
| 23 | 24 | ||
| 24 | const emit = defineEmits<{ | 25 | const emit = defineEmits<{ |
| @@ -31,6 +32,26 @@ const timePeriod = ref<Nullable<[number, number]>>(null) | @@ -31,6 +32,26 @@ const timePeriod = ref<Nullable<[number, number]>>(null) | ||
| 31 | const agg = ref() | 32 | const agg = ref() |
| 32 | const interval = ref() | 33 | const interval = ref() |
| 33 | const limit = ref(7) | 34 | const limit = ref(7) |
| 35 | +const rangeShortcuts = { | ||
| 36 | + 昨天: () => { | ||
| 37 | + return [ | ||
| 38 | + dayjs().startOf('day').valueOf(), | ||
| 39 | + dayjs().endOf('day').valueOf() | ||
| 40 | + ] as const | ||
| 41 | + }, | ||
| 42 | + 最近7天: () => { | ||
| 43 | + return [ | ||
| 44 | + dayjs().subtract(6, 'day').startOf('day').valueOf(), | ||
| 45 | + dayjs().endOf('day').valueOf() | ||
| 46 | + ] as const | ||
| 47 | + }, | ||
| 48 | + 最近30天: () => { | ||
| 49 | + return [ | ||
| 50 | + dayjs().subtract(29, 'day').startOf('day').valueOf(), | ||
| 51 | + dayjs().endOf('day').valueOf() | ||
| 52 | + ] as const | ||
| 53 | + } | ||
| 54 | +} | ||
| 34 | 55 | ||
| 35 | const getRangeOptions = (number: number) => { | 56 | const getRangeOptions = (number: number) => { |
| 36 | for (let i = 0; i < defaultIntervalOptions.length; i++) { | 57 | for (let i = 0; i < defaultIntervalOptions.length; i++) { |
| @@ -55,32 +76,32 @@ const getIntervalTimeOptions = computed(() => { | @@ -55,32 +76,32 @@ const getIntervalTimeOptions = computed(() => { | ||
| 55 | 76 | ||
| 56 | const handleTimePerionChange = (value: number[]) => { | 77 | const handleTimePerionChange = (value: number[]) => { |
| 57 | const [startTs, endTs] = value || [] | 78 | const [startTs, endTs] = value || [] |
| 58 | - emit('update:value', { ...props.value, startTs, endTs, interval: null }) | ||
| 59 | - emit('change', { ...props.value || {}, startTs, endTs, interval: null }) | 79 | + emit('update:value', {...props.value, startTs, endTs, interval: null}) |
| 80 | + emit('change', {...props.value || {}, startTs, endTs, interval: null}) | ||
| 60 | } | 81 | } |
| 61 | 82 | ||
| 62 | const handleAggChange = (value: string) => { | 83 | const handleAggChange = (value: string) => { |
| 63 | - const _value = { ...props.value, agg: value, ...(value === 'NONE' ? { limit: 7 } : {}) } | 84 | + const _value = {...props.value, agg: value, ...(value === 'NONE' ? {limit: 7} : {})} |
| 64 | Reflect.deleteProperty(_value, value === 'NONE' ? 'interval' : 'limit') | 85 | Reflect.deleteProperty(_value, value === 'NONE' ? 'interval' : 'limit') |
| 65 | emit('update:value', _value) | 86 | emit('update:value', _value) |
| 66 | emit('change', _value) | 87 | emit('change', _value) |
| 67 | } | 88 | } |
| 68 | 89 | ||
| 69 | const handleIntervalChange = (value: number) => { | 90 | const handleIntervalChange = (value: number) => { |
| 70 | - const _value = { ...props.value, interval: value } | 91 | + const _value = {...props.value, interval: value} |
| 71 | emit('update:value', _value) | 92 | emit('update:value', _value) |
| 72 | emit('change', _value) | 93 | emit('change', _value) |
| 73 | } | 94 | } |
| 74 | 95 | ||
| 75 | const handleLimitChange = (value: Nullable<number>) => { | 96 | const handleLimitChange = (value: Nullable<number>) => { |
| 76 | - const _value = { ...props.value, limit: value } | 97 | + const _value = {...props.value, limit: value} |
| 77 | emit('update:value', _value) | 98 | emit('update:value', _value) |
| 78 | emit('change', _value) | 99 | emit('change', _value) |
| 79 | } | 100 | } |
| 80 | 101 | ||
| 81 | watch(() => props.value, (target) => { | 102 | watch(() => props.value, (target) => { |
| 82 | if (target && isObject(target)) { | 103 | if (target && isObject(target)) { |
| 83 | - const { agg: _agg, interval: _interval, startTs, endTs, limit: _limit } = target || {} | 104 | + const {agg: _agg, interval: _interval, startTs, endTs, limit: _limit} = target || {} |
| 84 | if (startTs && endTs) { | 105 | if (startTs && endTs) { |
| 85 | timePeriod.value = [startTs!, endTs!] | 106 | timePeriod.value = [startTs!, endTs!] |
| 86 | } else { | 107 | } else { |
| @@ -97,26 +118,29 @@ watch(() => props.value, (target) => { | @@ -97,26 +118,29 @@ watch(() => props.value, (target) => { | ||
| 97 | <NGrid :cols="24"> | 118 | <NGrid :cols="24"> |
| 98 | <NGi :span="16"> | 119 | <NGi :span="16"> |
| 99 | <NFormItem :show-label="false"> | 120 | <NFormItem :show-label="false"> |
| 100 | - <NDatePicker v-model:value="timePeriod" type="datetimerange" placeholder="请选择时间范围" | ||
| 101 | - @update-value="handleTimePerionChange" clearable :default-time="['00:00:00', '23:59:59']"></NDatePicker> | 121 | + <NDatePicker :shortcuts="rangeShortcuts" v-model:value="timePeriod" type="datetimerange" |
| 122 | + placeholder="请选择时间范围" | ||
| 123 | + @update-value="handleTimePerionChange" clearable | ||
| 124 | + :default-time="['00:00:00', '23:59:59']"></NDatePicker> | ||
| 102 | </NFormItem> | 125 | </NFormItem> |
| 103 | </NGi> | 126 | </NGi> |
| 104 | <NGi :span="4"> | 127 | <NGi :span="4"> |
| 105 | <NFormItem :show-label="false"> | 128 | <NFormItem :show-label="false"> |
| 106 | <NSelect v-model:value="agg" @update:value="handleAggChange" :options="aggergationOptions" label-field="name" | 129 | <NSelect v-model:value="agg" @update:value="handleAggChange" :options="aggergationOptions" label-field="name" |
| 107 | - value-field="id" placeholder="聚合方式" clearable></NSelect> | 130 | + value-field="id" placeholder="聚合方式" clearable></NSelect> |
| 108 | </NFormItem> | 131 | </NFormItem> |
| 109 | </NGi> | 132 | </NGi> |
| 110 | <NGi v-if="!getShowLimit" :span="4"> | 133 | <NGi v-if="!getShowLimit" :span="4"> |
| 111 | <NFormItem :show-label="false"> | 134 | <NFormItem :show-label="false"> |
| 112 | <NSelect v-model:value="interval" @update:value="handleIntervalChange" :options="getIntervalTimeOptions" | 135 | <NSelect v-model:value="interval" @update:value="handleIntervalChange" :options="getIntervalTimeOptions" |
| 113 | - label-field="name" value-field="id" placeholder="间隔时间" clearable></NSelect> | 136 | + label-field="name" value-field="id" placeholder="间隔时间" clearable></NSelect> |
| 114 | </NFormItem> | 137 | </NFormItem> |
| 115 | </NGi> | 138 | </NGi> |
| 116 | <NGi v-if="getShowLimit" :span="4"> | 139 | <NGi v-if="getShowLimit" :span="4"> |
| 117 | <NFormItem :show-label="false"> | 140 | <NFormItem :show-label="false"> |
| 118 | <NInputNumber v-model:value="limit" :default-value="7" @update:value="handleLimitChange" | 141 | <NInputNumber v-model:value="limit" :default-value="7" @update:value="handleLimitChange" |
| 119 | - :parse="(input: string) => parseInt(input)" :min="7" :max="50000" :step="1" placeholder="请输入最大条数" /> | 142 | + :parse="(input: string) => parseInt(input)" :min="7" :max="50000" :step="1" |
| 143 | + placeholder="请输入最大条数"/> | ||
| 120 | </NFormItem> | 144 | </NFormItem> |
| 121 | </NGi> | 145 | </NGi> |
| 122 | </NGrid> | 146 | </NGrid> |
| @@ -109,6 +109,7 @@ const getSharePageContentData = async () => { | @@ -109,6 +109,7 @@ const getSharePageContentData = async () => { | ||
| 109 | // chartEditStore.requestGlobalConfig = requestGlobalConfig | 109 | // chartEditStore.requestGlobalConfig = requestGlobalConfig |
| 110 | // chartEditStore.componentList = componentList | 110 | // chartEditStore.componentList = componentList |
| 111 | chartEditStore.setPageConfig(content.pageConfig) | 111 | chartEditStore.setPageConfig(content.pageConfig) |
| 112 | + chartEditStore.setCurrentPageSelectId(content.pageConfig.pageList[0].id) | ||
| 112 | // handleRegisterComponent(componentList) | 113 | // handleRegisterComponent(componentList) |
| 113 | content.pageConfig.pageList.forEach(pageItem=>{ | 114 | content.pageConfig.pageList.forEach(pageItem=>{ |
| 114 | handleRegisterComponent(pageItem.componentList) | 115 | handleRegisterComponent(pageItem.componentList) |