Showing
4 changed files
with
623 additions
and
2 deletions
| 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> | ... | ... |