123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447 |
- <template>
- <div class="page">
- <div class="flex-row" style="gap: 12px">
- <el-card shadow="nover">
- <div class="title flex-row">
- <div class="">
- 今日告警 <el-tag size="small">{{ todayCount.currentDayCount }}</el-tag>
- </div>
- <div>
- 本月告警 <el-tag size="small">{{ todayCount.currentMonthCount }}</el-tag>
- </div>
- </div>
- <VueUiXy v-if="dataset?.length" :config="config" :dataset="dataset" />
- <VueUiSkeleton v-else :config="{ type: 'bar' }" />
- </el-card>
- <el-card shadow="nover">
- <div class="title">告警设备top10</div>
- <VueUiXy v-if="dataset2?.length" :config="config2" :dataset="dataset2" />
- <VueUiSkeleton v-else :config="{ type: 'bar' }" />
- </el-card>
- <el-card shadow="nover">
- <div class="title">最新告警</div>
- <el-table class="flex1" :data="alarmNewList" border style="width: 100%" size="small">
- <el-table-column prop="createdAt" label="告警日期" width="140" align="center" />
- <el-table-column prop="status" :formatter="(row:any) => (row.status ? '已处理' : '未处理')" label="告警状态" width="70" align="center" />
- <el-table-column prop="level" label="告警等级" :formatter="(row:any) => typeFormat(row.level)" width="100" align="center" />
- <el-table-column prop="ruleName" label="告警说明" show-overflow-tooltip aign="center" />
- </el-table>
- </el-card>
- </div>
- <div class="flex-row" style="gap: 12px">
- <el-card shadow="nover">
- <div class="title">
- 告警统计
- <el-date-picker
- v-model="dateRange"
- type="daterange"
- range-separator="至"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- @change="getAlarmStatistics"
- format="YYYY-MM-DD"
- value-format="YYYY-MM-DD"
- size="small"
- style="max-width: 200px"
- :clearable="false"
- :disabledDate="disabledDate"
- />
- </div>
- <VueUiXy v-if="dataset4?.length" :config="config4" :dataset="dataset4" />
- <VueUiSkeleton v-else :config="{ type: 'bar' }" />
- </el-card>
- <el-card shadow="nover">
- <div class="title">告警增长趋势</div>
- <VueUiXy v-if="dataset5?.length" :config="config5" :dataset="dataset5" />
- <VueUiSkeleton v-else :config="{ type: 'donut' }" />
- </el-card>
- <el-card shadow="nover">
- <div class="title">
- 部门告警分析
- <el-date-picker
- v-model="deptAlarmDate"
- type="daterange"
- range-separator="至"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- @change="getDeptAlarm"
- format="YYYY-MM-DD"
- value-format="YYYY-MM-DD"
- size="small"
- style="max-width: 200px"
- :clearable="false"
- :disabledDate="disabledDate"
- />
- </div>
- <VueUiXy v-if="dataset6?.length" :config="config6" :dataset="dataset6" />
- <VueUiSkeleton v-else :config="{ type: 'bar' }" />
- </el-card>
- </div>
- <div class="flex-row" style="gap: 12px">
- <el-card shadow="nover">
- <div class="title">
- 告警状态
- <el-date-picker
- v-model="alarmStatusDate"
- type="daterange"
- range-separator="至"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- @change="getAlarmStatus"
- format="YYYY-MM-DD"
- value-format="YYYY-MM-DD"
- size="small"
- style="max-width: 200px"
- :clearable="false"
- :disabledDate="disabledDate"
- />
- </div>
- <VueUiDonut v-if="dataset7?.length" :config="config7" :dataset="dataset7" />
- <VueUiSkeleton v-else :config="{ type: 'donut' }" />
- </el-card>
- <el-card shadow="nover">
- <div class="title">
- 告警等级
- <el-date-picker
- v-model="alarmLevelDate"
- type="daterange"
- range-separator="至"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- format="YYYY-MM-DD"
- value-format="YYYY-MM-DD"
- @change="getAlarmLevel"
- size="small"
- style="max-width: 200px"
- :clearable="false"
- :disabledDate="disabledDate"
- />
- </div>
- <VueUiXy v-if="dataset9?.length" :config="config9" :dataset="dataset9" />
- <VueUiSkeleton v-else :config="{ type: 'bar' }" />
- </el-card>
- <el-card shadow="nover">
- <div class="title">
- 告警类型
- <el-date-picker
- v-model="alarmTypeDate"
- type="daterange"
- range-separator="至"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- format="YYYY-MM-DD"
- value-format="YYYY-MM-DD"
- @change="getAlarmType"
- size="small"
- style="max-width: 200px"
- :clearable="false"
- :disabledDate="disabledDate"
- />
- </div>
- <VueUiDonut v-if="dataset8?.length" :config="config8" :dataset="dataset8" />
- <VueUiSkeleton v-else :config="{ type: 'donut' }" />
- </el-card>
- </div>
- </div>
- </template>
- <script lang="ts" setup>
- import { unref, reactive, getCurrentInstance, ref } from 'vue'
- import { VueUiXy, VueUiDonut, VueUiSkeleton } from 'vue-data-ui'
- import 'vue-data-ui/style.css'
- import { getBarData, getPieSmallData } from '/@/utils/dataUiOptions'
- import api from '/@/api/alarm'
- import { useThemeChange } from '/@/hooks/useCommon'
- import dayjs from 'dayjs'
- const { proxy } = getCurrentInstance() as any
- const { alarm_type } = proxy.useDict('alarm_type')
- const disabledDate = (time: any) => time.getTime() > Date.now()
- function typeFormat(type: string) {
- return proxy.selectDictLabel(unref(alarm_type), type)
- }
- const config = ref<any>({})
- const config2 = ref<any>({})
- const config4 = ref<any>({})
- const config5 = ref<any>({})
- const config6 = ref<any>({})
- const config7 = ref<any>({})
- const config8 = ref<any>({})
- const config9 = ref<any>({})
- const dataset = ref<any[]>([])
- const dataset2 = ref<any[]>([])
- const dataset4 = ref<any[]>([])
- const dataset5 = ref<any[]>([])
- const dataset6 = ref<any[]>([])
- const dataset7 = ref<any[]>([])
- const dataset8 = ref<any[]>([])
- const dataset9 = ref<any[]>([])
- // 监听暗黑模式变化,将 vue-data-ui 的 config 传进来,就能自动更新主题
- useThemeChange([config, config2, config4, config5, config6, config7, config8, config9])
- const todayCount = reactive({
- currentDayCount: '-',
- currentMonthCount: '-',
- })
- const alarmNewList = ref<any[]>([])
- const defaultDateRange = [dayjs().subtract(7, 'day').format('YYYY-MM-DD'), dayjs().format('YYYY-MM-DD')]
- const dateRange = ref([...defaultDateRange])
- const analyzeTrendDate = ref(dayjs().format('YYYY-MM'))
- const deptAlarmDate = ref([...defaultDateRange])
- const alarmStatusDate = ref([...defaultDateRange])
- const alarmTypeDate = ref([...defaultDateRange])
- const alarmLevelDate = ref([...defaultDateRange])
- getData()
- function getData() {
- // 今日告警信息
- api.dashboard.getCurrentDayInfo().then((res: any) => {
- const list = res?.data.alarmList || []
- todayCount.currentDayCount = res?.data?.currentDayCount
- todayCount.currentMonthCount = res?.data?.currentMonthCount
- const chartData = getBarData({
- xAxis: list.map((item: any) => item.alarmDate),
- legend: ['今日告警'],
- datas: [list.map((item: any) => item.alarmCount)],
- width: 300,
- height: 300,
- colors: ['#4B79F2'],
- modulo: 3,
- responsive: true,
- })
- config.value = chartData.config
- dataset.value = chartData.dataset
- })
- // 最新告警
- api.dashboard.getAlarmNewList().then((res: any) => {
- alarmNewList.value = res || []
- })
- // 告警统计
- getAlarmStatistics()
- // 告警趋势统计
- getAnalyzeTrend()
- // 部门告警统计
- getDeptAlarm()
- // 告警状态统计
- getAlarmStatus()
- // 告警类型统计
- getAlarmType()
- // 告警等级统计
- getAlarmLevel()
- // 告警设备top10
- api.dashboard.getDeviceAlarmTop10().then((res: any) => {
- const list = res || []
- const chartData = getBarData({
- xAxis: list.map((item: any) => item.deviceName),
- legend: ['告警设备top10'],
- datas: [list.map((item: any) => item.alarmCount)],
- colors: ['#FF7D5C'],
- responsive: true,
- })
- config2.value = chartData.config
- dataset2.value = chartData.dataset
- })
- }
- function getAlarmStatistics() {
- api.dashboard
- .getAlarmStatistics({
- startDate: dateRange.value[0],
- endDate: dateRange.value[1],
- })
- .then((res: any) => {
- const list = res || []
- const chartData = getBarData({
- xAxis: list.map((item: any) => item.alarmDate),
- legend: ['告警统计'],
- datas: [list.map((item: any) => item.alarmCount || 0)],
- modulo: 3,
- colors: ['#5AD8A6'],
- responsive: true,
- })
- config4.value = chartData.config
- dataset4.value = chartData.dataset
- })
- }
- function getAnalyzeTrend() {
- api.dashboard
- .getAnalyzeTrend({
- searchMonth: analyzeTrendDate.value,
- })
- .then((res: any) => {
- const list = res || []
- const chartData = getBarData({
- xAxis: list.map((item: any) => item.month),
- legend: ['部门告警'],
- datas: [list.map((item: any) => item.alarmCount)],
- modulo: 5,
- colors: ['#FFB64D'],
- responsive: true,
- })
- config5.value = chartData.config
- dataset5.value = chartData.dataset
- })
- }
- function getDeptAlarm() {
- api.dashboard
- .getDeptAlarm({
- startDate: deptAlarmDate.value[0],
- endDate: deptAlarmDate.value[1],
- })
- .then((res: any) => {
- const list = res || []
- const chartData = getBarData({
- xAxis: list.map((item: any) => item.deptName),
- legend: ['部门告警'],
- datas: [list.map((item: any) => item.alarmCount)],
- modulo: 5,
- colors: ['#5B8FF9'],
- responsive: true,
- })
- config6.value = chartData.config
- dataset6.value = chartData.dataset
- })
- }
- function getAlarmStatus() {
- api.dashboard
- .getAlarmStatus({
- startDate: alarmStatusDate.value[0],
- endDate: alarmStatusDate.value[1],
- })
- .then((res: any) => {
- const list = res || []
- const chartData = getPieSmallData({
- legend: list.map((item: any) => (item.status === '1' ? '已处理' : '未处理')),
- datas: list.map((item: any) => [item.alarmCount]),
- colors: ['#5AD8A6', '#E86452'],
- responsive: true,
- })
- config7.value = chartData.config
- dataset7.value = chartData.dataset
- })
- }
- function getAlarmType() {
- api.dashboard
- .getAlarmType({
- startDate: alarmTypeDate.value[0],
- endDate: alarmTypeDate.value[1],
- })
- .then((res: any) => {
- const list = res || []
- const chartData = getPieSmallData({
- legend: list.map((item: any) => (item.alarmType === '1' ? '规则告警' : '自助上报告警')),
- datas: list.map((item: any) => [item.alarmCount]),
- colors: ['#7453E5', '#FFB64D'],
- responsive: true,
- })
- config8.value = chartData.config
- dataset8.value = chartData.dataset
- })
- }
- function getAlarmLevel() {
- api.dashboard
- .getAlarmLevel({
- startDate: alarmLevelDate.value[0],
- endDate: alarmLevelDate.value[1],
- })
- .then((res: any) => {
- const list = res || []
- const chartData = getBarData({
- xAxis: list.map((item: any) => item.levelName),
- legend: ['告警等级'],
- datas: [list.map((item: any) => item.alarmCount)],
- modulo: 3,
- colors: ['#269A99'],
- responsive: true,
- })
- config9.value = chartData.config
- dataset9.value = chartData.dataset
- })
- }
- </script>
- <style scoped lang="scss">
- .page {
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- gap: 12px;
- .vue-ui-skeleton {
- height: 100%;
- & ::v-deep > svg {
- height: 100%;
- }
- }
- .title {
- font-size: 14px;
- color: #333;
- font-weight: 500;
- line-height: 1;
- height: 24px;
- min-height: 24px;
- margin-bottom: 6px;
- display: flex;
- align-items: center;
- justify-content: space-between;
- }
- .flex-row {
- flex: 1;
- .el-card {
- height: 100%;
- flex: 1;
- // overflow: hidden;
- box-sizing: border-box;
- & ::v-deep .el-card__body {
- padding: 1.5vh 1vw;
- // gap: 10px;
- height: 100%;
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- // overflow: hidden;
- .vue-ui-xy,
- .vue-ui-donut,
- .vue-ui-skeleton {
- // flex: 1 !important;
- height: calc(100% - 30px) !important;
- // overflow: auto;
- // display: flex;
- // flex-direction: column;
- // justify-content: center;
- // align-items: center;
- &-svg {
- height: 100%;
- }
- .vue-data-ui-fulscreen--off {
- height: 100%;
- }
- }
- .vue-ui-skeleton {
- overflow: hidden;
- }
- }
- }
- }
- }
- </style>
|