feat: 视频中心仪表盘卡片组件封装

This commit is contained in:
JiangQiming 2023-02-01 17:34:15 +08:00
parent 59e4bacd74
commit 1eda294d48
6 changed files with 219 additions and 5 deletions

View File

@ -0,0 +1,10 @@
import server from '@/utils/request'
import type { Agg, AggPlaying } from '@/views/media/DashBoard/typings'
export default {
// 录像数量
agg: () => server.get<Agg>(`/media/record/file/agg`),
// 播放中数量
aggPlaying: () => server.get<AggPlaying>(`/media/channel/playing/agg`),
}

View File

@ -0,0 +1,7 @@
<template>
<div class="page-container"></div>
</template>
<script setup lang="ts"></script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,94 @@
<template>
<div class="top-card">
<div class="top-card-content">
<div class="content-left">
<div class="content-left-title">
<span>{{ title }}</span>
<a-tooltip placement="top" v-if="tooltip">
<template #title>
<span>{{ tooltip }}</span>
</template>
<AIcon type="QuestionCircleOutlined" />
</a-tooltip>
</div>
<div class="content-left-value">{{ value }}</div>
</div>
<div class="content-right">
<img :src="img" alt="" />
</div>
</div>
<div class="top-card-footer">
<template v-for="(item, index) in footer" :key="index">
<a-badge :text="item.title" :status="item.status" />
<div class="footer-item-value">{{ item.value }}</div>
</template>
</div>
</div>
</template>
<script setup lang="ts">
import { PropType } from 'vue';
import type { Footer } from '@/views/media/DashBoard/typings';
const props = defineProps({
title: { type: String, default: '' },
tooltip: { type: String, default: '' },
img: { type: String, default: '' },
footer: { type: Array as PropType<Footer[]>, default: '' },
value: { type: Number, default: 0 },
});
</script>
<style lang="less" scoped>
.top-card {
display: flex;
flex-direction: column;
// height: 200px;
padding: 24px;
background-color: #fff;
border: 1px solid #e0e4e8;
border-radius: 2px;
.top-card-content {
display: flex;
flex-direction: row;
flex-grow: 1;
.content-left {
height: 100%;
width: 50%;
&-title {
color: rgba(0, 0, 0, 0.64);
}
&-value {
padding: 12px 0;
color: #323130;
font-weight: 700;
font-size: 36px;
}
}
.content-right {
width: 0;
height: 100%;
display: flex;
flex-grow: 1;
align-items: flex-end;
justify-content: flex-end;
img {
width: 100%;
height: 100%;
}
}
}
.top-card-footer {
display: flex;
align-items: center;
justify-content: space-between;
padding-top: 16px;
border-top: 1px solid #f0f0f0;
.footer-item-value {
color: #323130;
font-weight: 700;
font-size: 16px;
}
}
}
</style>

View File

@ -1,7 +1,93 @@
<template>
<div class="page-container">仪表盘</div>
<div class="page-container">
<a-row :gutter="24">
<a-col :span="6">
<TopCard
title="设备数量"
:img="getImage('/media/dashboard-1.png')"
:footer="deviceFooter"
:value="deviceTotal"
/>
</a-col>
<a-col :span="6">
<TopCard
title="通道数量"
:img="getImage('/media/dashboard-2.png')"
:footer="channelFooter"
:value="channelTotal"
/>
</a-col>
<a-col :span="6">
<TopCard
title="录像数量"
:img="getImage('/media/dashboard-3.png')"
:footer="aggFooter"
:value="aggTotal"
/>
</a-col>
<a-col :span="6">
<TopCard
title="播放中数量"
tooltip="当前正在播放的通道数量之和"
:img="getImage('/media/dashboard-4.png')"
:footer="aggPlayingFooter"
:value="aggPlayingTotal"
/>
</a-col>
</a-row>
</div>
</template>
<script setup lang="ts"></script>
<script setup lang="ts">
import TopCard from '@/views/media/DashBoard/components/TopCard.vue'
import { getImage } from '@/utils/comm';
import homeApi from '@/api/media/home';
import dashboardApi from '@/api/media/dashboard';
import type { Footer } from '@/views/media/DashBoard/typings';
<style lang="less" scoped></style>
//
const deviceFooter = ref<Footer[]>([]);
const deviceTotal = ref(0);
const getDeviceData = () => {
homeApi.deviceCount().then((res) => {
deviceTotal.value = res.result;
});
};
getDeviceData();
//
const channelFooter = ref<Footer[]>([]);
const channelTotal = ref(0);
const getChannelData = () => {
homeApi.channelCount().then((res) => {
channelTotal.value = res.result;
});
};
getChannelData();
//
const aggFooter = ref<Footer[]>([]);
const aggTotal = ref(0);
const getAggData = () => {
dashboardApi.agg().then((res) => {
aggTotal.value = res.result.total;
});
};
getAggData();
//
const aggPlayingFooter = ref<Footer[]>([]);
const aggPlayingTotal = ref(0);
const getAggPlayingData = () => {
dashboardApi.aggPlaying().then((res) => {
aggTotal.value = res.result.playingTotal;
});
};
getAggPlayingData();
</script>
<style lang="less" scoped>
.page-container {
padding: 24px;
}
</style>

16
src/views/media/DashBoard/typings.d.ts vendored Normal file
View File

@ -0,0 +1,16 @@
export type Agg = {
duration: number
total: number
}
export type AggPlaying = {
playerTotal: number
playingTotal: number
}
export type Footer = {
title: string;
value: number;
status?: "default" | "error" | "success" | "warning" | "processing"
}

View File

@ -13,12 +13,12 @@
<div class="box-item">
<div class="label">设备数量</div>
<div class="value">{{ deviceCount }}</div>
<img src="/images/home/top-2.png" alt="" />
<img :src="getImage('/home/top-1.png')" alt="" />
</div>
<div class="box-item">
<div class="label">通道数量</div>
<div class="value">{{ channelCount }}</div>
<img src="/images/home/top-1.png" alt="" />
<img :src="getImage('/home/top-2.png')" alt="" />
</div>
</div>
</a-card>
@ -26,6 +26,7 @@
<script setup lang="ts">
import homeApi from '@/api/media/home';
import { getImage } from '@/utils/comm';
const channelCount = ref(0);
const deviceCount = ref(0);