图标组件化页面

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">
<div class="alert-header">告警趋势</div>
<el-tabs v-model="activeName" @tab-click="handleClick" class="alert-tabs">
<el-tab-pane label="前一天" name="first">前一天数据</el-tab-pane>
<el-tab-pane label="3天" name="second">近3天数据展示</el-tab-pane>
<el-tab-pane label="今日" name="first">
<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>
<div id="alertChart" class="chart-container"></div>
</el-card>
</div>
</template>
<script>
<script setup>
import { ref, onMounted, watch } from 'vue';
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 password = '1234qwer!';
const activeName = ref('first');
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 {
name: 'AlertChart',
data() {
return {
activeName: 'first',
eventsData: []
};
const apiInstance = new BoxApi(); // BoxApi
// 7
const calculateWeekDates = () => {
const today = dayjs();
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 {
const token = await login(username, password);
this.eventsData = await getEvents(token);
this.initChart();
let currentPage = 1;
const pageSize = 2000; // 100
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) {
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();
} else if (this.activeName === 'second') {
option = this.get3DayChartOption();
//
const processEventData = (events) => {
//
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);
},
get24HourChartOption() {
const now = new Date();
const todayMidnight = new Date(now);
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]++;
// 7
const endedDay = dayjs(endedAt).format('YYYY-MM-DD');
weekDates.value.forEach((date, index) => {
if (endedDay === date) {
dailyCounts.value[index] += 1;
}
});
}
});
// Accumulate the alert counts
for (let i = 1; i < alertCounts.length; i++) {
alertCounts[i] += alertCounts[i - 1];
}
//
updateCharts();
};
return {
title: {
text: '24小时内客流数量变化',
left: 'center',
textStyle: {
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]++;
}
//
const updateCharts = () => {
if (chartInstanceToday.value) {
chartInstanceToday.value.setOption({
series: [{ data: hourlyCounts.value }]
});
}
return {
title: {
text: '近3天内告警数量变化',
left: 'center',
textStyle: {
color: '#fff'
if (chartInstanceWeek.value) {
chartInstanceWeek.value.setOption({
series: [{ data: dailyCounts.value }]
});
}
},
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: {}
};
//
onMounted(async () => {
calculateWeekDates(); // 7
const token = localStorage.getItem('alertToken');
await fetchAndProcessEvents(token);
//
initTodayChart();
initWeekChart();
});
// hourlyCounts
watch(hourlyCounts, () => {
if (chartInstanceToday.value) {
chartInstanceToday.value.setOption({
series: [{
data: hourlyCounts.value
}]
});
}
]
};
});
// 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>
@ -194,29 +303,28 @@ export default {
.alert-card {
background-color: #2a3f54;
color: #fff;
padding: 20px;
border-radius: 8px;
padding: 0;
margin: 0;
}
.alert-header {
font-size: 18px;
font-weight: bold;
margin-bottom: 20px;
border-bottom: 1px solid #3a4b5c;
padding-bottom: 10px;
}
.alert-tabs {
margin-bottom: 20px;
margin-bottom: 0;
}
::v-deep .el-tabs__item {
color: #fff;
}
.chart-container {
width: 100%;
height: 400px;
}
.el-tabs__item {
color: #fff;
width: 780px;
height: 420px;
}
.el-tabs__active-bar {

View File

@ -11,63 +11,93 @@
</div>
</template>
<script>
<script setup>
import { ref, onMounted } from 'vue';
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',
data() {
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);
//
const fetchTypeMapping = async (token) => {
const algorithms = await apiInstance.getAlgorithms(token);
let mapping = algorithms.map(algorithm => ({
value: 0, // 10
value: 0,
code_name: algorithm.code_name,
name: algorithm.name
}));
const newMapping = [
{code_name: "minizawu:532",name: "杂物堆积",value: 0},
]
mapping = mapping.concat(newMapping);
this.seriesData = mapping;
},
async updateSeriesData(token){
const events = await getEvents(token);
//
const newMapping = [
{ code_name: "minizawu:532", name: "杂物堆积", value: 0 }
];
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 => {
const matchAlgorithm = this.seriesData.find(item => item.code_name === event.types);
if (matchAlgorithm){
const matchAlgorithm = seriesData.value.find(item => item.code_name === event.types);
if (matchAlgorithm) {
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 = {
tooltip: {
trigger: 'item',
@ -79,7 +109,7 @@ export default {
color: '#fff',
},
itemGap: 20,
data: this.seriesData.map(item => item.name),
data: seriesData.value.map(item => item.name),
},
series: [
{
@ -87,50 +117,78 @@ export default {
type: 'pie',
radius: '50%',
center: ['50%', '150px'],
data: this.seriesData,
data: seriesData.value,
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
shadowColor: 'rgba(0, 0, 0, 0.5)',
}
},
label: {
show: true
show: true,
},
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>
<style scoped>
.stats-card {
background-color: #2a3f54;
color: #fff;
padding: 20px;
border-radius: 8px;
}
.stats-header {
font-size: 18px;
font-weight: bold;
margin-bottom: 20px;
border-bottom: 1px solid #3a4b5c;
padding-bottom: 10px;
}
.stats-row {
/* margin-top: 20px; */
margin-top: 20px;
margin-bottom: 10px;
}
.chart {
width: 100%;
height: 500px;
height: 445px;
}
</style>