|
@@ -1,11 +1,14 @@
|
|
|
<script setup lang="ts">
|
|
|
import { watchDebounced } from '@vueuse/core'
|
|
|
import chroma from 'chroma-js'
|
|
|
+import dayjs from 'dayjs'
|
|
|
import * as echarts from 'echarts'
|
|
|
-import { NNumberAnimation, NTag, NCard, NButton } from 'naive-ui'
|
|
|
+import { NTag, NCard, NButton, NEmpty } from 'naive-ui'
|
|
|
import { onMounted, watch, ref, onUnmounted } from 'vue'
|
|
|
|
|
|
+import { useRequest } from '@/api'
|
|
|
import { ScrollContainer } from '@/components'
|
|
|
+import Drawer from '@/components/alarm-drawer/Drawer.vue'
|
|
|
import { toRefsPreferencesStore, toRefsAlarmStore } from '@/stores'
|
|
|
import twc from '@/utils/tailwindColor'
|
|
|
|
|
@@ -15,13 +18,15 @@ defineOptions({
|
|
|
name: 'Dashboard',
|
|
|
})
|
|
|
|
|
|
+const tF = () => dayjs().subtract(2, 'minute').format('HH:mm:ss')
|
|
|
const { sidebarMenu, navigationMode, themeColor, isDark } = toRefsPreferencesStore()
|
|
|
-const { alarms } = toRefsAlarmStore()
|
|
|
+const { alarms, alarmCount } = toRefsAlarmStore()
|
|
|
+const { API_ALERT_STATISTICS_GET } = useRequest()
|
|
|
|
|
|
const cardList = ref([
|
|
|
{
|
|
|
title: '今日告警',
|
|
|
- value: 23,
|
|
|
+ value: alarmCount,
|
|
|
suffix: '个',
|
|
|
iconClass: 'iconify ph--warning-bold text-indigo-50 dark:text-indigo-150',
|
|
|
iconBgClass:
|
|
@@ -31,7 +36,7 @@ const cardList = ref([
|
|
|
title: '数据更新频率',
|
|
|
value: 2,
|
|
|
suffix: '分钟',
|
|
|
- description: '上次更新: 10:42:15',
|
|
|
+ description: `上次更新: ${tF()}`,
|
|
|
iconClass: 'iconify ph--timer-bold text-blue-50 dark:text-blue-150',
|
|
|
iconBgClass:
|
|
|
'text-blue-500/5 bg-blue-400 ring-4 ring-blue-200 dark:bg-blue-650 dark:ring-blue-500/30 transition-all',
|
|
@@ -67,143 +72,52 @@ const createTooltipConfig = (formatter?: any) => ({
|
|
|
...(formatter && { formatter }),
|
|
|
})
|
|
|
|
|
|
+const [loading1, loading2, loading3] = [true, true, true]
|
|
|
const chartDataManager = {
|
|
|
get24HourLine: () => {
|
|
|
return new Promise((resolve) => {
|
|
|
- // 24小时活动分布
|
|
|
- resolve([
|
|
|
- {
|
|
|
- label: '00:00',
|
|
|
- value: 100,
|
|
|
- },
|
|
|
- {
|
|
|
- label: '01:00',
|
|
|
- value: 120,
|
|
|
- },
|
|
|
- {
|
|
|
- label: '02:00',
|
|
|
- value: 80,
|
|
|
- },
|
|
|
- {
|
|
|
- label: '03:00',
|
|
|
- value: 90,
|
|
|
- },
|
|
|
- {
|
|
|
- label: '04:00',
|
|
|
- value: 110,
|
|
|
- },
|
|
|
- {
|
|
|
- label: '05:00',
|
|
|
- value: 130,
|
|
|
- },
|
|
|
- {
|
|
|
- label: '06:00',
|
|
|
- value: 150,
|
|
|
- },
|
|
|
- {
|
|
|
- label: '07:00',
|
|
|
- value: 170,
|
|
|
- },
|
|
|
- {
|
|
|
- label: '08:00',
|
|
|
- value: 190,
|
|
|
- },
|
|
|
- {
|
|
|
- label: '09:00',
|
|
|
- value: 210,
|
|
|
- },
|
|
|
- {
|
|
|
- label: '10:00',
|
|
|
- value: 230,
|
|
|
- },
|
|
|
- {
|
|
|
- label: '11:00',
|
|
|
- value: 250,
|
|
|
- },
|
|
|
- {
|
|
|
- label: '12:00',
|
|
|
- value: 270,
|
|
|
- },
|
|
|
- {
|
|
|
- label: '13:00',
|
|
|
- value: 290,
|
|
|
- },
|
|
|
- {
|
|
|
- label: '14:00',
|
|
|
- value: 310,
|
|
|
- },
|
|
|
- {
|
|
|
- label: '15:00',
|
|
|
- value: 330,
|
|
|
- },
|
|
|
- {
|
|
|
- label: '16:00',
|
|
|
- value: 350,
|
|
|
- },
|
|
|
- {
|
|
|
- label: '17:00',
|
|
|
- value: 370,
|
|
|
- },
|
|
|
- {
|
|
|
- label: '18:00',
|
|
|
- value: 390,
|
|
|
- },
|
|
|
- {
|
|
|
- label: '19:00',
|
|
|
- value: 410,
|
|
|
- },
|
|
|
- {
|
|
|
- label: '20:00',
|
|
|
- value: 430,
|
|
|
- },
|
|
|
- {
|
|
|
- label: '21:00',
|
|
|
- value: 450,
|
|
|
- },
|
|
|
- {
|
|
|
- label: '22:00',
|
|
|
- value: 470,
|
|
|
- },
|
|
|
- {
|
|
|
- label: '23:00',
|
|
|
- value: 490,
|
|
|
- },
|
|
|
- ])
|
|
|
+ getStatistics('hour').then((res: any) => {
|
|
|
+ // 24小时活动分布
|
|
|
+ resolve(res.Periods.map((item: any) => ({ label: item.Period, value: item.Count })))
|
|
|
+ })
|
|
|
})
|
|
|
},
|
|
|
|
|
|
getLowestWeekLine: () => {
|
|
|
return new Promise((resolve) => {
|
|
|
- resolve([
|
|
|
- {
|
|
|
- label: '周一',
|
|
|
- value: [1000, 5000, 8000, 1000],
|
|
|
- },
|
|
|
- {
|
|
|
- label: '周二',
|
|
|
- value: [4000, 6000, 9000, 1000],
|
|
|
- },
|
|
|
- {
|
|
|
- label: '周三',
|
|
|
- value: [3000, 7000, 10000, 5000],
|
|
|
- },
|
|
|
- {
|
|
|
- label: '周四',
|
|
|
- value: [5000, 8000, 12000, 6000],
|
|
|
- },
|
|
|
- {
|
|
|
- label: '周五',
|
|
|
- value: [4000, 6000, 9000, 1000],
|
|
|
- },
|
|
|
- {
|
|
|
- label: '周六',
|
|
|
- value: [6000, 8000, 10000, 2000],
|
|
|
- },
|
|
|
- {
|
|
|
- label: '周日',
|
|
|
- value: [7000, 9000, 600, 3000],
|
|
|
- },
|
|
|
- ])
|
|
|
+ getStatistics('day').then((res: any) => {
|
|
|
+ resolve(res.Periods.map((item: any) => ({ label: item.Period, value: [item.Count] })))
|
|
|
+ })
|
|
|
+ // resolve([
|
|
|
+ // {
|
|
|
+ // label: '周一',
|
|
|
+ // value: [1000, 5000, 8000, 1000],
|
|
|
+ // },
|
|
|
+ // {
|
|
|
+ // label: '周二',
|
|
|
+ // value: [4000, 6000, 9000, 1000],
|
|
|
+ // },
|
|
|
+ // {
|
|
|
+ // label: '周三',
|
|
|
+ // value: [3000, 7000, 10000, 5000],
|
|
|
+ // },
|
|
|
+ // {
|
|
|
+ // label: '周四',
|
|
|
+ // value: [5000, 8000, 12000, 6000],
|
|
|
+ // },
|
|
|
+ // {
|
|
|
+ // label: '周五',
|
|
|
+ // value: [4000, 6000, 9000, 1000],
|
|
|
+ // },
|
|
|
+ // {
|
|
|
+ // label: '周六',
|
|
|
+ // value: [6000, 8000, 10000, 2000],
|
|
|
+ // },
|
|
|
+ // {
|
|
|
+ // label: '周日',
|
|
|
+ // value: [7000, 9000, 600, 3000],
|
|
|
+ // },
|
|
|
+ // ])
|
|
|
})
|
|
|
},
|
|
|
|
|
@@ -219,41 +133,40 @@ const chartDataManager = {
|
|
|
},
|
|
|
}
|
|
|
|
|
|
-async function initRevenueChart() {
|
|
|
- if (!revenueChart.value) return
|
|
|
+const initRevenueChartOption = async (chart: ECharts) => {
|
|
|
const lineData = (await chartDataManager.getLowestWeekLine()) as Array<{
|
|
|
label: string
|
|
|
value: number
|
|
|
}>
|
|
|
+ chart.hideLoading()
|
|
|
const lineX = lineData.map((item) => item.label)
|
|
|
const lineY = lineData.map((item) => item.value)
|
|
|
|
|
|
const legend = [
|
|
|
{
|
|
|
name: '大型鸟类',
|
|
|
- color: '#EF4444', // 红色
|
|
|
+ color: themeColor.value, // 红色
|
|
|
data: lineY.map((data: any) => data[0]),
|
|
|
},
|
|
|
- {
|
|
|
- name: '中型鸟类',
|
|
|
- color: '#F59E0B', // 黄色
|
|
|
- data: lineY.map((data: any) => data[1]),
|
|
|
- },
|
|
|
- {
|
|
|
- name: '小型鸟类',
|
|
|
- color: '#3B82F6', // 蓝色
|
|
|
- data: lineY.map((data: any) => data[2]),
|
|
|
- },
|
|
|
- {
|
|
|
- name: '未知',
|
|
|
- color: '#10B981', // 绿色
|
|
|
- data: lineY.map((data: any) => data[3]),
|
|
|
- },
|
|
|
+ // {
|
|
|
+ // name: '中型鸟类',
|
|
|
+ // color: '#F59E0B', // 黄色
|
|
|
+ // data: lineY.map((data: any) => data[1]),
|
|
|
+ // },
|
|
|
+ // {
|
|
|
+ // name: '小型鸟类',
|
|
|
+ // color: '#3B82F6', // 蓝色
|
|
|
+ // data: lineY.map((data: any) => data[2]),
|
|
|
+ // },
|
|
|
+ // {
|
|
|
+ // name: '未知',
|
|
|
+ // color: '#10B981', // 绿色
|
|
|
+ // data: lineY.map((data: any) => data[3]),
|
|
|
+ // },
|
|
|
]
|
|
|
|
|
|
- const chart = echarts.init(revenueChart.value)
|
|
|
-
|
|
|
const option = {
|
|
|
+ loading3,
|
|
|
title: [
|
|
|
{
|
|
|
text: '周活动趋势',
|
|
@@ -296,7 +209,7 @@ async function initRevenueChart() {
|
|
|
},
|
|
|
grid: {
|
|
|
left: 20,
|
|
|
- right: 20,
|
|
|
+ right: 38,
|
|
|
top: 72,
|
|
|
bottom: 0,
|
|
|
containLabel: true,
|
|
@@ -313,6 +226,7 @@ async function initRevenueChart() {
|
|
|
},
|
|
|
splitLine: {
|
|
|
show: true,
|
|
|
+ rotate: 'auto',
|
|
|
lineStyle: {
|
|
|
type: 'dashed',
|
|
|
color: isDark.value ? 'rgba(255, 255, 255, 0.08)' : 'rgba(0, 0, 0, 0.08)',
|
|
@@ -328,10 +242,6 @@ async function initRevenueChart() {
|
|
|
axisLabel: {
|
|
|
color: isDark.value ? twc.neutral[400] : twc.neutral[600],
|
|
|
fontSize: 11,
|
|
|
- formatter(value: number) {
|
|
|
- if (value === 0) return '0'
|
|
|
- return `${(value / 1000).toFixed(0)},000`
|
|
|
- },
|
|
|
},
|
|
|
splitLine: {
|
|
|
show: true,
|
|
@@ -347,7 +257,7 @@ async function initRevenueChart() {
|
|
|
type: 'line',
|
|
|
data: line.data,
|
|
|
symbol: 'circle',
|
|
|
- showSymbol: false,
|
|
|
+ symbolSize: 6,
|
|
|
smooth: true,
|
|
|
lineStyle: {
|
|
|
color: line.color,
|
|
@@ -389,23 +299,24 @@ async function initRevenueChart() {
|
|
|
}
|
|
|
|
|
|
chart.setOption(option)
|
|
|
+}
|
|
|
|
|
|
+async function initRevenueChart() {
|
|
|
+ if (!revenueChart.value) return
|
|
|
+ const chart = echarts.init(revenueChart.value)
|
|
|
+ chart?.showLoading()
|
|
|
+ initRevenueChartOption(chart)
|
|
|
revenueChartInstance = chart
|
|
|
revenueChartResizeHandler = () => chart.resize()
|
|
|
window.addEventListener('resize', revenueChartResizeHandler, { passive: true })
|
|
|
}
|
|
|
|
|
|
-async function initMonthlyRadarChart() {
|
|
|
- if (!monthlyRadarChart.value) return
|
|
|
-
|
|
|
- // const now = new Date()
|
|
|
- // const currentDay = now.getDay()
|
|
|
-
|
|
|
+const initMonthlyRadarChartOption = async (chart: ECharts) => {
|
|
|
const currentDayData = await chartDataManager.getCurrentDayData()
|
|
|
-
|
|
|
- const chart = echarts.init(monthlyRadarChart.value)
|
|
|
+ chart.hideLoading()
|
|
|
|
|
|
const option = {
|
|
|
+ loading1,
|
|
|
title: {
|
|
|
text: '鸟类分布图',
|
|
|
textStyle: {
|
|
@@ -446,24 +357,31 @@ async function initMonthlyRadarChart() {
|
|
|
}
|
|
|
|
|
|
chart.setOption(option)
|
|
|
+}
|
|
|
+
|
|
|
+async function initMonthlyRadarChart() {
|
|
|
+ if (!monthlyRadarChart.value) return
|
|
|
+
|
|
|
+ // const now = new Date()
|
|
|
+ // const currentDay = now.getDay()
|
|
|
+
|
|
|
+ const chart = echarts.init(monthlyRadarChart.value)
|
|
|
+ chart?.showLoading()
|
|
|
+ initMonthlyRadarChartOption(chart)
|
|
|
monthlyRadarChartInstance = chart
|
|
|
monthlyRadarChartResizeHandler = () => chart.resize()
|
|
|
window.addEventListener('resize', monthlyRadarChartResizeHandler, { passive: true })
|
|
|
}
|
|
|
-
|
|
|
-async function initHighestRevenueChart() {
|
|
|
- if (!highestRevenueChart.value) return
|
|
|
-
|
|
|
+const initHighestRevenueChartOption = async (chart: ECharts) => {
|
|
|
const twentyFourHourLine = (await chartDataManager.get24HourLine()) as Array<{
|
|
|
label: string
|
|
|
value: number
|
|
|
}>
|
|
|
+ chart.hideLoading()
|
|
|
const xAxisData = twentyFourHourLine.map((item) => item.label)
|
|
|
const seriesData = twentyFourHourLine.map((item) => item.value)
|
|
|
-
|
|
|
- const chart = echarts.init(highestRevenueChart.value)
|
|
|
-
|
|
|
const option = {
|
|
|
+ loading2,
|
|
|
title: {
|
|
|
text: '24小时活动分布',
|
|
|
textStyle: {
|
|
@@ -512,6 +430,9 @@ async function initHighestRevenueChart() {
|
|
|
axisTick: {
|
|
|
alignWithLabel: true,
|
|
|
},
|
|
|
+ axisLabel: {
|
|
|
+ rotate: 45,
|
|
|
+ },
|
|
|
splitLine: {
|
|
|
show: true,
|
|
|
lineStyle: {
|
|
@@ -547,15 +468,42 @@ async function initHighestRevenueChart() {
|
|
|
}
|
|
|
|
|
|
chart.setOption(option)
|
|
|
+}
|
|
|
+async function initHighestRevenueChart() {
|
|
|
+ if (!highestRevenueChart.value) return
|
|
|
+
|
|
|
+ const chart = echarts.init(highestRevenueChart.value)
|
|
|
+ chart?.showLoading()
|
|
|
+ initHighestRevenueChartOption(chart)
|
|
|
highestRevenueChartInstance = chart
|
|
|
highestRevenueChartResizeHandler = () => chart.resize()
|
|
|
window.addEventListener('resize', highestRevenueChartResizeHandler, { passive: true })
|
|
|
}
|
|
|
+// hour (24小时) day (7天) month (30天)
|
|
|
+const getStatistics = (periodType: 'hour' | 'day' | 'month') => {
|
|
|
+ return new Promise((resolve) => {
|
|
|
+ API_ALERT_STATISTICS_GET({ periodType }).then((res) => {
|
|
|
+ resolve(res)
|
|
|
+ })
|
|
|
+ })
|
|
|
+}
|
|
|
|
|
|
-onMounted(() => {
|
|
|
+const initEcharts = () => {
|
|
|
initRevenueChart()
|
|
|
initMonthlyRadarChart()
|
|
|
initHighestRevenueChart()
|
|
|
+}
|
|
|
+
|
|
|
+let timer: any = null
|
|
|
+onMounted(() => {
|
|
|
+ initEcharts()
|
|
|
+ // 两分钟更新一次
|
|
|
+ timer = setInterval(() => {
|
|
|
+ if (revenueChartInstance) initRevenueChartOption(revenueChartInstance)
|
|
|
+ if (monthlyRadarChartInstance) initMonthlyRadarChartOption(monthlyRadarChartInstance)
|
|
|
+ if (highestRevenueChartInstance) initHighestRevenueChartOption(highestRevenueChartInstance)
|
|
|
+ cardList.value[1].description = `上次更新: ${tF()}`
|
|
|
+ }, 120000)
|
|
|
})
|
|
|
|
|
|
onUnmounted(() => {
|
|
@@ -590,20 +538,10 @@ onUnmounted(() => {
|
|
|
clearTimeout(collapseResizeTimeout)
|
|
|
collapseResizeTimeout = null
|
|
|
}
|
|
|
+ if (timer) clearInterval(timer)
|
|
|
})
|
|
|
|
|
|
-function resizeAllCharts() {
|
|
|
- if (revenueChartInstance) revenueChartInstance.resize()
|
|
|
- if (monthlyRadarChartInstance) monthlyRadarChartInstance.resize()
|
|
|
- if (highestRevenueChartInstance) highestRevenueChartInstance.resize()
|
|
|
-}
|
|
|
-
|
|
|
-watchDebounced([() => sidebarMenu.value, () => navigationMode.value], resizeAllCharts, {
|
|
|
- debounce: 300,
|
|
|
- deep: true,
|
|
|
-})
|
|
|
-
|
|
|
-watch([isDark, themeColor], () => {
|
|
|
+function clearCharts() {
|
|
|
if (revenueChartInstance) {
|
|
|
if (revenueChartResizeHandler) {
|
|
|
window.removeEventListener('resize', revenueChartResizeHandler)
|
|
@@ -630,11 +568,30 @@ watch([isDark, themeColor], () => {
|
|
|
highestRevenueChartInstance.dispose()
|
|
|
highestRevenueChartInstance = null
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- initRevenueChart()
|
|
|
- initMonthlyRadarChart()
|
|
|
- initHighestRevenueChart()
|
|
|
+function resizeAllCharts() {
|
|
|
+ if (revenueChartInstance) revenueChartInstance.resize()
|
|
|
+ if (monthlyRadarChartInstance) monthlyRadarChartInstance.resize()
|
|
|
+ if (highestRevenueChartInstance) highestRevenueChartInstance.resize()
|
|
|
+}
|
|
|
+
|
|
|
+watchDebounced([() => sidebarMenu.value, () => navigationMode.value], resizeAllCharts, {
|
|
|
+ debounce: 300,
|
|
|
+ deep: true,
|
|
|
+})
|
|
|
+
|
|
|
+watch([isDark, themeColor], () => {
|
|
|
+ clearCharts()
|
|
|
+ initEcharts()
|
|
|
})
|
|
|
+
|
|
|
+const drawerShow = ref(false)
|
|
|
+const currentItem = ref(null)
|
|
|
+const alarmShow = (item: any) => {
|
|
|
+ currentItem.value = item
|
|
|
+ drawerShow.value = true
|
|
|
+}
|
|
|
</script>
|
|
|
<template>
|
|
|
<ScrollContainer wrapper-class="flex flex-col gap-y-4 max-sm:gap-y-2">
|
|
@@ -649,10 +606,11 @@ watch([isDark, themeColor], () => {
|
|
|
<div
|
|
|
class="mt-1 mb-1.5 flex items-center gap-x-4 text-2xl text-neutral-700 dark:text-neutral-400"
|
|
|
>
|
|
|
- <NNumberAnimation
|
|
|
+ <!-- <NNumberAnimation
|
|
|
:to="value"
|
|
|
show-separator
|
|
|
- />
|
|
|
+ /> -->
|
|
|
+ <span>{{ value }}</span>
|
|
|
<span class="text-lg text-neutral-500 dark:text-neutral-400">{{ suffix }}</span>
|
|
|
</div>
|
|
|
<div class="flex items-center">
|
|
@@ -702,60 +660,72 @@ watch([isDark, themeColor], () => {
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div class="overflow-hidden rounded bg-naive-card p-6 shadow-xs transition-[background-color]">
|
|
|
+ <div
|
|
|
+ class="overflow-hidden rounded bg-naive-card p-6 shadow-xs transition-[background-color] lg:h-[193px]"
|
|
|
+ >
|
|
|
<div class="mb-4 flex items-center gap-x-2">
|
|
|
<span class="iconify text-xl ph--warning-bold"></span>
|
|
|
<span class="text-xl font-medium text-neutral-750 dark:text-neutral-400">最近告警</span>
|
|
|
</div>
|
|
|
- <div class="grid grid-cols-1 gap-4 max-sm:gap-2 md:grid-cols-2 lg:grid-cols-4">
|
|
|
- <NCard
|
|
|
- v-for="item in alarms"
|
|
|
- :key="item.id"
|
|
|
+ <NEmpty
|
|
|
+ v-if="!alarms.length"
|
|
|
+ description="暂无告警"
|
|
|
+ ></NEmpty>
|
|
|
+ <div class="grid grid-cols-1 gap-4 max-sm:gap-2 md:grid-cols-1 lg:grid-cols-4">
|
|
|
+ <TransitionGroup
|
|
|
+ type="animation"
|
|
|
+ enter-active-class="animate__animated animate__fadeInLeft"
|
|
|
+ leave-active-class="animate__animated animate__fadeOutRight"
|
|
|
>
|
|
|
- <div class="flex items-center justify-between">
|
|
|
- <div class="flex flex-1 gap-x-3">
|
|
|
- <img
|
|
|
- class="size-15 object-cover"
|
|
|
- :src="item.img"
|
|
|
- alt="鸟图"
|
|
|
- />
|
|
|
- <div class="flex flex-1 flex-col justify-between">
|
|
|
- <div>
|
|
|
- <span
|
|
|
- v-if="item.type === 'large'"
|
|
|
- class="rounded-xl bg-red-500 px-2 py-1 text-white"
|
|
|
- >大型鸟类</span
|
|
|
- >
|
|
|
- <span
|
|
|
- v-else-if="item.type === 'medium'"
|
|
|
- class="rounded-xl bg-yellow-500 px-2 py-1 text-white"
|
|
|
- >中型鸟类</span
|
|
|
- >
|
|
|
- <span
|
|
|
- v-else
|
|
|
- class="rounded-xl bg-green-500 px-2 py-1 text-white"
|
|
|
- >小型鸟类</span
|
|
|
- >
|
|
|
- <span class="ml-2">{{ item.location }}</span>
|
|
|
- </div>
|
|
|
- <div class="text-xs text-neutral-500 dark:text-neutral-400">
|
|
|
- <span>{{ item.timestamp }}</span>
|
|
|
+ <NCard
|
|
|
+ v-for="item in alarms"
|
|
|
+ :key="item.id"
|
|
|
+ >
|
|
|
+ <div class="flex items-center justify-between">
|
|
|
+ <div class="flex flex-1 gap-x-3">
|
|
|
+ <img
|
|
|
+ class="size-15 object-cover"
|
|
|
+ :src="item.img"
|
|
|
+ alt="鸟图"
|
|
|
+ />
|
|
|
+ <div class="flex flex-1 flex-col justify-between">
|
|
|
+ <div class="whitespace-nowrap">
|
|
|
+ <span
|
|
|
+ v-if="item.type === 'large'"
|
|
|
+ class="rounded-xl bg-red-500 px-2 py-1 text-white"
|
|
|
+ >大型鸟类</span
|
|
|
+ >
|
|
|
+ <span
|
|
|
+ v-else-if="item.type === 'medium'"
|
|
|
+ class="rounded-xl bg-yellow-500 px-2 py-1 text-white"
|
|
|
+ >中型鸟类</span
|
|
|
+ >
|
|
|
+ <span
|
|
|
+ v-else
|
|
|
+ class="rounded-xl bg-green-500 px-2 py-1 text-white"
|
|
|
+ >小型鸟类</span
|
|
|
+ >
|
|
|
+ <span class="ml-2">{{ item.location }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="text-xs text-neutral-500 dark:text-neutral-400">
|
|
|
+ <span>{{ item.timestamp }}</span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+ <div>
|
|
|
+ <NButton
|
|
|
+ size="medium"
|
|
|
+ strong
|
|
|
+ secondary
|
|
|
+ circle
|
|
|
+ @click="alarmShow(item)"
|
|
|
+ >
|
|
|
+ <span class="iconify ph--eye"></span>
|
|
|
+ </NButton>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <div>
|
|
|
- <NButton
|
|
|
- size="medium"
|
|
|
- strong
|
|
|
- secondary
|
|
|
- circle
|
|
|
- @click="() => {}"
|
|
|
- >
|
|
|
- <span class="iconify ph--eye"></span>
|
|
|
- </NButton>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </NCard>
|
|
|
+ </NCard>
|
|
|
+ </TransitionGroup>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
@@ -796,5 +766,6 @@ watch([isDark, themeColor], () => {
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+ <Drawer v-model="drawerShow" :currentItem="currentItem"> 123123 </Drawer>
|
|
|
</ScrollContainer>
|
|
|
</template>
|