首页完善

This commit is contained in:
renna 2025-06-09 12:05:24 +08:00
parent 36aef50419
commit 0b23ae04bb
10 changed files with 365 additions and 99 deletions

View File

@ -102,6 +102,24 @@ export const robotApi = {
url: `/api/v1/events/alertFront/${messageId}`, url: `/api/v1/events/alertFront/${messageId}`,
method: 'get', method: 'get',
}) })
},
// 查看全部告警事件接口
getAlarmEventList: (number) => {
return service({
url: `/api/v1/events/getAllAlertMessage/${number}`,
method: 'get',
})
},
// 查看全部告警事件接口(支持分页)
getAlarmDetailList: (params) => {
return service({
url: `/api/v1/events/getAllAlertMessage/${params.number}`,
method: 'get',
params: {
offset: params.offset,
limit: params.limit
}
})
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -7,9 +7,9 @@
type="text" type="text"
placeholder="请输入机器人搜索" placeholder="请输入机器人搜索"
v-model="searchText" v-model="searchText"
@input="handleSearchInput" @keyup.enter="handleSearchInput"
> >
<img src="../assets/img/fdj.png" alt="搜索" class="search-icon" /> <img src="../assets/img/fdj.png" alt="搜索" class="search-icon" @click="handleSearchInput"/>
</div> </div>
<CustomSelect <CustomSelect
v-model="selectedFilter" v-model="selectedFilter"
@ -32,9 +32,11 @@
<button class="retry-button" @click="fetchRobotList">重试</button> <button class="retry-button" @click="fetchRobotList">重试</button>
</div> </div>
<div v-else-if="groupedRobots.length === 0" class="empty-state"> <div v-else-if="groupedRobots.length === 0" class="empty-state-container">
<div class="empty-icon">🔍</div> <EmptyState
<div class="empty-text">没有找到机器人</div> subtitle="暂无机器人信息"
:iconSrc="emptyRobot"
/>
</div> </div>
<template v-else> <template v-else>
@ -68,10 +70,23 @@ import { ref, onMounted, onUnmounted, computed, watch } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import BatteryIndicator from './common/BatteryIndicator.vue' import BatteryIndicator from './common/BatteryIndicator.vue'
import CustomSelect from './common/CustomSelect.vue' import CustomSelect from './common/CustomSelect.vue'
import EmptyState from './common/EmptyState.vue'
import { homeApi } from '../api/index' import { homeApi } from '../api/index'
import emptyRobot from '../assets/img/empty_robot.png'
const router = useRouter() const router = useRouter()
//
const debounce = (fn, delay) => {
let timer = null
return function(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, delay)
}
}
// //
const searchText = ref('') const searchText = ref('')
const filterOptions = ['全部', '在线', '离线', '故障'] const filterOptions = ['全部', '在线', '离线', '故障']
@ -83,14 +98,14 @@ const loading = ref(false)
const error = ref(null) const error = ref(null)
// //
const fetchRobotList = async () => { const fetchRobotList = async (searchNumber = null) => {
loading.value = true loading.value = true
error.value = null error.value = null
try { try {
const res = await homeApi.getRobotList({ const res = await homeApi.getRobotList({
tenantInfoId: '4fff5d4bcc4b4239941ff077a0da8958', // id tenantInfoId: '4fff5d4bcc4b4239941ff077a0da8958', // id
number: null, // number: searchNumber, //
status: null, // status: null, //
onlineStatus: null // 线 onlineStatus: null // 线
}) })
@ -210,8 +225,9 @@ const groupedRobots = computed(() => {
return grouped.filter(group => group.robots.length > 0) return grouped.filter(group => group.robots.length > 0)
}) })
const handleSearchInput = (e) => { const handleSearchInput = () => {
searchText.value = e.target.value console.log('点击搜索:', searchText.value)
searchRobots()
} }
const handleWheel = (e) => { const handleWheel = (e) => {
@ -258,7 +274,14 @@ onUnmounted(() => {
// //
watch(selectedFilter, () => { watch(selectedFilter, () => {
console.log('筛选条件变化:', selectedFilter.value) console.log('筛选条件变化:', selectedFilter.value)
searchRobots() //
}) })
//
const searchRobots = () => {
console.log('搜索机器人:', searchText.value)
fetchRobotList(searchText.value)
}
</script> </script>
<style scoped> <style scoped>
@ -558,4 +581,20 @@ watch(selectedFilter, () => {
.robot-status.待机中 { .robot-status.待机中 {
color: #00ffff; color: #00ffff;
} }
.empty-state-container {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
:deep(.empty-icon) {
width: 213px !important;
height: 150px !important;
}
:deep(.empty-subtitle) {
color: #fff!important;
font-size: 16px!important;
}
</style> </style>

View File

@ -53,6 +53,10 @@ const props = defineProps({
variant: { variant: {
type: String, type: String,
default: 'default' // 'default', 'search' default: 'default' // 'default', 'search'
},
font: {
type: String,
default: 'default' // 'default', 'small'
} }
}) })
@ -108,6 +112,7 @@ const selectOption = (option) => {
.select-text { .select-text {
color: #B9E8FF; color: #B9E8FF;
margin-right: 25px; margin-right: 25px;
font-size: v-bind("font === 'small' ? '12px' : '14px'");
} }
.arrow-icon { .arrow-icon {
@ -137,7 +142,7 @@ const selectOption = (option) => {
color: #B9E8FF; color: #B9E8FF;
cursor: pointer; cursor: pointer;
white-space: nowrap; white-space: nowrap;
font-size: v-bind("size === 'small' ? '12px' : '12px'"); font-size: v-bind("font === 'small' ? '12px' : '12px'");
line-height: v-bind("size === 'small' ? '18px' : '20px'"); line-height: v-bind("size === 'small' ? '18px' : '20px'");
} }

View File

@ -14,7 +14,7 @@ import small_title from '../../assets/img/small_title.png';
const props = defineProps({ const props = defineProps({
title: String title: String
}); });
console.log(props.title,"--------------");
const titleBgSrc = computed(() => { const titleBgSrc = computed(() => {
if (props.title === '最新告警') { if (props.title === '最新告警') {
return title2; return title2;

View File

@ -164,8 +164,8 @@
<!-- 底部按钮 --> <!-- 底部按钮 -->
<div class="modal-footer"> <div class="modal-footer">
<button class="btn cancel" @click="handleClose">取消</button> <button class="btn cancel" @click="handleClose">取消</button>
<button class="btn confirm" @click="handleConfirm">确认处理</button> <button class="btn confirm" @click="handleConfirm" v-if="alarmData.status !== '已处理'">确认处理</button>
<button class="btn report" @click="handleReport">处理并上报</button> <button class="btn report" @click="handleReport" v-if="alarmData.status !== '已处理'">处理并上报</button>
</div> </div>
</div> </div>
</div> </div>
@ -271,15 +271,17 @@ const updateRemark = (e) => {
<style scoped> <style scoped>
.alarm-modal { .alarm-modal {
position: fixed; position: fixed;
top: 0; top: 50%;
left: 0; left: 50%;
transform: translate(-50%, -50%);
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
/* background: rgba(0, 0, 0, 0.7); */ overflow: auto;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
z-index: 1000; z-index: 1000;
background-color: rgba(0, 0, 0, 0.5);
} }
.modal-content { .modal-content {

View File

@ -49,15 +49,17 @@ const handleCancel = () => {
<style scoped> <style scoped>
.confirm-dialog-overlay { .confirm-dialog-overlay {
position: fixed; position: fixed;
top: 0; top: 50%;
left: 0; left: 50%;
transform: translate(-50%, -50%);
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
background: rgba(0, 0, 0, 0.5); overflow: auto;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
z-index: 1000; z-index: 1000;
background-color: rgba(0, 0, 0, 0.5);
} }
.confirm-dialog { .confirm-dialog {

View File

@ -13,10 +13,10 @@
<div class="left-content"> <div class="left-content">
<!-- 主监控 --> <!-- 主监控 -->
<div class="main-monitor"> <div class="main-monitor">
<div class="monitor-title">主监控</div> <div class="monitor-title">{{ selectedEvent ? selectedEvent.etypeName : '主监控' }}</div>
<div class="monitor-view"> <div class="monitor-view">
<template v-if="eventData.mainImage"> <template v-if="selectedImage">
<img :src="eventData.mainImage" alt="" @error="imgLoadError.main = true" v-show="!imgLoadError.main" /> <img :src="selectedImage" alt="" @error="imgLoadError.main = true" v-show="!imgLoadError.main" />
<EmptyState <EmptyState
v-if="imgLoadError.main" v-if="imgLoadError.main"
subtitle="暂无图片" subtitle="暂无图片"
@ -35,33 +35,18 @@
<!-- 云台监控和热成像 --> <!-- 云台监控和热成像 -->
<div class="sub-monitors"> <div class="sub-monitors">
<div class="monitor-item"> <div class="monitor-item" v-for="index in 2" :key="index-1">
<div class="monitor-title">云台监控</div> <div class="monitor-title">{{ index === 1 ? '云台监控' : '热成像' }}</div>
<div class="monitor-view"> <div class="monitor-view">
<template v-if="eventData.subImages && eventData.subImages.length > 0"> <template v-if="selectedEvent && selectedEvent.imageList && selectedEvent.imageList.length >= index">
<img :src="eventData.subImages[0]" alt="" @error="imgLoadError.sub1 = true" v-show="!imgLoadError.sub1" /> <img
<EmptyState :src="selectedEvent.imageList[index-1]"
v-if="imgLoadError.sub1" alt=""
subtitle="暂无图片" @error="imgLoadError['sub'+(index-1)] = true"
:iconSrc="empty" v-show="!imgLoadError['sub'+(index-1)]"
class="video-empty-state"
/> />
</template>
<EmptyState
v-else
subtitle="暂无图片"
:iconSrc="empty"
class="video-empty-state"
/>
</div>
</div>
<div class="monitor-item">
<div class="monitor-title">热成像</div>
<div class="monitor-view">
<template v-if="eventData.subImages && eventData.subImages.length > 1">
<img :src="eventData.subImages[1]" alt="" @error="imgLoadError.sub2 = true" v-show="!imgLoadError.sub2" />
<EmptyState <EmptyState
v-if="imgLoadError.sub2" v-if="imgLoadError['sub'+(index-1)]"
subtitle="暂无图片" subtitle="暂无图片"
:iconSrc="empty" :iconSrc="empty"
class="video-empty-state" class="video-empty-state"
@ -89,11 +74,12 @@
<th>状态</th> <th>状态</th>
</tr> </tr>
<tr class="table-content"> <tr class="table-content">
<td>{{ eventData.type }}</td> <td>{{ selectedEvent ? selectedEvent.etypeName : '' }}</td>
<td>{{ eventData.time }}</td> <td>{{ rawCreateTime }}</td>
<td>{{ eventData.robotName }}</td> <td>{{ selectedEvent ? selectedEvent.name : '' }}</td>
<td :class="eventData.status">{{ eventData.status }}</td> <td :class="handleStatus">{{ handleStatus }}</td>
</tr> </tr>
</table> </table>
</div> </div>
</div> </div>
@ -102,20 +88,32 @@
<div class="remark-section"> <div class="remark-section">
<TitleBlock>备注</TitleBlock> <TitleBlock>备注</TitleBlock>
<div class="remark-content"> <div class="remark-content">
<div class="remark-box" contenteditable="true" data-placeholder="请输入备注信息..." @input="updateRemark"></div> <div
class="remark-box"
contenteditable="true"
data-placeholder="请输入备注信息..."
@input="updateRemark"
v-text="selectedEvent && selectedEvent.remark ? selectedEvent.remark : ''"
></div>
</div> </div>
</div> </div>
</div> </div>
<!-- 右侧监控视图列表 --> <!-- 右侧监控视图列表 -->
<div class="right-content"> <div class="right-content">
<TitleBlock>监控视图</TitleBlock> <TitleBlock>告警列表</TitleBlock>
<div class="monitor-list"> <div class="monitor-list">
<div v-for="(monitor, index) in monitorList" :key="index" class="monitor-item"> <div
<div class="monitor-title">{{ monitor.title }}</div> v-for="(event, index) in eventList"
:key="event.messageId"
class="monitor-item"
:class="{ 'active': selectedEventIndex === index }"
@click="selectEvent(event, index)"
>
<div class="monitor-title">{{ event.etypeName }}</div>
<div class="monitor-view"> <div class="monitor-view">
<template v-if="monitor.image"> <template v-if="event.imagePreview">
<img :src="monitor.image" alt="" @error="setMonitorError(index)" v-show="!monitorErrors[index]" /> <img :src="event.imagePreview" alt="" @error="setMonitorError(index)" v-show="!monitorErrors[index]" />
<EmptyState <EmptyState
v-if="monitorErrors[index]" v-if="monitorErrors[index]"
subtitle="暂无图片" subtitle="暂无图片"
@ -138,15 +136,23 @@
<!-- 底部按钮 --> <!-- 底部按钮 -->
<div class="modal-footer"> <div class="modal-footer">
<button class="btn cancel" @click="handleClose">取消</button> <button class="btn cancel" @click="handleClose">取消</button>
<button class="btn confirm" @click="handleConfirm">确认处理</button> <button
<button class="btn report" @click="handleReport">处理并上报</button> class="btn confirm"
@click="handleConfirm"
v-if="selectedEvent && selectedEvent.handle !== '1'"
>确认处理</button>
<button
class="btn report"
@click="handleReport"
v-if="selectedEvent && selectedEvent.handle !== '1'"
>处理并上报</button>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, onMounted, watch } from 'vue'; import { ref, onMounted, watch, computed } from 'vue';
import TitleBlock from '../common/TitleBlock.vue'; import TitleBlock from '../common/TitleBlock.vue';
import EmptyState from '../common/EmptyState.vue'; import EmptyState from '../common/EmptyState.vue';
import empty from '../../assets/img/empty.png'; import empty from '../../assets/img/empty.png';
@ -170,14 +176,79 @@ const props = defineProps({
monitorList: { monitorList: {
type: Array, type: Array,
default: () => [] default: () => []
},
eventList: {
type: Array,
default: () => []
} }
}); });
//
const selectedEventIndex = ref(0);
const selectedEvent = ref(null);
const selectedImage = ref('');
//
const formatTime = computed(() => {
if (!selectedEvent.value || !selectedEvent.value.createTime) {
return '';
}
//
if (typeof selectedEvent.value.createTime === 'string' && selectedEvent.value.createTime.includes('-')) {
return selectedEvent.value.createTime;
}
// T" "
if (selectedEvent.value.createTime.includes('T')) {
selectedEvent.value.createTime = selectedEvent.value.createTime.replace('T', ' ');
}
//
try {
const date = new Date(Number(selectedEvent.value.createTime));
return date.toLocaleString();
} catch (e) {
return selectedEvent.value.createTime || '';
}
});
// createTimeT
const rawCreateTime = computed(() => {
if (!selectedEvent.value || !selectedEvent.value.createTime) return '-';
return selectedEvent.value.createTime.replace('T', ' ');
});
//
const handleStatus = computed(() => {
if (!selectedEvent.value) {
return '未处理';
}
return selectedEvent.value.handle === '1' ? '已处理' : '未处理';
});
//
const selectEvent = (event, index) => {
selectedEventIndex.value = index;
selectedEvent.value = event;
selectedImage.value = event.imagePreview || (event.imageList && event.imageList.length > 0 ? event.imageList[0] : '');
//
resetImgLoadError();
};
//
watch(() => props.eventList, (newList) => {
if (newList && newList.length > 0) {
selectEvent(newList[0], 0);
} else {
selectedEvent.value = null;
selectedImage.value = '';
}
}, { immediate: true });
// //
const imgLoadError = ref({ const imgLoadError = ref({
main: false, main: false,
sub1: false, sub0: false,
sub2: false sub1: false
}); });
// //
@ -198,8 +269,8 @@ const setMonitorError = (index) => {
const resetImgLoadError = () => { const resetImgLoadError = () => {
imgLoadError.value = { imgLoadError.value = {
main: false, main: false,
sub1: false, sub0: false,
sub2: false sub1: false
}; };
monitorErrors.value = []; monitorErrors.value = [];
}; };
@ -236,14 +307,14 @@ const handleClose = () => {
const handleConfirm = () => { const handleConfirm = () => {
emit('confirm', { emit('confirm', {
...props.eventData, ...selectedEvent.value,
remark: remarkText.value remark: remarkText.value
}); });
}; };
const handleReport = () => { const handleReport = () => {
emit('report', { emit('report', {
...props.eventData, ...selectedEvent.value,
remark: remarkText.value remark: remarkText.value
}); });
}; };
@ -252,20 +323,22 @@ const handleReport = () => {
<style scoped> <style scoped>
.event-detail-modal { .event-detail-modal {
position: fixed; position: fixed;
top: 0; top: 50%;
left: 0; left: 50%;
transform: translate(-50%, -50%);
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
overflow: auto;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
z-index: 1000; z-index: 1000;
background-color: rgba(0, 0, 0, 0.5);
} }
.modal-content { .modal-content {
width: 890px; width: 890px;
height: 900px; height: 800px;
background: url("../../assets/img/alert2.png") no-repeat; background: url("../../assets/img/alert2.png") no-repeat;
background-size: 100% 100%; background-size: 100% 100%;
border-radius: 4px; border-radius: 4px;
@ -287,6 +360,7 @@ const handleReport = () => {
font-size: 28px; font-size: 28px;
letter-spacing: 4px; letter-spacing: 4px;
padding-left: 20px; padding-left: 20px;
line-height: 20px;
} }
.close-icon { .close-icon {
@ -327,8 +401,8 @@ const handleReport = () => {
} }
.main-monitor { .main-monitor {
min-height: 300px; min-height: 215px;
height: 300px; height: 215px;
} }
.monitor-title { .monitor-title {
@ -337,7 +411,7 @@ const handleReport = () => {
left: 0; left: 0;
width: 100%; width: 100%;
padding: 5px 10px; padding: 5px 10px;
/* background: rgba(0, 21, 31, 0.2); */ background: rgba(0, 21, 31, 0.5);
color: #B9E8FF; color: #B9E8FF;
font-size: 12px; font-size: 12px;
z-index: 1; z-index: 1;
@ -410,7 +484,7 @@ const handleReport = () => {
.remark-section{ .remark-section{
border:1px solid rgba(0,206,234,0.7); border:1px solid rgba(0,206,234,0.7);
border-radius: 4px; border-radius: 4px;
height: 135px; height: 116px;
} }
.remark-content { .remark-content {
padding:10px; padding:10px;
@ -434,7 +508,7 @@ const handleReport = () => {
} }
.monitor-list { .monitor-list {
padding:10px; padding:10px;
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
} }
@ -455,6 +529,16 @@ padding:10px;
.monitor-list .monitor-item { .monitor-list .monitor-item {
margin-bottom: 10px; margin-bottom: 10px;
height: 150px; height: 150px;
cursor: pointer;
transition: all 0.3s;
}
.monitor-list .monitor-item:hover {
transform: scale(1.02);
}
.monitor-list .monitor-item.active {
border: 2px solid #00FFFF;
} }
.modal-footer { .modal-footer {

View File

@ -57,7 +57,7 @@
</div> </div>
<CustomSelect <CustomSelect
v-model="selectedViews[camera.title]" v-model="selectedViews[camera.title]"
:options="viewOptions" :options="getViewOptionsForCamera(camera)"
size="small" size="small"
variant="search" variant="search"
font="small" font="small"
@ -108,6 +108,10 @@ import Icon3 from '../assets/img/icon3.png'
import Icon4 from '../assets/img/icon4.png' import Icon4 from '../assets/img/icon4.png'
import jkA from '../assets/img/jkA.png' import jkA from '../assets/img/jkA.png'
import jkRobot from '../assets/img/jkRobot.png' import jkRobot from '../assets/img/jkRobot.png'
import VideoPlayer from '../components/common/VideoPlayer.vue'
import EmptyState from '../components/common/EmptyState.vue'
import CustomWebRTCPlayer from '../components/common/CustomWebRTCPlayer.vue'
import empty from '../assets/img/empty.png'
// //
const statistics = ref([ const statistics = ref([
@ -180,14 +184,20 @@ const cameras = ref([
// //
const selectedViews = ref({ const selectedViews = ref({
'A区厂区监控': '视角1', 'A区厂区监控': '',
'B区厂区监控': '视角1', 'B区厂区监控': '',
'追随机器人监控': '视角1', '追随机器人监控': '',
'室外机器人监控': '视角1' '室外机器人监控': ''
}); });
// //
const viewOptions = ['视角1', '视角2']; const getViewOptionsForCamera = (camera) => {
const cameraData = monitorStreams.value[camera.title];
if (!cameraData) return [];
// URL
return Object.keys(cameraData);
};
// //
const monitorStreams = ref({}); const monitorStreams = ref({});
@ -200,6 +210,15 @@ const fetchMonitorStreams = async () => {
if (res.code === 200) { if (res.code === 200) {
monitorStreams.value = res.data || {}; monitorStreams.value = res.data || {};
console.log('获取监控视频流成功:', JSON.stringify(monitorStreams.value)); console.log('获取监控视频流成功:', JSON.stringify(monitorStreams.value));
//
cameras.value.forEach(camera => {
const viewOptions = getViewOptionsForCamera(camera);
if (viewOptions.length > 0) {
//
selectedViews.value[camera.title] = viewOptions[0];
}
});
} else { } else {
console.error('获取监控视频流失败:', res); console.error('获取监控视频流失败:', res);
} }
@ -211,7 +230,7 @@ const fetchMonitorStreams = async () => {
// WebRTC // WebRTC
const isWebRTCStream = (url) => { const isWebRTCStream = (url) => {
if (!url) return false; if (!url) return false;
return url.startsWith('webrtc://') || url.includes('31011500991180041301'); return url.startsWith('webrtc://') || url.includes('31011500991180041301') || url.includes('34020000001320000');
}; };
// //
@ -219,12 +238,13 @@ const getViewsForCamera = (camera) => {
const cameraData = monitorStreams.value[camera.title]; const cameraData = monitorStreams.value[camera.title];
if (!cameraData) return []; if (!cameraData) return [];
return viewOptions.map(viewName => { //
return Object.entries(cameraData).map(([viewName, streamUrl]) => {
return { return {
name: viewName, name: viewName,
streamUrl: cameraData[viewName] || '' streamUrl: streamUrl || '' // URL"empty"
}; };
}).filter(view => view.streamUrl); // URL }); // URL
}; };
// 使WebRTC // 使WebRTC
@ -232,8 +252,8 @@ const isWebRTCCamera = (camera) => {
const views = getViewsForCamera(camera); const views = getViewsForCamera(camera);
if (views.length === 0) return false; if (views.length === 0) return false;
// WebRTC // WebRTC
return isWebRTCStream(views[0].streamUrl); return views.some(view => isWebRTCStream(view.streamUrl));
}; };
const showRobotListModal = ref(false); const showRobotListModal = ref(false);

View File

@ -69,7 +69,7 @@
v-model="alarmTab" v-model="alarmTab"
:pending-count="pendingCount" :pending-count="pendingCount"
:done-count="doneCount" :done-count="doneCount"
:unread-count="unreadCount" :unread-count="allCount"
@view-all="handleViewAll" @view-all="handleViewAll"
@process-all="handleProcessAll" @process-all="handleProcessAll"
/> />
@ -215,6 +215,7 @@
v-model:visible="showViewAllModal" v-model:visible="showViewAllModal"
:event-data="currentEvent" :event-data="currentEvent"
:monitor-list="monitorList" :monitor-list="monitorList"
:event-list="eventListData"
@confirm="handleConfirm" @confirm="handleConfirm"
@report="handleReport" @report="handleReport"
/> />
@ -537,6 +538,7 @@ const unreadCountComputed = computed(
const pendingCount = ref(0); const pendingCount = ref(0);
const doneCount = ref(0); const doneCount = ref(0);
const unreadCount = ref(0); const unreadCount = ref(0);
const allCount = ref(0); // allCount
const alertCount = ref(0); const alertCount = ref(0);
const processedCount = ref(0); const processedCount = ref(0);
// //
@ -553,8 +555,51 @@ const setAlarmTab = async (tab) => {
}; };
// //
const handleViewAll = () => { const handleViewAll = async () => {
showViewAllModal.value = true; try {
isLoading.value = true;
// 使API10
const res = await robotApi.getAlarmDetailList({
number: robotId.value,
offset: 0,
limit: 10
});
if (res.code === 200 && res.data && res.data.length > 0) {
console.log('获取告警事件列表成功:', res.data);
// APIEventDetailModal
showViewAllModal.value = true;
//
currentEvent.value = {
mainImage: res.data[0].imagePreview || '',
subImages: res.data[0].imageList || [],
type: res.data[0].etypeName || '',
time: res.data[0].createTime || '',
robotName: res.data[0].name || robotId.value,
status: res.data[0].handle === '1' ? '已处理' : '未处理'
};
// monitorList
monitorList.value = res.data.map(item => ({
title: item.etypeName || '未知告警',
image: item.imagePreview || ''
}));
//
eventListData.value = res.data;
} else {
console.error('获取告警事件列表失败或列表为空');
window.$message && window.$message.error('获取告警事件列表失败或列表为空');
}
} catch (error) {
console.error('获取告警事件列表异常:', error);
window.$message && window.$message.error('获取告警事件列表失败');
} finally {
isLoading.value = false;
}
}; };
// //
@ -672,6 +717,7 @@ const getAlarmEventCount = async () => {
console.log('获取告警数量成功,原始数据:', res.data); console.log('获取告警数量成功,原始数据:', res.data);
alertCount.value = res.data.alert_count || 0; alertCount.value = res.data.alert_count || 0;
processedCount.value = res.data.processed_count || 0; processedCount.value = res.data.processed_count || 0;
allCount.value = res.data.all_count || 0; // all_count
// //
pendingCount.value = alertCount.value; pendingCount.value = alertCount.value;
@ -680,6 +726,7 @@ const getAlarmEventCount = async () => {
console.log('告警数量更新:', { console.log('告警数量更新:', {
未处理: alertCount.value, 未处理: alertCount.value,
已处理: processedCount.value, 已处理: processedCount.value,
全部: allCount.value, //
当前标签: alarmTab.value, 当前标签: alarmTab.value,
pendingCount: pendingCount.value, pendingCount: pendingCount.value,
doneCount: doneCount.value doneCount: doneCount.value
@ -1350,14 +1397,46 @@ const monitorList = ref([
{ title: '监控视图6', image: '../assets/img/camera-thumb3.jpg' } { title: '监控视图6', image: '../assets/img/camera-thumb3.jpg' }
]); ]);
const handleConfirm = () => { const handleConfirm = async (data) => {
console.log('确认处理'); console.log('确认处理告警事件:', data);
showViewAllModal.value = false;
// messageId
if (data.messageId) {
try {
const res = await robotApi.handleSingleAlarmEvent({
messageId: data.messageId,
remark: data.remark || '',
number: robotId.value
});
if (res.code === 200) {
console.log('处理单个告警成功');
//
await getAlarmEventList();
//
await getAlarmEventCount();
//
showViewAllModal.value = false;
} else {
console.error('处理单个告警失败:', res);
}
} catch (error) {
console.error('处理单个告警异常:', error);
}
} else {
console.log('缺少messageId无法处理告警');
showViewAllModal.value = false;
}
}; };
const handleReport = () => { const handleReport = async (data) => {
console.log('处理并上报'); console.log('处理并上报告警事件:', data);
showViewAllModal.value = false;
// handleConfirm
await handleConfirm(data);
}; };
// //
@ -1802,17 +1881,34 @@ watch(alarmTab, async (newValue) => {
// //
const handleAlarmEvent = async (alarm) => { const handleAlarmEvent = async (alarm) => {
try { try {
// //
if (alarm.group === "meter" || alarm.content === "日常巡检") { if (alarm.group === "meter" || alarm.content === "日常巡检") {
await showMeterDetail(alarm); // messageId
if (!alarm.messageId) {
window.$message && window.$message.error('缺少 messageId无法处理该告警');
return;
}
// loading
isLoading.value = true;
try {
await handleSingleAlarm({ messageId: alarm.messageId });
} catch (err) {
window.$message && window.$message.error('处理仪表识别告警失败');
} finally {
isLoading.value = false;
}
} else { } else {
// //
await showAlarmDetail(alarm); await showAlarmDetail(alarm);
} }
} catch (error) { } catch (error) {
console.error('处理告警事件失败:', error); console.error('处理告警事件失败:', error);
} }
}; };
// RobotDetail.vueeventListData
// currentEventmonitorList
const eventListData = ref([]);
</script> </script>
<style scoped> <style scoped>