|
@@ -0,0 +1,173 @@
|
|
|
+<template>
|
|
|
+ <div class="monitoring">
|
|
|
+ <div class="header">
|
|
|
+ <h2>铁塔运行监测</h2>
|
|
|
+ <div class="stats">
|
|
|
+ <div v-for="(value, key) in stats" :key="key" class="stat-item">
|
|
|
+ <p>{{ value }}</p>
|
|
|
+ <span>{{ key }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="chart">
|
|
|
+ <h3>各区县异常比例</h3>
|
|
|
+ <!-- 使用外部图表库或者CSS实现柱状图 -->
|
|
|
+ <div class="chart-container">
|
|
|
+ <bar-chart :data="chartData" :options="chartOptions" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="table">
|
|
|
+ <h3>各区县告警类型分析</h3>
|
|
|
+ <el-table-v2 v-model:sort-state="sortState" :columns="columns" :data="data" :width="700" :height="400" fixed="50%" @column-sort="onSort" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="ts" setup>
|
|
|
+import { ref, onMounted } from 'vue';
|
|
|
+import { TableV2SortOrder } from 'element-plus';
|
|
|
+import type { SortBy, SortState } from 'element-plus';
|
|
|
+import { Bar, useChart } from 'vue-chartjs';
|
|
|
+import 'chart.js/auto';
|
|
|
+
|
|
|
+const generateColumns = (length = 10, prefix = 'column-', props?: any) =>
|
|
|
+ Array.from({ length }).map((_, columnIndex) => ({
|
|
|
+ ...props,
|
|
|
+ key: `${prefix}${columnIndex}`,
|
|
|
+ dataKey: `${prefix}${columnIndex}`,
|
|
|
+ title: `Column ${columnIndex}`,
|
|
|
+ width: 150
|
|
|
+ }));
|
|
|
+
|
|
|
+const generateData = (columns: ReturnType<typeof generateColumns>, length = 200, prefix = 'row-') =>
|
|
|
+ Array.from({ length }).map((_, rowIndex) => {
|
|
|
+ return columns.reduce(
|
|
|
+ (rowData, column, columnIndex) => {
|
|
|
+ rowData[column.dataKey] = `Row ${rowIndex} - Col ${columnIndex}`;
|
|
|
+ return rowData;
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: `${prefix}${rowIndex}`,
|
|
|
+ parentId: null
|
|
|
+ }
|
|
|
+ );
|
|
|
+ });
|
|
|
+
|
|
|
+const columns = generateColumns(10);
|
|
|
+const data = ref(generateData(columns, 200));
|
|
|
+
|
|
|
+columns[0].sortable = true;
|
|
|
+columns[1].sortable = true;
|
|
|
+
|
|
|
+const sortState = ref<SortState>({
|
|
|
+ 'column-0': TableV2SortOrder.DESC,
|
|
|
+ 'column-1': TableV2SortOrder.ASC
|
|
|
+});
|
|
|
+
|
|
|
+const onSort = ({ key, order }: SortBy) => {
|
|
|
+ sortState.value[key] = order;
|
|
|
+ data.value = data.value.reverse();
|
|
|
+};
|
|
|
+
|
|
|
+const chartData = ref({
|
|
|
+ labels: ['茂南区', '电白区', '信宜市', '高州市', '化州市', '滨海新区', '高新区', '水东湾新城'],
|
|
|
+ datasets: [
|
|
|
+ {
|
|
|
+ label: '异常比例 (%)',
|
|
|
+ data: [20, 25, 30, 35, 5, 15, 40, 45],
|
|
|
+ backgroundColor: [
|
|
|
+ 'rgba(255, 99, 132, 0.2)',
|
|
|
+ 'rgba(54, 162, 235, 0.2)',
|
|
|
+ 'rgba(255, 206, 86, 0.2)',
|
|
|
+ 'rgba(75, 192, 192, 0.2)',
|
|
|
+ 'rgba(153, 102, 255, 0.2)',
|
|
|
+ 'rgba(255, 159, 64, 0.2)',
|
|
|
+ 'rgba(255, 205, 86, 0.2)',
|
|
|
+ 'rgba(201, 203, 207, 0.2)'
|
|
|
+ ],
|
|
|
+ borderColor: [
|
|
|
+ 'rgba(255, 99, 132, 1)',
|
|
|
+ 'rgba(54, 162, 235, 1)',
|
|
|
+ 'rgba(255, 206, 86, 1)',
|
|
|
+ 'rgba(75, 192, 192, 1)',
|
|
|
+ 'rgba(153, 102, 255, 1)',
|
|
|
+ 'rgba(255, 159, 64, 1)',
|
|
|
+ 'rgba(255, 205, 86, 1)',
|
|
|
+ 'rgba(201, 203, 207, 1)'
|
|
|
+ ],
|
|
|
+ borderWidth: 1
|
|
|
+ }
|
|
|
+ ]
|
|
|
+});
|
|
|
+
|
|
|
+const chartOptions = {
|
|
|
+ scales: {
|
|
|
+ y: {
|
|
|
+ beginAtZero: true,
|
|
|
+ title: {
|
|
|
+ display: true,
|
|
|
+ text: '异常比例 (%)'
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ responsive: true,
|
|
|
+ maintainAspectRatio: false
|
|
|
+};
|
|
|
+
|
|
|
+const { renderChart } = useChart();
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ renderChart(chartData.value, chartOptions);
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style>
|
|
|
+.monitoring {
|
|
|
+ width: 800px;
|
|
|
+ margin: 0 auto;
|
|
|
+ font-family: Arial, sans-serif;
|
|
|
+}
|
|
|
+.header {
|
|
|
+ background-color: #f9f9f9;
|
|
|
+ padding: 20px;
|
|
|
+ border-radius: 5px;
|
|
|
+}
|
|
|
+.stats {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ flex-wrap: wrap;
|
|
|
+}
|
|
|
+.stat-item {
|
|
|
+ width: 100px;
|
|
|
+ text-align: center;
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+.chart {
|
|
|
+ margin-top: 20px;
|
|
|
+}
|
|
|
+.bar {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+.bar-inner {
|
|
|
+ height: 20px;
|
|
|
+ background-color: #5ba5f9;
|
|
|
+ margin: 0 10px;
|
|
|
+}
|
|
|
+.table {
|
|
|
+ margin-top: 20px;
|
|
|
+}
|
|
|
+table {
|
|
|
+ width: 100%;
|
|
|
+ border-collapse: collapse;
|
|
|
+}
|
|
|
+th,
|
|
|
+td {
|
|
|
+ border: 1px solid #ccc;
|
|
|
+ padding: 8px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+</style>
|