<template>
|
<div v-loading="loading" class="screen-cameras">
|
<el-empty v-if="!loading && !previewList.length" description="暂无在线摄像头" :image-size="72">
|
<router-link class="screen-cameras__link" to="/monitor/device">前往监控设备</router-link>
|
</el-empty>
|
|
<div v-else class="screen-cameras__grid">
|
<div v-for="dev in previewList" :key="dev.id" class="screen-cameras__item">
|
<div class="screen-cameras__player">
|
<ezuikit-player
|
v-if="ysToken"
|
:key="'screen_cam_' + dev.id + '_' + ysToken + '_' + playerRemountKey"
|
:container-id="'screen_cam_' + dev.id + '_' + playerRemountKey"
|
:access-token="ysToken"
|
:url="cameraUrl(dev)"
|
:pause-after-first-frame="true"
|
/>
|
</div>
|
<div v-if="dev.iotName" class="screen-cameras__name" :title="dev.iotName">{{ dev.iotName }}</div>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<script lang="ts" setup>
|
defineOptions({
|
name: 'report-screen-camera-preview'
|
});
|
|
import { computed, onMounted, onUnmounted, ref } from 'vue';
|
import { useCool } from '/@/cool';
|
import EzuikitPlayer from '../../ezuikit/components/ezuikit-player.vue';
|
|
const props = withDefaults(
|
defineProps<{
|
/** 最多展示路数,4~6 */
|
limit?: number;
|
}>(),
|
{
|
limit: 6
|
}
|
);
|
|
const maxCount = computed(() => Math.min(Math.max(props.limit, 4), 6));
|
const previewList = computed(() => deviceList.value.slice(0, maxCount.value));
|
|
const { service } = useCool();
|
const playerRemountKey = ref(0);
|
|
function onScreenFullscreenChange() {
|
playerRemountKey.value += 1;
|
}
|
|
const deviceList = ref<any[]>([]);
|
const ysToken = ref('');
|
const loading = ref(false);
|
|
function cameraUrl(dev: { iotCode?: string; code?: string }) {
|
return `ezopen://open.ys7.com/${dev.iotCode || dev.code}/1.hd.live`;
|
}
|
|
async function fetchYsToken() {
|
if (ysToken.value) return;
|
try {
|
const res = await service.base.sys.param.stringbykey({ key: 'ys7.accessToken' });
|
ysToken.value = res as string;
|
} catch (e: any) {
|
console.error('萤石 Token 获取失败', e?.response?.data?.message || e.message);
|
}
|
}
|
|
async function fetchDevices() {
|
loading.value = true;
|
try {
|
const res = await service.basicdata.iot.getCameras();
|
deviceList.value = (res || []) as any[];
|
} catch (e: any) {
|
console.error('获取摄像头列表失败', e?.response?.data?.message || e.message);
|
deviceList.value = [];
|
} finally {
|
loading.value = false;
|
}
|
}
|
|
onMounted(async () => {
|
window.addEventListener('report-screen-fullscreen-change', onScreenFullscreenChange);
|
await fetchYsToken();
|
await fetchDevices();
|
});
|
|
onUnmounted(() => {
|
window.removeEventListener('report-screen-fullscreen-change', onScreenFullscreenChange);
|
});
|
</script>
|
|
<style lang="scss" scoped>
|
.screen-cameras {
|
min-height: 200px;
|
|
&__grid {
|
display: grid;
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
gap: 10px;
|
}
|
|
&__item {
|
display: flex;
|
flex-direction: column;
|
min-width: 0;
|
border-radius: 10px;
|
overflow: hidden;
|
background: #000;
|
border: 1px solid var(--el-border-color-extra-light);
|
}
|
|
&__player {
|
aspect-ratio: 16 / 9;
|
background: #0f172a;
|
|
:deep(> div) {
|
width: 100%;
|
height: 100%;
|
}
|
}
|
|
&__name {
|
padding: 6px 8px;
|
font-size: 12px;
|
line-height: 1.4;
|
color: var(--el-text-color-regular);
|
background: var(--el-fill-color-lighter);
|
white-space: nowrap;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
}
|
|
&__link {
|
color: var(--el-color-primary);
|
text-decoration: none;
|
|
&:hover {
|
text-decoration: underline;
|
}
|
}
|
|
@media (max-width: 1200px) {
|
&__grid {
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
}
|
}
|
|
@media (max-width: 768px) {
|
&__grid {
|
grid-template-columns: 1fr;
|
}
|
}
|
}
|
</style>
|