|
|
@@ -4,7 +4,7 @@
|
|
|
:scrollable="false"
|
|
|
>
|
|
|
<div class="data-m-container relative flex h-full flex-col gap-4 overflow-hidden">
|
|
|
- <div class="video-container-box flex">
|
|
|
+ <div class="video-container-box relative flex">
|
|
|
<div
|
|
|
class="relative flex-1"
|
|
|
v-for="(v, i) in videoInfo"
|
|
|
@@ -12,21 +12,26 @@
|
|
|
>
|
|
|
<canvas :class="['dm-video' + i, 'h-30 w-full']"></canvas>
|
|
|
</div>
|
|
|
+ <NSkeleton
|
|
|
+ v-if="loading"
|
|
|
+ width="100%"
|
|
|
+ height="100%"
|
|
|
+ />
|
|
|
</div>
|
|
|
<div class="flex flex-1 gap-4 max-sm:flex-col">
|
|
|
<div class="flex flex-2 flex-col gap-4">
|
|
|
<div
|
|
|
- class="grid flex-2 grid-cols-2 grid-rows-3 gap-1 overflow-hidden sm:grid-cols-3 lg:grid-cols-5"
|
|
|
+ class="relative grid flex-2 grid-cols-2 grid-rows-3 gap-1 overflow-hidden sm:grid-cols-3 lg:grid-cols-5"
|
|
|
>
|
|
|
<div
|
|
|
v-for="v in dataListComputed"
|
|
|
- :key="v.EventId"
|
|
|
+ :key="v.EventID"
|
|
|
class="h-full w-full bg-naive-card"
|
|
|
>
|
|
|
- <div class="flex h-full flex-col">
|
|
|
+ <div class="relative flex h-full flex-col">
|
|
|
<img
|
|
|
- class="h-[100px] w-full object-cover"
|
|
|
- :src="v.imageFileName"
|
|
|
+ class="h-[100px] w-full"
|
|
|
+ :src="v.ImgUrlClip"
|
|
|
alt=""
|
|
|
/>
|
|
|
<div class="flex h-full items-center justify-between pl-2">
|
|
|
@@ -34,12 +39,13 @@
|
|
|
<span :style="{ color: parseFloat(v.Score) > 0.5 ? 'red' : 'green' }">{{
|
|
|
v.Score
|
|
|
}}</span>
|
|
|
- <span>{{ v.EventTime.split(' ')[1] }}</span>
|
|
|
+ <span>{{ v.EventTimeFormat.split(' ')[1] }}</span>
|
|
|
<span>{{ v.Type == '0' ? '鸟' : '未知' }}</span>
|
|
|
</div>
|
|
|
<NButton
|
|
|
quaternary
|
|
|
circle
|
|
|
+ @click="alarmShow(v)"
|
|
|
>
|
|
|
<template #icon>
|
|
|
<i class="iconify-[fe--warning] iconify"></i>
|
|
|
@@ -48,6 +54,14 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+ <template v-for="v in 15">
|
|
|
+ <NSkeleton
|
|
|
+ v-if="isRequestLoading"
|
|
|
+ :key="v"
|
|
|
+ width="100%"
|
|
|
+ height="100%"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
</div>
|
|
|
<div class="flex-1">
|
|
|
<NDataTable
|
|
|
@@ -66,41 +80,45 @@
|
|
|
<BallCameraTracking />
|
|
|
</div>
|
|
|
</div>
|
|
|
- <!-- <div
|
|
|
- v-if="loading"
|
|
|
- class="absolute top-0 right-0 bottom-0 left-0 flex items-center justify-center bg-[rgba(0,0,0,0.1)]"
|
|
|
- >
|
|
|
- <NSpin size="medium" />
|
|
|
- </div> -->
|
|
|
</div>
|
|
|
+ <Drawer
|
|
|
+ v-model="drawerShow"
|
|
|
+ v-model:currentItem="currentItem"
|
|
|
+ >
|
|
|
+ <AlarmShow />
|
|
|
+ </Drawer>
|
|
|
</ScrollContainer>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
+import { watchThrottled } from '@vueuse/core'
|
|
|
import dayjs from 'dayjs'
|
|
|
-import { NDataTable, NButton } from 'naive-ui'
|
|
|
+import { NDataTable, NButton, NSkeleton } from 'naive-ui'
|
|
|
import useWorker from 'omnimatrix-video-player'
|
|
|
import { onMounted, onUnmounted, ref, h, watch, computed } from 'vue'
|
|
|
|
|
|
import { useRequest } from '@/api'
|
|
|
import { ScrollContainer } from '@/components'
|
|
|
+import AlarmShow from '@/components/alarm-drawer/components/AlarmShow.vue'
|
|
|
+import Drawer from '@/components/alarm-drawer/Drawer.vue'
|
|
|
import { useInjection } from '@/composables'
|
|
|
import { mediaQueryInjectionKey } from '@/injection'
|
|
|
import { useAlarmStore } from '@/stores'
|
|
|
+import { drawBoundingBox, revokeBlob } from '@/utils'
|
|
|
|
|
|
import BallCameraTracking from './components/ballCameraTracking.vue'
|
|
|
|
|
|
import type { DataTableColumns } from 'naive-ui'
|
|
|
// import { enableImageManipulation } from '@/utils'
|
|
|
interface RowData {
|
|
|
- EventId: string
|
|
|
- EventTime: string
|
|
|
+ EventID: string
|
|
|
+ EventTimeFormat: string
|
|
|
Score: string
|
|
|
Pan: string
|
|
|
Tilt: string
|
|
|
Type: string
|
|
|
Status: number
|
|
|
- imageFileName?: string
|
|
|
+ ImgUrlClip?: string
|
|
|
}
|
|
|
|
|
|
defineOptions({ name: 'DataMonitoring' })
|
|
|
@@ -115,8 +133,8 @@ const videoInfo = ref([
|
|
|
`wss://${alarmStore.ipF}/VideoShow/Preview/Full/Main?DeviceID=1`,
|
|
|
`wss://${alarmStore.ipF}/VideoShow/Preview/Full/Main?DeviceID=2`,
|
|
|
])
|
|
|
-const loading = ref(false)
|
|
|
-const isRequestLoading = ref(false)
|
|
|
+const loading = ref(true)
|
|
|
+const isRequestLoading = ref(true)
|
|
|
const tableRowsStyle = { fontSize: '12px' }
|
|
|
const columns: DataTableColumns<RowData> = [
|
|
|
{
|
|
|
@@ -130,11 +148,11 @@ const columns: DataTableColumns<RowData> = [
|
|
|
},
|
|
|
{
|
|
|
title: '事件ID',
|
|
|
- key: 'EventId',
|
|
|
+ key: 'EventID',
|
|
|
width: 150,
|
|
|
align: 'center',
|
|
|
render(row) {
|
|
|
- return h('span', { style: tableRowsStyle }, row.EventId)
|
|
|
+ return h('span', { style: tableRowsStyle }, row.EventID)
|
|
|
},
|
|
|
},
|
|
|
{
|
|
|
@@ -143,7 +161,7 @@ const columns: DataTableColumns<RowData> = [
|
|
|
align: 'center',
|
|
|
width: 200,
|
|
|
render(row) {
|
|
|
- return h('span', { style: tableRowsStyle }, row.EventTime)
|
|
|
+ return h('span', { style: tableRowsStyle }, row.EventTimeFormat)
|
|
|
},
|
|
|
},
|
|
|
{
|
|
|
@@ -217,28 +235,94 @@ const showVideo = () => {
|
|
|
})
|
|
|
}
|
|
|
|
|
|
-watch(
|
|
|
+const formatData = async (list: any[]) => {
|
|
|
+ const promises = list.map((item: any) => {
|
|
|
+ return drawBoundingBox(
|
|
|
+ {
|
|
|
+ X: item.target_x ? item.target_x : item.X,
|
|
|
+ Y: item.target_y ? item.target_y : item.Y,
|
|
|
+ W: item.target_width ? item.target_width : item.W,
|
|
|
+ H: item.target_height ? item.target_height : item.H,
|
|
|
+ ImgUrl: item.ImgUrl ? item.ImgUrl : getFileUrl(item.image_file_name),
|
|
|
+ },
|
|
|
+ true,
|
|
|
+ )
|
|
|
+ })
|
|
|
+ const data = await Promise.all(promises)
|
|
|
+
|
|
|
+ return list.map((item: any, i: number) => {
|
|
|
+ return {
|
|
|
+ Image: item.image_file_name ? item.image_file_name : item.Image,
|
|
|
+ Video: item.video_file_name ? item.video_file_name : item.Video,
|
|
|
+ Degree: item.degree ? item.degree : item.Degree,
|
|
|
+ EventTime: item.event_timestamp ? item.event_timestamp : item.EventTime,
|
|
|
+ X: item.target_x ? item.target_x : item.X,
|
|
|
+ Y: item.target_y ? item.target_y : item.Y,
|
|
|
+ W: item.target_width ? item.target_width : item.W,
|
|
|
+ H: item.target_height ? item.target_height : item.H,
|
|
|
+ Score: item.confidence_score ? item.confidence_score : item.Score,
|
|
|
+ Type: item.alarm_type ? item.alarm_type : item.Type,
|
|
|
+ Pan: item.pan_angle ? item.pan_angle : item.Pan,
|
|
|
+ Tilt: item.tilt_angle ? item.tilt_angle : item.Tilt,
|
|
|
+ EventID: item.event_id ? item.event_id : item.EventID,
|
|
|
+ Status: item.status ? item.status : item.Status,
|
|
|
+ EventTimeFormat: dayjs(item.event_timestamp ? item.event_timestamp : item.EventTime).format(
|
|
|
+ 'YYYY-MM-DD HH:mm:ss',
|
|
|
+ ),
|
|
|
+ ImgUrlClip: data[i],
|
|
|
+ ImgUrl: item.ImgUrl ? item.ImgUrl : getFileUrl(item.image_file_name),
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+watchThrottled(
|
|
|
() => alarmStore.alarms,
|
|
|
(v) => {
|
|
|
- console.log(v)
|
|
|
+ console.log(v) // TODO
|
|
|
},
|
|
|
+ { throttle: 3000, deep: true },
|
|
|
)
|
|
|
async function getDataList() {
|
|
|
- isRequestLoading.value = true
|
|
|
- const res: any = await API_ALERT_ESEARCH_GET({ page: 1, page_size: 20 }).finally(() => {
|
|
|
- isRequestLoading.value = false
|
|
|
- })
|
|
|
+ const res: any = await API_ALERT_ESEARCH_GET({ page: 1, page_size: 20 })
|
|
|
+ console.log(res.items)
|
|
|
+
|
|
|
+ const resF = await formatData(res.items)
|
|
|
+ dataList.value = resF as RowData[]
|
|
|
+ isRequestLoading.value = false
|
|
|
+}
|
|
|
+
|
|
|
+const drawerShow = ref(false)
|
|
|
+const currentItem = ref<any>(null)
|
|
|
+const alarmShow = (item: any) => {
|
|
|
+ console.log(item)
|
|
|
|
|
|
- dataList.value = res.items.map((item: any) => ({
|
|
|
- EventId: item.event_id,
|
|
|
- EventTime: dayjs(item.event_timestamp).format('YYYY-MM-DD HH:mm:ss'),
|
|
|
- Score: item.confidence_score,
|
|
|
- Pan: item.pan_angle,
|
|
|
- Tilt: item.tilt_angle,
|
|
|
- Type: item.alarm_type,
|
|
|
- Status: item.status,
|
|
|
- imageFileName: getFileUrl(item.image_file_name),
|
|
|
- }))
|
|
|
+ if (item.event_id) {
|
|
|
+ currentItem.value = {
|
|
|
+ ...item,
|
|
|
+ ID: item.alert_id,
|
|
|
+ UsbCameraIndex: 1,
|
|
|
+ Image: item.image_file_name,
|
|
|
+ ImageData: '',
|
|
|
+ Video: item.video_file_name,
|
|
|
+ Degree: item.degree,
|
|
|
+ EventTime: item.event_timestamp,
|
|
|
+ X: item.target_x,
|
|
|
+ Y: item.target_y,
|
|
|
+ W: item.target_width,
|
|
|
+ H: item.target_height,
|
|
|
+ Score: item.confidence_score,
|
|
|
+ Type: item.alarm_type,
|
|
|
+ Pan: item.pan_angle,
|
|
|
+ Tilt: item.tilt_angle,
|
|
|
+ EventID: item.event_id,
|
|
|
+ Status: item.status,
|
|
|
+ EventTimeFormat: dayjs(item.event_timestamp).format('YYYY-MM-DD HH:mm:ss'),
|
|
|
+ ImgUrl: getFileUrl(item.image_file_name),
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ currentItem.value = item
|
|
|
+ }
|
|
|
+ drawerShow.value = true
|
|
|
}
|
|
|
|
|
|
onMounted(() => {
|
|
|
@@ -250,5 +334,6 @@ onUnmounted(() => {
|
|
|
workerObj.forEach((item: any) => {
|
|
|
item.close()
|
|
|
})
|
|
|
+ revokeBlob()
|
|
|
})
|
|
|
</script>
|