| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- <template>
- <!-- 设备画面组件:右侧面板上方,包含操作按钮和 2×4 监控画面网格 -->
- <div class="device-view">
- <!-- 顶部操作按钮:最新热源 / 最新闯入 / 最新烟雾 / 关闭声光报警 -->
- <div class="view-actions">
- <button v-for="btn in actions" :key="btn.key" type="button"
- :class="['action-btn', { active: activeAction === btn.key }]" @click="onAction(btn.key)">
- {{ btn.label }}
- </button>
- </div>
- <!-- 2×4 监控画面网格 -->
- <div class="view-grid">
- <div class="view-cell" @click="selectChannel">
- <div class="media-wrap">
- <div v-if="renderPlayer" ref="playerRef" style="
- display: flex;
- width: 100%;
- height: 100%;
- overflow-y: auto;
- pointer-events: none;
- ">
- </div>
- </div>
- </div>
- </div>
- </div>
- </template>
- <script setup lang="ts">
- import { onBeforeUnmount, onMounted, ref } from 'vue'
- import { useCamera } from '/@/hooks/system/useCamera';
- /** 操作按钮数据结构 */
- interface ActionItem {
- key: string
- label: string
- }
- let props = defineProps({
- deviceId: {
- type: String,
- default: ''
- },
- });
- /** 组件自定义事件 */
- const emit = defineEmits<{
- (e: 'action', key: string): void
- (e: 'select', channel: any): void
- }>()
- const { getCamera, removeCamera } = useCamera();
- const playerRef = ref();
- const renderPlayer = ref(true);
- /** 顶部操作按钮列表 */
- const actions: ActionItem[] = [
- { key: 'heat', label: '最新热源' },
- { key: 'intrusion', label: '最新闯入' },
- { key: 'smoke', label: '最新烟雾' },
- { key: 'alarmOff', label: '关闭声光报警' },
- ]
- /** 当前激活的操作按钮 */
- const activeAction = ref('')
- /** 当前选中的通道 ID */
- const selectedId = ref('')
- /** 点击操作按钮,触发 action 事件 */
- function onAction(key: string) {
- activeAction.value = key
- emit('action', key)
- }
- /** 选中监控通道,触发 select 事件 */
- function selectChannel(item) {
- selectedId.value = item.id
- emit('select', item)
- }
- onMounted(async () => {
- await getCamera(props.deviceId, playerRef, renderPlayer);
- });
- onBeforeUnmount(() => {
- removeCamera(playerRef);
- });
- </script>
- <style lang="less" scoped>
- @import '/@/design/theme.less';
- // 设备画面主容器
- .device-view {
- --image-bg: url('@/assets/images/home-container/configurable/hsq/7-5.png');
- --dv-accent: #00d4ff;
- --dv-accent-soft: rgba(0, 212, 255, 0.45);
- --dv-text: #d8f4ff;
- width: 100%;
- height: 100%;
- display: flex;
- flex-direction: column;
- overflow: hidden;
- color: var(--dv-text);
- user-select: none;
- padding: 15px;
- box-sizing: border-box;
- }
- // 顶部操作按钮栏
- .view-actions {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: 12px;
- margin-bottom: 14px;
- flex-shrink: 0;
- .action-btn {
- min-width: 96px;
- height: 30px;
- padding: 0 14px;
- border: 1px solid #269ee1;
- border-radius: 2px;
- background: #185f8e;
- color: #fff;
- font-size: 13px;
- letter-spacing: 0.5px;
- cursor: pointer;
- box-shadow: 0 0 6px rgba(0, 200, 255, 0.25), inset 0 0 8px rgba(0, 120, 180, 0.12);
- transition: color 0.2s, background 0.2s, box-shadow 0.2s;
- &:hover,
- &.active {
- color: #fff;
- background: rgba(0, 90, 140, 0.45);
- }
- &:active {
- transform: translateY(1px);
- }
- }
- }
- // 2×4 监控画面网格
- .view-grid {
- flex: 1;
- display: flex;
- // flex-wrap: wrap;
- // gap: 15px 10px;
- // justify-content: flex-start;
- // align-items: flex-start;
- overflow-y: auto;
- }
- // // 单个监控画面单元格
- // .view-cell {
- // width: calc(25% - 10px);
- // height: 220px;
- // cursor: pointer;
- // // background: var(--image-bg) no-repeat center;
- // // background-size: 100% 100%;
- // }
- // // 媒体内容包裹层
- // .media-wrap {
- // height: 100%;
- // padding: 10px 10px 12px 10px;
- // box-sizing: border-box;
- // }
- // 无画面占位提示
- .media-empty {
- height: 100%;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- :deep(#LivePlayerBox) {
- display: flex;
- flex-direction: row;
- justify-content: flex-start;
- flex-wrap: wrap;
- pointer-events: none;
- gap: 10px;
- .liveVideo {
- width: 349px !important;
- height: 252px !important;
- padding: 12px 8px !important;
- align-self: auto !important;
- // margin: 8px !important;
- background-size: 100% 100% !important;
- }
- .video-parent {
- pointer-events: auto !important;
- align-self: auto !important;
- }
- }
- ::-webkit-scrollbar {
- display: none;
- }
- </style>
|