diff --git a/src/api/detail.js b/src/api/detail.js index 2cc4dfe..2e84df8 100644 --- a/src/api/detail.js +++ b/src/api/detail.js @@ -120,6 +120,13 @@ export const robotApi = { limit: params.limit } }) + }, + // 获取事件类型下拉框 + getEventTypes: () => { + return service({ + url: '/api/v1/events/getEtypeNameList', + method: 'get', + }) } } diff --git a/src/components/AlarmStatistics copy.vue b/src/components/AlarmStatistics copy.vue new file mode 100644 index 0000000..df6bd63 --- /dev/null +++ b/src/components/AlarmStatistics copy.vue @@ -0,0 +1,403 @@ + + + + + diff --git a/src/components/AlarmStatistics.vue b/src/components/AlarmStatistics.vue index d22f1d7..941cb83 100644 --- a/src/components/AlarmStatistics.vue +++ b/src/components/AlarmStatistics.vue @@ -175,33 +175,18 @@ const updateChart = () => { }, series: [ { - // 当没有数据时,显示一个空数据点 data: chartData.series.length > 0 ? chartData.series : [0], type: "line", - smooth: true, + smooth: false, symbol: "circle", symbolSize: 8, itemStyle: { - color: "#FF8A00", + color: "#fff", // 圆点白色 + borderColor: '#FF8A00', // 橙色描边 + borderWidth: 1, }, lineStyle: { - color: { - type: "linear", - x: 0, - y: 0, - x2: 0, - y2: 1, - colorStops: [ - { - offset: 0, - color: "#FF8A00", - }, - { - offset: 1, - color: "rgba(255, 138, 0, 0)", - }, - ], - }, + color: "#FF8A00", // 线条橙色 width: 3, }, areaStyle: { @@ -212,50 +197,18 @@ const updateChart = () => { x2: 0, y2: 1, colorStops: [ - { - offset: 0, - color: "rgba(255, 138, 0, 0.3)", - }, - { - offset: 1, - color: "rgba(255, 138, 0, 0)", - }, + { offset: 0, color: "rgba(255, 138, 0, 0.3)" }, + { offset: 1, color: "rgba(255, 138, 0, 0)" }, ], }, }, - markPoint: chartData.series.length > 0 ? { - symbol: "circle", - symbolSize: 50, - itemStyle: { - color: { - type: "radial", - x: 0.5, - y: 0.5, - r: 0.5, - colorStops: [ - { - offset: 0, - color: "rgba(255, 138, 0, 0.2)", - }, - { - offset: 0.8, - color: "rgba(255, 138, 0, 0.1)", - }, - { - offset: 1, - color: "rgba(255, 138, 0, 0)", - }, - ], - }, - }, - data: [ - { - type: "max", - name: "最高频率", - label: { show: true, color: "#FF8A00", fontSize: 12 }, - }, - ], - } : null, + label: { + show: true, + position: 'top', + color: '#FF8A00', + fontSize: 14, + fontWeight: 'bold', + }, }, ], }; diff --git a/src/components/common/CarouselVideoPlayer.vue b/src/components/common/CarouselVideoPlayer.vue index 4e4d3cc..b7310c0 100644 --- a/src/components/common/CarouselVideoPlayer.vue +++ b/src/components/common/CarouselVideoPlayer.vue @@ -26,7 +26,7 @@ -
+
diff --git a/src/components/common/CarouselWebRTCPlayer.vue b/src/components/common/CarouselWebRTCPlayer.vue index 70ce3e7..12a6ebc 100644 --- a/src/components/common/CarouselWebRTCPlayer.vue +++ b/src/components/common/CarouselWebRTCPlayer.vue @@ -24,7 +24,7 @@ -
+
diff --git a/src/components/common/CustomWebRTCPlayer.vue b/src/components/common/CustomWebRTCPlayer.vue index 4afd605..1030e49 100644 --- a/src/components/common/CustomWebRTCPlayer.vue +++ b/src/components/common/CustomWebRTCPlayer.vue @@ -19,6 +19,24 @@
加载中...
{{ error }}
+ + +
+ 全屏 + 退出全屏 +
@@ -50,6 +68,57 @@ const videoRef = ref(null); const isLoading = ref(false); const error = ref(''); const pc = ref(null); // WebRTC连接 +const isFullscreen = ref(false); // 是否全屏 + +// 切换全屏模式 +const toggleFullscreen = () => { + const container = videoRef.value?.parentElement || videoRef.value; + + if (!container) return; + + if (!document.fullscreenElement) { + // 进入全屏模式 + if (container.requestFullscreen) { + container.requestFullscreen().then(() => { + isFullscreen.value = true; + }).catch(err => { + console.error('全屏模式出错:', err); + }); + } else if (container.webkitRequestFullscreen) { // Safari + container.webkitRequestFullscreen(); + isFullscreen.value = true; + } else if (container.msRequestFullscreen) { // IE11 + container.msRequestFullscreen(); + isFullscreen.value = true; + } + } else { + exitFullscreen(); + } +}; + +// 退出全屏模式 +const exitFullscreen = () => { + if (document.exitFullscreen) { + document.exitFullscreen().then(() => { + isFullscreen.value = false; + }).catch(err => { + console.error('退出全屏模式出错:', err); + }); + } else if (document.webkitExitFullscreen) { // Safari + document.webkitExitFullscreen(); + isFullscreen.value = false; + } else if (document.msExitFullscreen) { // IE11 + document.msExitFullscreen(); + isFullscreen.value = false; + } +}; + +// 监听全屏状态变化 +const handleFullscreenChange = () => { + isFullscreen.value = !!document.fullscreenElement || + !!document.webkitFullscreenElement || + !!document.msFullscreenElement; +}; // 初始化WebRTC连接 const initWebRTC = async () => { @@ -249,80 +318,63 @@ const cleanupWebRTC = () => { error.value = ''; }; -// 监听流URL变化 +// 监听streamUrl变化 watch(() => props.streamUrl, (newUrl) => { if (newUrl) { - console.log('流URL变化,重新初始化WebRTC:', newUrl); + console.log('streamUrl变化,重新初始化WebRTC:', newUrl); initWebRTC(); } else { - console.log('流URL为空,清理WebRTC连接'); + console.log('streamUrl为空,清理WebRTC连接'); cleanupWebRTC(); } -}, { immediate: true }); - -onMounted(() => { - console.log('CustomWebRTCPlayer组件挂载'); - if (props.streamUrl) { - initWebRTC(); - } }); +// 组件挂载时初始化 +onMounted(() => { + if (props.streamUrl) { + console.log('组件挂载,初始化WebRTC:', props.streamUrl); + initWebRTC(); + } + + // 添加全屏变化事件监听 + document.addEventListener('fullscreenchange', handleFullscreenChange); + document.addEventListener('webkitfullscreenchange', handleFullscreenChange); + document.addEventListener('msfullscreenchange', handleFullscreenChange); +}); + +// 组件卸载时清理 onUnmounted(() => { - console.log('CustomWebRTCPlayer组件卸载'); + console.log('组件卸载,清理WebRTC连接'); cleanupWebRTC(); + + // 移除全屏变化事件监听 + document.removeEventListener('fullscreenchange', handleFullscreenChange); + document.removeEventListener('webkitfullscreenchange', handleFullscreenChange); + document.removeEventListener('msfullscreenchange', handleFullscreenChange); + + // 确保退出全屏 + if (isFullscreen.value) { + exitFullscreen(); + } }); \ No newline at end of file + +.loading-text { + color: #ffffff; + margin-top: 10px; + font-size: 14px; +} + +.error-message { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + color: #ff4d4f; + background-color: rgba(0, 0, 0, 0.7); + padding: 10px 15px; + border-radius: 4px; + font-size: 14px; + max-width: 80%; + text-align: center; + z-index: 2; +} + +.empty-state { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; +} + +.video-empty-state { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +/* 控制按钮样式 */ +.control-buttons { + position: absolute; + right: 10px; + bottom: 10px; + display: flex; + gap: 10px; + z-index: 3; +} + +.control-icon { + width: 32px; + height: 32px; + cursor: pointer; + opacity: 0.7; + transition: opacity 0.3s; + background-color: rgba(0, 0, 0, 0.5); + padding: 5px; + border-radius: 4px; +} + +.control-icon:hover { + opacity: 1; +} + \ No newline at end of file diff --git a/src/views/Home.vue b/src/views/Home.vue index acd066d..470ea0a 100644 --- a/src/views/Home.vue +++ b/src/views/Home.vue @@ -472,6 +472,7 @@ onMounted(() => { /* background: rgba(0, 21, 31, 0.5); */ background: #033347; border-radius: 4px; + position: relative; } .camera-feed img { diff --git a/src/views/RobotDetail.vue b/src/views/RobotDetail.vue index 7597fec..97468db 100644 --- a/src/views/RobotDetail.vue +++ b/src/views/RobotDetail.vue @@ -31,7 +31,7 @@
-
+
主摄像头
    -
  • 全部告警
  • -
  • 事件告警
  • -
  • 仪表识别
  • +
  • {{ type }}
@@ -559,12 +557,19 @@ const handleViewAll = async () => { try { isLoading.value = true; - // 使用新API获取告警事件列表,每页10条 - const res = await robotApi.getAlarmDetailList({ + // 构建接口参数 + const params = { number: robotId.value, - offset: 0, - limit: 10 - }); + offset: (currentPage.value - 1) * pageSize.value, + limit: pageSize.value + }; + // 如果不是全部告警,添加etypeName参数 + if (selectedType.value && selectedType.value !== '全部告警') { + params.etypeName = selectedType.value; + } + + // 使用新API获取告警事件列表 + const res = await robotApi.getAlarmDetailList(params); if (res.code === 200 && res.data && res.data.length > 0) { console.log('获取告警事件列表成功:', res.data); @@ -1055,14 +1060,18 @@ const getAlarmEventList = async () => { // 过滤当前Tab下的告警 const filteredEventAlarms = computed(() => { + let list = eventAlarms.value; + if (selectedType.value && selectedType.value !== '全部告警') { + // 按类型过滤,匹配etypeName或content字段 + list = list.filter(a => a.etypeName === selectedType.value || a.content === selectedType.value); + } if (alarmTab.value === "pending") { - // 未处理标签下显示待处理和超时未处理的告警 - return eventAlarms.value.filter((a) => a.status === "pending" || a.status === "timeout"); + return list.filter((a) => a.status === "pending" || a.status === "timeout"); } if (alarmTab.value === "done") { - return eventAlarms.value.filter((a) => a.status === "done"); + return list.filter((a) => a.status === "done"); } - return eventAlarms.value; + return list; }); const filteredMeterAlarms = computed(() => { @@ -1172,6 +1181,17 @@ onMounted(async () => { } catch (error) { console.error('初始化告警数据失败:', error); } + + // 获取告警类型 + try { + // 获取告警类型 + const res = await robotApi.getEventTypes(); + if (res.code === 200 && Array.isArray(res.data)) { + eventTypeOptions.value = ['全部告警', ...res.data]; + } + } catch (e) { + console.error('获取告警类型失败', e); + } }); onUnmounted(() => { @@ -1194,6 +1214,10 @@ const closeSelect = () => { const selectType = (type) => { selectedType.value = type; selectOpen.value = false; + // 如果"查看全部"弹窗已打开,自动刷新 + if (showViewAllModal.value) { + handleViewAll(); + } }; // 告警详情弹窗相关 @@ -1909,6 +1933,24 @@ const handleAlarmEvent = async (alarm) => { // 在RobotDetail.vue中添加eventListData变量,用于存储完整的告警事件列表数据 // 在currentEvent和monitorList之后添加 const eventListData = ref([]); + +// 告警类型选项 +const eventTypeOptions = ref(['全部告警']); + +// 页面加载时获取告警类型 +onMounted(async () => { + // ... existing code ... + try { + // 获取告警类型 + const res = await robotApi.getEventTypes(); + if (res.code === 200 && Array.isArray(res.data)) { + eventTypeOptions.value = ['全部告警', ...res.data]; + } + } catch (e) { + console.error('获取告警类型失败', e); + } + // ... existing code ... +});