Commit 7b3faf2d54f0f57a9a7386287848f92ffaaafab8

Authored by loveumiko
1 parent 4bc4891e

feat: 新增GB/T28181协议

1 1 import { h } from 'vue';
2 2 import { BasicColumn, FormSchema } from '/@/components/Table';
3 3 import { Tag } from 'ant-design-vue';
  4 +import { withInstall } from '/@/utils/index';
  5 +
  6 +import VideoPlay from './video.vue';
  7 +export const Video = withInstall(VideoPlay);
4 8
5 9 export const configColumns: BasicColumn[] = [
6 10 {
... ... @@ -40,6 +44,7 @@ export const configColumns: BasicColumn[] = [
40 44 {
41 45 title: '操作',
42 46 dataIndex: 'action',
  47 + slots: { customRender: 'action' },
43 48 },
44 49 ];
45 50
... ...
... ... @@ -18,12 +18,13 @@
18 18 {
19 19 label: '播放',
20 20 auth: 'api:yt:sceneLinkage:get',
21   - icon: 'ant-design:playCircle-outlined',
  21 + icon: 'ant-design:play-circle-outlined',
22 22 onClick: handlePlay.bind(null, record),
23 23 },
24 24 ]"
25 25 /></template>
26 26 </BasicTable>
  27 + <VideoModal @register="registerModal" />
27 28 </template>
28 29
29 30 <script lang="ts" setup>
... ... @@ -32,6 +33,9 @@
32 33 import { Switch } from 'ant-design-vue';
33 34 import { DeviceRecord } from '/@/api/device/model/deviceModel';
34 35 import { watch } from 'vue';
  36 + import VideoModal from './videoModal.vue';
  37 + import { useModal } from '/@/components/Modal';
  38 + import { onMounted } from 'vue';
35 39
36 40 const props = defineProps({
37 41 fromId: {
... ... @@ -51,7 +55,9 @@
51 55 }
52 56 );
53 57
54   - const [registerTable] = useTable({
  58 + const [registerModal, { openModal }] = useModal();
  59 +
  60 + const [registerTable, { setTableData }] = useTable({
55 61 // api: deviceCommandRecordGetQuery,
56 62 columns: configColumns,
57 63 showTableSetting: true,
... ... @@ -71,7 +77,198 @@
71 77 console.log(checked, record, 'record');
72 78 };
73 79
  80 + const tableList = [
  81 + {
  82 + id: '8b66f4fa-88e0-42b2-be33-60652cd2bda1',
  83 + creator: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
  84 + createTime: '2023-03-10 17:16:54',
  85 + updater: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
  86 + updateTime: '2023-04-11 10:25:49',
  87 + name: 'dasd',
  88 + enabled: false,
  89 + tenantId: '0277ca80-693d-11ed-9e12-e5edad4f7148',
  90 + videoUrl:
  91 + 'https://vcsplay.scjtonline.cn:8200/live/HD_1569b634-4789-11eb-ab67-3cd2e55e0b20.m3u8?auth_key=1681179278-0-0-5c54a376f2ca32d05c4a152ee96336e9',
  92 + sn: 's',
  93 + organizationId: '27ef2a83-6f1f-4e33-824b-80afac684699',
  94 + organizationName: '车车组织',
  95 + status: false,
  96 + accessMode: 0,
  97 + playProtocol: 0,
  98 + channellNumber: 1,
  99 + },
  100 + {
  101 + id: '9ff408ab-980f-470c-a55c-e4e284ddd34d',
  102 + creator: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
  103 + createTime: '2023-02-22 14:50:13',
  104 + updater: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
  105 + updateTime: '2023-04-11 10:36:25',
  106 + name: '2',
  107 + enabled: false,
  108 + tenantId: '0277ca80-693d-11ed-9e12-e5edad4f7148',
  109 + videoUrl:
  110 + 'https://vcsplay.scjtonline.cn:8099/live/HD_d80a740b-2672-4ad1-90e4-52eb71d8c2ef.m3u8?auth_key=1681180571-0-0-dfdb334e5f83838ade5f01f61f910107',
  111 + sn: '212',
  112 + organizationId: '27ef2a83-6f1f-4e33-824b-80afac684699',
  113 + organizationName: '车车组织',
  114 + status: false,
  115 + accessMode: 0,
  116 + playProtocol: 0,
  117 + channellNumber: 1,
  118 + },
  119 + {
  120 + id: 'a6edd8fb-a91a-4a1b-8124-65959206dac4',
  121 + creator: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
  122 + createTime: '2023-02-21 16:39:51',
  123 + updater: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
  124 + updateTime: '2023-04-11 10:33:27',
  125 + name: 'dasda',
  126 + enabled: false,
  127 + tenantId: '0277ca80-693d-11ed-9e12-e5edad4f7148',
  128 + videoUrl:
  129 + 'https://vcsplay.scjtonline.cn:8200/live/HD_1b361aa9-5230-48ba-b8be-d1e2c4e9b178.m3u8?auth_key=1681180365-0-0-e77f40e88550091053139f5562d8afa2',
  130 + brand: 'dasdad',
  131 + sn: 'adsad',
  132 + organizationId: '27ef2a83-6f1f-4e33-824b-80afac684699',
  133 + organizationName: '车车组织',
  134 + status: false,
  135 + accessMode: 0,
  136 + playProtocol: 0,
  137 + channellNumber: 1,
  138 + },
  139 + {
  140 + id: '51b4c0bc-8050-4b37-bdb3-9fe08b14cf86',
  141 + creator: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
  142 + createTime: '2023-02-21 16:37:44',
  143 + updater: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
  144 + updateTime: '2023-04-11 10:56:59',
  145 + name: '视频',
  146 + enabled: false,
  147 + tenantId: '0277ca80-693d-11ed-9e12-e5edad4f7148',
  148 + videoUrl:
  149 + 'https://vcsplay.scjtonline.cn:8093/live/HD_c54034ca-4a6d-11eb-8edc-3cd2e55e088c.m3u8?auth_key=1681181808-0-0-d756d9b0426b71482e45b9377958e4dc',
  150 + brand: '视频厂家',
  151 + sn: 'DART2143SAD12RE',
  152 + organizationId: '27ef2a83-6f1f-4e33-824b-80afac684699',
  153 + organizationName: '车车组织',
  154 + status: false,
  155 + accessMode: 0,
  156 + playProtocol: 0,
  157 + channellNumber: 1,
  158 + },
  159 + {
  160 + id: '8c0e6ed0-3176-4e76-bd8e-92f722f61e79',
  161 + creator: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
  162 + createTime: '2022-12-01 15:55:54',
  163 + updater: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
  164 + updateTime: '2023-04-11 10:59:22',
  165 + name: '视频',
  166 + enabled: false,
  167 + tenantId: '0277ca80-693d-11ed-9e12-e5edad4f7148',
  168 + avatar: 'https://demo.thingskit.com:9000/yunteng/itbbqOBXIUzWvjq.jpeg',
  169 + videoUrl: 'http://113.204.115.250:83/openUrl/iFzoWME/live.m3u8',
  170 + brand: '厂家',
  171 + sn: 'JDKSA11321',
  172 + organizationId: '9196fd9a-624a-4891-a8b3-ce588baedf9f',
  173 + organizationName: '丰田',
  174 + status: false,
  175 + channellNumber: 1,
  176 + accessMode: 0,
  177 + playProtocol: 0,
  178 + },
  179 + {
  180 + id: 'c30422a7-9498-49a5-96d5-e77f3a2823e3',
  181 + creator: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
  182 + createTime: '2022-12-01 14:42:52',
  183 + updater: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
  184 + updateTime: '2023-03-02 17:12:53',
  185 + name: '湖南卫视',
  186 + enabled: false,
  187 + tenantId: '0277ca80-693d-11ed-9e12-e5edad4f7148',
  188 + videoUrl:
  189 + 'http://219.151.31.38/liveplay-kk.rtxapp.com/live/program/live/hnwshd/4000000/mnf.m3u8',
  190 + brand: 'BUZHIDAO',
  191 + sn: 'QKDK123456',
  192 + organizationId: '27ef2a83-6f1f-4e33-824b-80afac684699',
  193 + organizationName: '车车组织',
  194 + status: false,
  195 + channellNumber: 1,
  196 + accessMode: 0,
  197 + playProtocol: 0,
  198 + },
  199 + {
  200 + id: 'e3253015-b8df-4e8f-ad0c-f634d3fd927e',
  201 + creator: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
  202 + createTime: '2022-11-29 11:19:00',
  203 + name: '玩具视频播放',
  204 + enabled: false,
  205 + tenantId: '0277ca80-693d-11ed-9e12-e5edad4f7148',
  206 + avatar: 'http://nc.tianzow.com:29000/yunteng/tgygMQmYaaPDPdG.jpg',
  207 + videoUrl: 'https://ask.dcloud.net.cn/topic.m3u8',
  208 + brand: '成都厂家',
  209 + sn: 'TCL1528GOP',
  210 + organizationId: '27ef2a83-6f1f-4e33-824b-80afac684699',
  211 + organizationName: '车车组织',
  212 + status: false,
  213 + accessMode: 0,
  214 + channellNumber: 1,
  215 + playProtocol: 0,
  216 + },
  217 + {
  218 + id: '9edc9f73-3a9a-4e4b-9b4c-b955329b99b3',
  219 + creator: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
  220 + createTime: '2022-11-29 11:13:44',
  221 + updater: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
  222 + updateTime: '2023-01-11 10:03:18',
  223 + name: '视频',
  224 + enabled: false,
  225 + tenantId: '0277ca80-693d-11ed-9e12-e5edad4f7148',
  226 + sn: '7aeb4061f3cf4ba384ed8e1a3027d2a8',
  227 + organizationId: '27ef2a83-6f1f-4e33-824b-80afac684699',
  228 + organizationName: '车车组织',
  229 + status: false,
  230 + accessMode: 1,
  231 + videoPlatformId: '8cc7c20e-693b-48ea-9124-994e0908c83e',
  232 + streamType: 0,
  233 + playProtocol: 0,
  234 + channellNumber: 1,
  235 + videoPlatformDTO: {
  236 + enabled: false,
  237 + host: '113.204.115.250:7120',
  238 + appKey: '28238690',
  239 + appSecret: 'F3e3Ffvo9Wyg9jkl8BUS',
  240 + ssl: 1,
  241 + },
  242 + },
  243 + {
  244 + id: '9d6675ad-07ed-45ae-bb4a-457000e164f8',
  245 + creator: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
  246 + createTime: '2022-11-21 11:49:59',
  247 + updater: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
  248 + updateTime: '2023-04-11 10:53:27',
  249 + name: '新视频',
  250 + enabled: false,
  251 + tenantId: '0277ca80-693d-11ed-9e12-e5edad4f7148',
  252 + videoUrl: 'http://www.w3school.com.cn/example/html5/mov_bbb.mp4',
  253 + brand: '1111',
  254 + sn: 'XYZ',
  255 + organizationId: '27ef2a83-6f1f-4e33-824b-80afac684699',
  256 + organizationName: '车车组织',
  257 + status: false,
  258 + accessMode: 0,
  259 + channellNumber: 1,
  260 + playProtocol: 0,
  261 + },
  262 + ];
  263 +
  264 + onMounted(() => {
  265 + setTableData(tableList);
  266 + });
  267 +
74 268 const handlePlay = (record: Recordable) => {
75 269 console.log(record);
  270 + openModal(true, {
  271 + record,
  272 + });
76 273 };
77 274 </script>
... ...
  1 +<script lang="ts" setup>
  2 + import { isNumber } from 'lodash';
  3 + import videoJs, { VideoJsPlayer, VideoJsPlayerOptions } from 'video.js';
  4 + import 'video.js/dist/video-js.css';
  5 + import { computed, CSSProperties, onMounted, onUnmounted, ref, unref } from 'vue';
  6 + import { useDesign } from '/@/hooks/web/useDesign';
  7 + import { getJwtToken, getShareJwtToken } from '/@/utils/auth';
  8 + import { isShareMode } from '/@/views/sys/share/hook';
  9 + import 'videojs-flvjs-es6';
  10 + import {
  11 + CaretUpOutlined,
  12 + CaretRightOutlined,
  13 + PauseOutlined,
  14 + CaretDownOutlined,
  15 + CaretLeftOutlined,
  16 + PlusOutlined,
  17 + MinusOutlined,
  18 + } from '@ant-design/icons-vue';
  19 + import { Button } from 'ant-design-vue';
  20 + const { prefixCls } = useDesign('basic-video-play');
  21 +
  22 + const props = defineProps<{
  23 + options?: VideoJsPlayerOptions;
  24 + withToken?: boolean;
  25 + }>();
  26 +
  27 + const emit = defineEmits<{
  28 + (event: 'ready', instance?: Nullable<VideoJsPlayer>): void;
  29 + (event: 'onUnmounted'): void;
  30 + }>();
  31 +
  32 + const videoPlayEl = ref<HTMLVideoElement>();
  33 +
  34 + const isPlay = ref<Boolean>(true); //是否是播放状态
  35 +
  36 + const videoPlayInstance = ref<Nullable<VideoJsPlayer>>();
  37 +
  38 + const getOptions = computed(() => {
  39 + const { options, withToken } = props;
  40 +
  41 + const defaultOptions: VideoJsPlayerOptions & Recordable = {
  42 + language: 'zh',
  43 + muted: true,
  44 + liveui: true,
  45 + controls: true,
  46 + techOrder: ['html5', 'flvjs'],
  47 + flvjs: {
  48 + mediaDataSource: {
  49 + isLive: true,
  50 + cors: true,
  51 + hasAudio: false,
  52 + withCredentials: false,
  53 + },
  54 + config: {
  55 + headers: {
  56 + ...(withToken
  57 + ? {
  58 + 'X-Authorization': `Bearer ${isShareMode() ? getShareJwtToken() : getJwtToken()}`,
  59 + }
  60 + : {}),
  61 + },
  62 + autoCleanupSourceBuffer: true,
  63 + },
  64 + },
  65 + };
  66 + return videoJs.mergeOptions(defaultOptions, options);
  67 + });
  68 +
  69 + const getWidthHeight = computed(() => {
  70 + let { width = 300, height = 150 } = unref(getOptions);
  71 + width = isNumber(width) ? (`${width}px` as unknown as number) : width;
  72 + height = isNumber(height) ? (`${height}px` as unknown as number) : height;
  73 + return { width, height } as CSSProperties;
  74 + });
  75 +
  76 + const init = () => {
  77 + if (unref(videoPlayInstance)) unref(videoPlayInstance)?.dispose();
  78 + videoPlayInstance.value = videoJs(unref(videoPlayEl)!, unref(getOptions), () => {
  79 + emit('ready', unref(videoPlayInstance));
  80 + });
  81 + };
  82 +
  83 + //type 1:上 2:右 3:下 4:左 5:暂停
  84 + const handleClick = (type: number) => {
  85 + console.log(type, 'type');
  86 + if (type == 5) {
  87 + isPlay.value = !unref(isPlay);
  88 + }
  89 + };
  90 +
  91 + // type 1:放大 2:缩小
  92 + const handleScale = (type: number) => {
  93 + console.log(type, 'type');
  94 + };
  95 +
  96 + onMounted(() => {
  97 + init();
  98 + });
  99 +
  100 + onUnmounted(() => {
  101 + unref(videoPlayInstance)?.dispose();
  102 + videoPlayInstance.value = null;
  103 + emit('onUnmounted');
  104 + });
  105 +
  106 + defineExpose({
  107 + reloadPlayer: init,
  108 + getInstance: () => unref(videoPlayInstance),
  109 + });
  110 +</script>
  111 +
  112 +<template>
  113 + <div :class="prefixCls" class="w-full h-full flex" :style="getWidthHeight">
  114 + <video
  115 + ref="videoPlayEl"
  116 + class="video-js vjs-big-play-centered vjs-show-big-play-button-on-pause !w-8/10 !h-full"
  117 + muted
  118 + >
  119 + </video>
  120 + <div class="!w-2/10 bg-white flex items-center flex-col">
  121 + <h1>云台控制</h1>
  122 +
  123 + <div class="home mt-5">
  124 + <CaretUpOutlined class="front-sty-top child-icon" @click="handleClick(1)" />
  125 + <CaretRightOutlined class="front-sty-right child-icon" @click="handleClick(2)" />
  126 + <CaretDownOutlined class="front-sty-bottom child-icon" @click="handleClick(4)" />
  127 + <CaretLeftOutlined class="front-sty-left child-icon" @click="handleClick(3)" />
  128 +
  129 + <Button class="front-sty-center child center" shape="circle" @click="handleClick(5)">
  130 + <PauseOutlined v-if="isPlay" class="child-icon" style="color: #fffbfb" />
  131 + <CaretRightOutlined v-else class="child-icon" style="color: #fffbfb" />
  132 + </Button>
  133 +
  134 + <div class="box">
  135 + <div>
  136 + <Button class="left-top in-block" @click="handleClick(1)">
  137 + <i> 上</i>
  138 + </Button>
  139 + <Button class="right-top in-block" @click="handleClick(2)">
  140 + <i> 右</i>
  141 + </Button>
  142 + </div>
  143 + <div>
  144 + <Button class="left-bottom in-block" @click="handleClick(3)">
  145 + <i> 左</i>
  146 + </Button>
  147 + <Button class="right-bottom in-block" @click="handleClick(4)">
  148 + <i> 下</i>
  149 + </Button>
  150 + </div>
  151 +
  152 + <Button class="circle" @click="handleClick(5)" />
  153 + </div>
  154 + </div>
  155 + <div class="flex justify-center mt-8">
  156 + <Button shape="circle" class="button-icon" @click="handleScale(1)">
  157 + <PlusOutlined style="color: #315a9c; font-size: 1.5rem" />
  158 + </Button>
  159 + <Button shape="circle" class="ml-10 button-icon" @click="handleScale(2)">
  160 + <MinusOutlined style="color: #315a9c; font-size: 1.5rem" />
  161 + </Button>
  162 + </div>
  163 + </div>
  164 + </div>
  165 +</template>
  166 +
  167 +<style lang="less" scoped>
  168 + @prefix-cls: ~'@{namespace}-basic-video-play';
  169 +
  170 + .@{prefix-cls} {
  171 + .vjs-error-display {
  172 + .vjs-modal-dialog-content::after {
  173 + content: '无法加载视频,原因可能是服务器或网络故障,也可能是格式不支持.';
  174 + }
  175 + }
  176 + }
  177 +
  178 + .child {
  179 + position: absolute;
  180 + width: 3rem;
  181 + height: 3rem;
  182 + display: flex;
  183 + justify-content: center;
  184 + background: #e2dede;
  185 + align-items: center;
  186 + border: none;
  187 + }
  188 +
  189 + .child-icon {
  190 + font-size: 1.5rem;
  191 + color: #fffbfb;
  192 + }
  193 +
  194 + .button-icon {
  195 + width: 3rem;
  196 + height: 3rem;
  197 + background: #f5f5f5;
  198 + border: none;
  199 + }
  200 +
  201 + .center {
  202 + top: 50%;
  203 + left: 50%;
  204 + width: 4rem;
  205 + height: 4rem;
  206 + transform: translate(-50%, -50%);
  207 + border-radius: 50%;
  208 + background: #5586d4;
  209 + }
  210 +
  211 + .home {
  212 + position: relative;
  213 + width: 10rem;
  214 + height: 10rem;
  215 + }
  216 +
  217 + .box {
  218 + transform: rotateZ(45deg);
  219 + width: 10rem;
  220 + height: 10rem;
  221 + }
  222 +
  223 + .box i {
  224 + visibility: collapse;
  225 + }
  226 +
  227 + .front-sty-top {
  228 + position: absolute;
  229 + top: 1rem;
  230 + z-index: 9999;
  231 + left: 50%;
  232 + transform: translate(-50%);
  233 + }
  234 +
  235 + .front-sty-bottom {
  236 + position: absolute;
  237 + bottom: 1rem;
  238 + z-index: 9999;
  239 + left: 50%;
  240 + transform: translate(-50%);
  241 + }
  242 +
  243 + .front-sty-right {
  244 + position: absolute;
  245 + top: 50%;
  246 + z-index: 9999;
  247 + right: 1rem;
  248 + transform: translateY(-50%);
  249 + }
  250 +
  251 + .front-sty-left {
  252 + position: absolute;
  253 + top: 50%;
  254 + z-index: 9999;
  255 + left: 1rem;
  256 + transform: translateY(-50%);
  257 + }
  258 +
  259 + .front-sty-center {
  260 + position: absolute;
  261 + top: 50%;
  262 + z-index: 9999;
  263 + left: 50%;
  264 + transform: translate(-50%, -50%);
  265 + }
  266 +
  267 + .circle {
  268 + display: inline-block;
  269 + border-radius: 50%;
  270 + background-color: #5586d4;
  271 + width: 4rem;
  272 + height: 4rem;
  273 + position: absolute;
  274 + top: 50%;
  275 + left: 50%;
  276 + transform: translate(-50%, -50%);
  277 + }
  278 +
  279 + .in-block {
  280 + display: inline-block;
  281 + position: relative;
  282 + }
  283 +
  284 + .left-top {
  285 + width: 5rem;
  286 + height: 5rem;
  287 + border-radius: 5rem 0 0 0;
  288 + background-color: #e2dede;
  289 + }
  290 +
  291 + .right-top {
  292 + width: 5rem;
  293 + height: 5rem;
  294 + border-radius: 0 5rem 0 0;
  295 + background-color: #e2dede;
  296 + }
  297 +
  298 + .left-bottom {
  299 + width: 5rem;
  300 + height: 5rem;
  301 + border-radius: 0 0 0 5rem;
  302 + background-color: #e2dede;
  303 + }
  304 +
  305 + .right-bottom {
  306 + width: 5rem;
  307 + height: 5rem;
  308 + border-radius: 0 0 5rem 0;
  309 + background-color: #e2dede;
  310 + }
  311 +</style>
... ...
  1 +<template>
  2 + <div>
  3 + <BasicModal
  4 + v-bind="$attrs"
  5 + width="60rem"
  6 + destroyOnClose
  7 + :height="heightNum"
  8 + @register="register"
  9 + title="视频预览"
  10 + :showOkBtn="false"
  11 + @cancel="handleCancel"
  12 + >
  13 + <div class="flex items-center justify-center w-full h-full min-h-96 video-container">
  14 + <Video
  15 + v-if="showVideo"
  16 + :options="(options as any)"
  17 + :withToken="withToken"
  18 + @on-unmounted="handleCloseFlvPlayUrl"
  19 + />
  20 + </div>
  21 + </BasicModal>
  22 + </div>
  23 +</template>
  24 +<script setup lang="ts">
  25 + import { ref, reactive, unref } from 'vue';
  26 + import { BasicModal, useModalInner } from '/@/components/Modal';
  27 + import type { StreamingManageRecord, CameraModel } from '/@/api/camera/model/cameraModel';
  28 + import { getVideoTypeByUrl } from '/@/components/Video';
  29 + import { closeFlvPlay, getFlvPlayUrl, getStreamingPlayUrl } from '/@/api/camera/cameraManager';
  30 + import { isRtspProtocol } from '/@/components/Video/src/utils';
  31 + import { VideoJsPlayerOptions } from 'video.js';
  32 + import { useFingerprint } from '/@/utils/useFingerprint';
  33 + import { GetResult } from '@fingerprintjs/fingerprintjs';
  34 + import { AccessMode } from '/@/views/camera/manage/config.data';
  35 + import { Video } from './config';
  36 +
  37 + const heightNum = ref(800);
  38 + const showVideo = ref(false);
  39 +
  40 + const playUrl = ref('');
  41 +
  42 + const withToken = ref(false);
  43 +
  44 + const fingerprintResult = ref<Nullable<GetResult>>(null);
  45 +
  46 + const options = reactive<VideoJsPlayerOptions>({
  47 + width: '100%' as unknown as number,
  48 + height: 384 as unknown as number,
  49 + autoplay: true,
  50 + });
  51 +
  52 + const setSources = (url: string, fingerprintResult: GetResult) => {
  53 + const flag = isRtspProtocol(url);
  54 + options.sources = [
  55 + {
  56 + src: flag ? getFlvPlayUrl(url, fingerprintResult.visitorId) : url,
  57 + type: getVideoTypeByUrl(url),
  58 + },
  59 + ];
  60 + };
  61 +
  62 + const { getResult } = useFingerprint();
  63 + const [register] = useModalInner(
  64 + async (data: { record: CameraModel | StreamingManageRecord }) => {
  65 + console.log(data, 'data');
  66 + const { record } = data;
  67 + const result = await getResult();
  68 + fingerprintResult.value = result;
  69 + if (record.accessMode === AccessMode.ManuallyEnter) {
  70 + if ((record as CameraModel).videoUrl) {
  71 + if (isRtspProtocol((record as CameraModel).videoUrl)) {
  72 + playUrl.value = (record as CameraModel).videoUrl;
  73 + closeFlvPlay(unref(playUrl), result.visitorId);
  74 + withToken.value = true;
  75 + }
  76 + setSources((record as CameraModel).videoUrl, result);
  77 + }
  78 + } else {
  79 + try {
  80 + const { data: { url } = { url: '' } } = await getStreamingPlayUrl(record.id!);
  81 + setSources(url, result);
  82 + } catch (error) {}
  83 + }
  84 + showVideo.value = true;
  85 + }
  86 + );
  87 +
  88 + const handleCloseFlvPlayUrl = () => {
  89 + if (isRtspProtocol(unref(playUrl))) {
  90 + closeFlvPlay(unref(playUrl)!, unref(fingerprintResult)!.visitorId!);
  91 + }
  92 + };
  93 +
  94 + const handleCancel = () => {
  95 + showVideo.value = false;
  96 + withToken.value = false;
  97 + };
  98 +</script>
  99 +
  100 +<style lang="less" scoped>
  101 + .video-container:deep(.vben-basic-video-play) {
  102 + min-height: 13rem;
  103 + }
  104 +
  105 + .video-container:deep(.video-js) {
  106 + min-height: 13rem;
  107 + }
  108 +</style>
... ...