图标组件化页面

This commit is contained in:
龚皓 2024-09-30 15:46:37 +08:00
parent d423ea00c0
commit 8acedde40f
2 changed files with 435 additions and 269 deletions

View File

@ -3,189 +3,298 @@
<el-card class="alert-card"> <el-card class="alert-card">
<div class="alert-header">告警趋势</div> <div class="alert-header">告警趋势</div>
<el-tabs v-model="activeName" @tab-click="handleClick" class="alert-tabs"> <el-tabs v-model="activeName" @tab-click="handleClick" class="alert-tabs">
<el-tab-pane label="前一天" name="first">前一天数据</el-tab-pane> <el-tab-pane label="今日" name="first">
<el-tab-pane label="3天" name="second">近3天数据展示</el-tab-pane> <div ref="todayLineChartDom" class="chart-container"></div> <!-- 今日图表 -->
</el-tab-pane>
<el-tab-pane label="本周" name="second">
<div ref="weekLineChartDom" class="chart-container"></div> <!-- 本周图表 -->
</el-tab-pane>
</el-tabs> </el-tabs>
<div id="alertChart" class="chart-container"></div>
</el-card> </el-card>
</div> </div>
</template> </template>
<script> <script setup>
import { ref, onMounted, watch } from 'vue';
import * as echarts from 'echarts'; import * as echarts from 'echarts';
import { login, getEvents } from '@/utils/superbox.js'; import dayjs from 'dayjs';
import { BoxApi } from '@/utils/boxApi.ts'; // 使 BoxApi
const username = 'turingvideo'; const activeName = ref('first');
const password = '1234qwer!'; const hourlyCounts = ref(Array(24).fill(0)); // 24
const dailyCounts = ref(Array(7).fill(0)); // 7
const weekDates = ref([]); // 7
const chartInstanceToday = ref(null);
const chartInstanceWeek = ref(null);
const todayLineChartDom = ref(null);
const weekLineChartDom = ref(null);
export default { const apiInstance = new BoxApi(); // BoxApi
name: 'AlertChart',
data() { // 7
return { const calculateWeekDates = () => {
activeName: 'first', const today = dayjs();
eventsData: [] weekDates.value = Array.from({ length: 7 }, (_, i) => today.subtract(i, 'day').format('YYYY-MM-DD')).reverse();
}; };
//
const initWeekChart = () => {
if (weekLineChartDom.value) {
chartInstanceWeek.value = echarts.init(weekLineChartDom.value);
const option = {
title: {
text: '最近7天告警数量趋势',
top: '5%',
textStyle: {
color: '#fff',
fontSize: 18,
fontWeight: 'bold'
}
}, },
async created() { tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
},
formatter: function (params) {
const { value } = params[0];
return `告警数量: ${value}`;
},
textStyle: {
color: '#fff',
fontSize: 12
}
},
xAxis: {
type: 'category',
boundaryGap: true,
data: weekDates.value.length > 0 ? weekDates.value : Array.from({ length: 7 }, (_, i) => `日期 ${i+1}`),
axisLabel: {
rotate: 0,
interval: 0,
color: '#fff',
fontSize: 12
}
},
yAxis: {
type: 'value',
min: 0,
minInterval: 1,
axisLabel: {
color: '#fff',
fontSize: 12
}
},
series: [
{
name: '告警数量',
type: 'line',
data: dailyCounts.value.length > 0 ? dailyCounts.value : Array(7).fill(0),
smooth: true,
label: {
show: true,
position: 'top',
textStyle: {
color: '#fff',
fontSize: 12
}
}
}
]
};
chartInstanceWeek.value.setOption(option);
}
};
//
const initTodayChart = () => {
if (todayLineChartDom.value) {
chartInstanceToday.value = echarts.init(todayLineChartDom.value);
const option = {
title: {
text: '今日告警数量趋势',
top: '3%',
textStyle: {
color: '#fff',
fontWeight: 'bold'
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
},
formatter: function (params) {
const { value, name } = params[0];
return `${name}<br/>告警数量: ${value}`;
},
textStyle: {
color: '#fff',
fontSize: 12
}
},
xAxis: {
type: 'category',
boundaryGap: false,
data: Array.from({ length: 24 }, (_, i) => `${i.toString().padStart(2, '0')}:00`),
axisLabel: {
rotate: 0,
color: '#fff',
}
},
yAxis: {
type: 'value',
min: 0,
minInterval: 1,
axisLabel: {
color: '#fff',
}
},
series: [
{
name: '告警数量',
type: 'line',
data: hourlyCounts.value.length > 0 ? hourlyCounts.value : Array(24).fill(0),
smooth: true,
label: {
show: true,
position: 'top',
textStyle: {
color: '#fff',
}
}
}
]
};
chartInstanceToday.value.setOption(option);
}
};
//
const fetchAndProcessEvents = async (token) => {
try { try {
const token = await login(username, password); let currentPage = 1;
this.eventsData = await getEvents(token); const pageSize = 2000; // 100
this.initChart(); let allEvents = [];
//
const { tableData: firstBatch, totalItems } = await apiInstance.getEvents(token, pageSize, currentPage);
allEvents = [...firstBatch];
//
const totalPages = Math.ceil(totalItems / pageSize);
//
while (currentPage < totalPages) {
currentPage++;
const { tableData: nextBatch } = await apiInstance.getEvents(token, pageSize, currentPage);
allEvents = [...allEvents, ...nextBatch];
//
processEventData(allEvents);
}
//
processEventData(allEvents);
} catch (error) { } catch (error) {
console.error("Error fetching events:", error); console.error("Error fetching events:", error);
} }
}, };
methods: {
handleClick(tab, event) {
this.initChart();
},
initChart() {
var chartDom = document.getElementById('alertChart');
var myChart = echarts.init(chartDom);
var option;
if (this.activeName === 'first') { //
option = this.get24HourChartOption(); const processEventData = (events) => {
} else if (this.activeName === 'second') { //
option = this.get3DayChartOption(); hourlyCounts.value = Array(24).fill(0);
dailyCounts.value = Array(7).fill(0);
const today = new Date();
const startOfToday = new Date(today.getFullYear(), today.getMonth(), today.getDate());
const endOfToday = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1);
//
events.forEach(event => {
const endedAt = event.ended_at;
if (endedAt) {
const endedDate = new Date(endedAt);
//
if (endedDate >= startOfToday && endedDate < endOfToday) {
const hour = endedDate.getHours();
hourlyCounts.value[hour] += 1;
} }
option && myChart.setOption(option); // 7
}, const endedDay = dayjs(endedAt).format('YYYY-MM-DD');
get24HourChartOption() { weekDates.value.forEach((date, index) => {
const now = new Date(); if (endedDay === date) {
const todayMidnight = new Date(now); dailyCounts.value[index] += 1;
todayMidnight.setHours(0, 0, 0, 0); }
});
const yesterdayMidnight = new Date(todayMidnight);
yesterdayMidnight.setDate(todayMidnight.getDate() - 1);
const timePoints = ['00:00', '04:00', '08:00', '12:00', '16:00', '20:00', '24:00'];
const alertCounts = Array(timePoints.length).fill(0);
this.eventsData.forEach(event => {
const eventTime = new Date(event.started_at);
if (eventTime >= yesterdayMidnight && eventTime < todayMidnight) {
const hours = eventTime.getHours();
if (hours < 4) alertCounts[1]++;
else if (hours < 8) alertCounts[2]++;
else if (hours < 12) alertCounts[3]++;
else if (hours < 16) alertCounts[4]++;
else if (hours < 20) alertCounts[5]++;
else if (hours < 24) alertCounts[6]++;
} }
}); });
// Accumulate the alert counts //
for (let i = 1; i < alertCounts.length; i++) { updateCharts();
alertCounts[i] += alertCounts[i - 1]; };
}
return { //
title: { const updateCharts = () => {
text: '24小时内客流数量变化', if (chartInstanceToday.value) {
left: 'center', chartInstanceToday.value.setOption({
textStyle: { series: [{ data: hourlyCounts.value }]
color: '#fff'
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
},
formatter: '{b0}: {c0}'
},
xAxis: {
type: 'category',
boundaryGap: false,
data: timePoints
},
yAxis: {
type: 'value'
},
series: [
{
data: alertCounts,
type: 'line',
areaStyle: {}
}
]
};
},
get3DayChartOption() {
const now = new Date();
const day1Midnight = new Date(now);
day1Midnight.setHours(0, 0, 0, 0);
const day2Midnight = new Date(day1Midnight);
day2Midnight.setDate(day1Midnight.getDate() - 1);
const day3Midnight = new Date(day2Midnight);
day3Midnight.setDate(day2Midnight.getDate() - 1);
//
const adjustedDay1 = new Date(day1Midnight);
adjustedDay1.setDate(day1Midnight.getDate() + 1);
const adjustedDay2 = new Date(day2Midnight);
adjustedDay2.setDate(day2Midnight.getDate() + 1);
const adjustedDay3 = new Date(day3Midnight);
adjustedDay3.setDate(day3Midnight.getDate() + 1);
// 使
const timePoints = [
adjustedDay3.toISOString().slice(0, 10),
adjustedDay2.toISOString().slice(0, 10),
adjustedDay1.toISOString().slice(0, 10),
];
const alertCounts = Array(timePoints.length).fill(0);
this.eventsData.forEach(event => {
const eventTime = new Date(event.started_at);
if (eventTime >= day3Midnight && eventTime < day2Midnight) {
alertCounts[0]++;
} else if (eventTime >= day2Midnight && eventTime < day1Midnight) {
alertCounts[1]++;
} else if (eventTime >= day1Midnight && eventTime <= now) {
alertCounts[2]++;
}
}); });
}
return { if (chartInstanceWeek.value) {
title: { chartInstanceWeek.value.setOption({
text: '近3天内告警数量变化', series: [{ data: dailyCounts.value }]
left: 'center', });
textStyle: {
color: '#fff'
} }
}, };
tooltip: {
trigger: 'axis', //
axisPointer: { onMounted(async () => {
type: 'cross' calculateWeekDates(); // 7
},
formatter: '{b0}: {c0}' const token = localStorage.getItem('alertToken');
}, await fetchAndProcessEvents(token);
xAxis: {
type: 'category', //
boundaryGap: false, initTodayChart();
data: timePoints initWeekChart();
}, });
yAxis: {
type: 'value' // hourlyCounts
}, watch(hourlyCounts, () => {
series: [ if (chartInstanceToday.value) {
{ chartInstanceToday.value.setOption({
data: alertCounts, series: [{
type: 'line', data: hourlyCounts.value
areaStyle: {} }]
});
} }
] });
};
// dailyCounts
watch(dailyCounts, () => {
if (chartInstanceWeek.value) {
chartInstanceWeek.value.setOption({
series: [{
data: dailyCounts.value
}]
});
} }
});
// tab
const handleClick = (tab) => {
if (tab.name === 'first') {
initTodayChart(); //
} else if (tab.name === 'second') {
initWeekChart(); //
} }
}; };
</script> </script>
@ -194,29 +303,28 @@ export default {
.alert-card { .alert-card {
background-color: #2a3f54; background-color: #2a3f54;
color: #fff; color: #fff;
padding: 20px;
border-radius: 8px; border-radius: 8px;
padding: 0;
margin: 0;
} }
.alert-header { .alert-header {
font-size: 18px; font-size: 18px;
font-weight: bold; font-weight: bold;
margin-bottom: 20px;
border-bottom: 1px solid #3a4b5c; border-bottom: 1px solid #3a4b5c;
padding-bottom: 10px;
} }
.alert-tabs { .alert-tabs {
margin-bottom: 20px; margin-bottom: 0;
}
::v-deep .el-tabs__item {
color: #fff;
} }
.chart-container { .chart-container {
width: 100%; width: 780px;
height: 400px; height: 420px;
}
.el-tabs__item {
color: #fff;
} }
.el-tabs__active-bar { .el-tabs__active-bar {

View File

@ -11,63 +11,93 @@
</div> </div>
</template> </template>
<script> <script setup>
import { ref, onMounted } from 'vue';
import * as echarts from 'echarts'; import * as echarts from 'echarts';
import { login, getAlgorithms,getEvents} from '@/utils/superbox.js'; import { BoxApi } from '@/utils/boxApi.ts'; // BoxApi
const username = 'turingvideo'; //
const password = '1234qwer!'; const chart = ref(null);
const seriesData = ref([]);
// BoxApi
const apiInstance = new BoxApi();
export default { //
name: 'Statistics', const fetchTypeMapping = async (token) => {
data() { const algorithms = await apiInstance.getAlgorithms(token);
return {
chart: null,
seriesData: [
],
};
},
// mounted() {
// this.initChart();
// },
async created(){
try{
const token = await login(username, password);
await this.fetchTypeMapping(token);
await this.updateSeriesData(token);
this.initChart();
}catch(error){
console.error("Error fetching algorithms:", error);
}
},
methods: {
async fetchTypeMapping(token) {
const algorithms = await getAlgorithms(token);
let mapping = algorithms.map(algorithm => ({ let mapping = algorithms.map(algorithm => ({
value: 0, // 10 value: 0,
code_name: algorithm.code_name, code_name: algorithm.code_name,
name: algorithm.name name: algorithm.name
})); }));
const newMapping = [
{code_name: "minizawu:532",name: "杂物堆积",value: 0},
]
mapping = mapping.concat(newMapping); //
this.seriesData = mapping; const newMapping = [
}, { code_name: "minizawu:532", name: "杂物堆积", value: 0 }
async updateSeriesData(token){ ];
const events = await getEvents(token);
seriesData.value = mapping.concat(newMapping);
};
// seriesData
const fetchAndProcessEvents = async (token) => {
try {
let currentPage = 1;
const pageSize = 2000; // 2000
let allEvents = [];
//
const { tableData: firstBatch, totalItems } = await apiInstance.getEvents(token, pageSize, currentPage);
allEvents = [...firstBatch];
//
const totalPages = Math.ceil(totalItems / pageSize);
//
while (currentPage < totalPages) {
currentPage++;
const { tableData: nextBatch } = await apiInstance.getEvents(token, pageSize, currentPage);
allEvents = [...allEvents, ...nextBatch];
//
processEventData(allEvents);
updateChart(); //
}
//
processEventData(allEvents);
updateChart(); //
} catch (error) {
console.error("Error fetching events:", error);
}
};
// seriesData
const processEventData = (events) => {
//
seriesData.value.forEach(item => {
item.value = 0;
});
//
events.forEach(event => { events.forEach(event => {
const matchAlgorithm = this.seriesData.find(item => item.code_name === event.types); const matchAlgorithm = seriesData.value.find(item => item.code_name === event.types);
if (matchAlgorithm){ if (matchAlgorithm) {
matchAlgorithm.value += 1; matchAlgorithm.value += 1;
} }
}) });
}, };
initChart() {
this.chart = echarts.init(this.$refs.chart); //
const initChart = () => {
// ECharts
if (!chart.value) {
console.error("Chart DOM element is not available");
return;
}
chart.value = echarts.init(chart.value);
const option = { const option = {
tooltip: { tooltip: {
trigger: 'item', trigger: 'item',
@ -79,7 +109,7 @@ export default {
color: '#fff', color: '#fff',
}, },
itemGap: 20, itemGap: 20,
data: this.seriesData.map(item => item.name), data: seriesData.value.map(item => item.name),
}, },
series: [ series: [
{ {
@ -87,50 +117,78 @@ export default {
type: 'pie', type: 'pie',
radius: '50%', radius: '50%',
center: ['50%', '150px'], center: ['50%', '150px'],
data: this.seriesData, data: seriesData.value,
emphasis: { emphasis: {
itemStyle: { itemStyle: {
shadowBlur: 10, shadowBlur: 10,
shadowOffsetX: 0, shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)' shadowColor: 'rgba(0, 0, 0, 0.5)',
} }
}, },
label: { label: {
show: true show: true,
}, },
stillShowZeroSum: false, stillShowZeroSum: false,
} }
] ]
}; };
this.chart.setOption(option); chart.value.setOption(option);
};
//
const updateChart = () => {
if (chart.value && typeof chart.value.setOption === 'function') {
chart.value.setOption({
series: [
{
data: seriesData.value
} }
]
});
} else {
console.error("ECharts instance is not initialized properly");
} }
}; };
//
onMounted(async () => {
try {
const token = localStorage.getItem('alertToken');
//
await fetchTypeMapping(token);
//
initChart();
//
await fetchAndProcessEvents(token);
} catch (error) {
console.error("Error fetching data:", error);
}
});
</script> </script>
<style scoped> <style scoped>
.stats-card { .stats-card {
background-color: #2a3f54; background-color: #2a3f54;
color: #fff; color: #fff;
padding: 20px;
border-radius: 8px; border-radius: 8px;
} }
.stats-header { .stats-header {
font-size: 18px; font-size: 18px;
font-weight: bold; font-weight: bold;
margin-bottom: 20px;
border-bottom: 1px solid #3a4b5c; border-bottom: 1px solid #3a4b5c;
padding-bottom: 10px;
} }
.stats-row { .stats-row {
/* margin-top: 20px; */ margin-top: 20px;
margin-bottom: 10px; margin-bottom: 10px;
} }
.chart { .chart {
width: 100%; width: 100%;
height: 500px; height: 445px;
} }
</style> </style>