增加折线
This commit is contained in:
parent
55ff382434
commit
a42c3f5824
|
|
@ -86,14 +86,14 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onBeforeUnmount, nextTick, computed } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { ReloadOutlined } from '@ant-design/icons-vue';
|
||||
import * as echarts from 'echarts';
|
||||
import dayjs from 'dayjs';
|
||||
import { getDeviceAlertStatistic, getAllDeviceList } from './datacenter.api';
|
||||
import { ref, onMounted, onBeforeUnmount, nextTick, computed } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { ReloadOutlined } from '@ant-design/icons-vue';
|
||||
import * as echarts from 'echarts';
|
||||
import dayjs from 'dayjs';
|
||||
import { getDeviceAlertStatistic, getAllDeviceList } from './datacenter.api';
|
||||
|
||||
const fetchCategoryOptions = () => {
|
||||
const fetchCategoryOptions = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
getAllDeviceList({})
|
||||
.then((res) => {
|
||||
|
|
@ -108,10 +108,10 @@
|
|||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
// ==================== 根据类别获取图表数据 ====================
|
||||
const fetchChartDataByCategory = (deployId, summaryMode, startTime) => {
|
||||
// ==================== 根据类别获取图表数据 ====================
|
||||
const fetchChartDataByCategory = (deployId, summaryMode, startTime) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const chartData = [];
|
||||
const dataMap = {
|
||||
|
|
@ -195,22 +195,22 @@
|
|||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
// ==================== 数据状态 ====================
|
||||
const categoryOptions = ref([]);
|
||||
const categoryLoading = ref(false);
|
||||
const selectedCategory = ref('');
|
||||
const chartDataList = ref([]);
|
||||
const loading = ref(false);
|
||||
const chartInstances = [];
|
||||
const chartRefs = {};
|
||||
// ==================== 数据状态 ====================
|
||||
const categoryOptions = ref([]);
|
||||
const categoryLoading = ref(false);
|
||||
const selectedCategory = ref('');
|
||||
const chartDataList = ref([]);
|
||||
const loading = ref(false);
|
||||
const chartInstances = [];
|
||||
const chartRefs = {};
|
||||
|
||||
const selectedDimension = ref('dayhours');
|
||||
const selectedDate = ref(null);
|
||||
const selectedDimension = ref('dayhours');
|
||||
const selectedDate = ref(null);
|
||||
|
||||
// ==================== 根据统计模式动态计算日期格式 ====================
|
||||
const dateFormat = computed(() => {
|
||||
// ==================== 根据统计模式动态计算日期格式 ====================
|
||||
const dateFormat = computed(() => {
|
||||
switch (selectedDimension.value) {
|
||||
case 'dayhours':
|
||||
return 'YYYY-MM-DD';
|
||||
|
|
@ -221,9 +221,9 @@
|
|||
default:
|
||||
return 'YYYY-MM-DD';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const pickerType = computed(() => {
|
||||
const pickerType = computed(() => {
|
||||
switch (selectedDimension.value) {
|
||||
case 'dayhours':
|
||||
return 'date';
|
||||
|
|
@ -234,9 +234,9 @@
|
|||
default:
|
||||
return 'date';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const datePlaceholder = computed(() => {
|
||||
const datePlaceholder = computed(() => {
|
||||
switch (selectedDimension.value) {
|
||||
case 'dayhours':
|
||||
return '选择日期';
|
||||
|
|
@ -247,27 +247,27 @@
|
|||
default:
|
||||
return '选择日期';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ==================== 下拉框筛选 ====================
|
||||
const filterOption = (input, option) => {
|
||||
// ==================== 下拉框筛选 ====================
|
||||
const filterOption = (input, option) => {
|
||||
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
||||
};
|
||||
};
|
||||
|
||||
const getCategoryLabel = (value) => {
|
||||
const getCategoryLabel = (value) => {
|
||||
const found = categoryOptions.value.find((item) => item.id === value);
|
||||
return found ? found.deployDes : value;
|
||||
};
|
||||
};
|
||||
|
||||
// ==================== 设置图表 DOM 引用 ====================
|
||||
const setChartRef = (el, index) => {
|
||||
// ==================== 设置图表 DOM 引用 ====================
|
||||
const setChartRef = (el, index) => {
|
||||
if (el) {
|
||||
chartRefs[index] = el;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// ==================== 加载下拉选项 ====================
|
||||
const loadCategories = async () => {
|
||||
// ==================== 加载下拉选项 ====================
|
||||
const loadCategories = async () => {
|
||||
categoryLoading.value = true;
|
||||
try {
|
||||
const res = await fetchCategoryOptions();
|
||||
|
|
@ -282,12 +282,15 @@
|
|||
} finally {
|
||||
categoryLoading.value = false;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// ==================== 加载图表数据(参数名:deployId, summaryMode, startTime) ====================
|
||||
const loadChartData = async (deployId, summaryMode, startTime) => {
|
||||
// ==================== 加载图表数据(参数名:deployId, summaryMode, startTime) ====================
|
||||
const loadChartData = async (deployId, summaryMode, startTime) => {
|
||||
if (!deployId) return;
|
||||
|
||||
// ✅ 先清空数据,让 tag 显示 0 项
|
||||
chartDataList.value = [];
|
||||
|
||||
loading.value = true;
|
||||
try {
|
||||
// 格式化日期
|
||||
|
|
@ -312,19 +315,19 @@
|
|||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// ==================== 查询(收集所有参数) ====================
|
||||
const handleSearch = () => {
|
||||
// ==================== 查询(收集所有参数) ====================
|
||||
const handleSearch = () => {
|
||||
if (!selectedCategory.value) {
|
||||
message.warning('请先选择设备');
|
||||
return;
|
||||
}
|
||||
loadChartData(selectedCategory.value, selectedDimension.value, selectedDate.value);
|
||||
};
|
||||
};
|
||||
|
||||
// ==================== 初始化所有图表 ====================
|
||||
const initCharts = () => {
|
||||
// ==================== 初始化所有图表 ====================
|
||||
const initCharts = () => {
|
||||
chartInstances.forEach((instance) => {
|
||||
if (instance._resizeHandler) {
|
||||
window.removeEventListener('resize', instance._resizeHandler);
|
||||
|
|
@ -356,16 +359,16 @@
|
|||
window.addEventListener('resize', resizeHandler);
|
||||
chart._resizeHandler = resizeHandler;
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
// ==================== 保留两位小数 ====================
|
||||
const roundToTwo = (num) => {
|
||||
// ==================== 保留两位小数 ====================
|
||||
const roundToTwo = (num) => {
|
||||
if (num === undefined || num === null || isNaN(num)) return num;
|
||||
return Math.round(num * 100) / 100;
|
||||
};
|
||||
};
|
||||
|
||||
// ==================== 计算 y 轴范围(确保 markLine 可见) ====================
|
||||
const calculateYAxisRange = (data, markLines) => {
|
||||
// ==================== 计算 y 轴范围(确保 markLine 可见) ====================
|
||||
const calculateYAxisRange = (data, markLines) => {
|
||||
if (!data || data.length === 0) {
|
||||
return { min: null, max: null };
|
||||
}
|
||||
|
|
@ -410,10 +413,10 @@
|
|||
min: roundToTwo(dataMin - padding),
|
||||
max: roundToTwo(dataMax + padding),
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// ==================== 生成 ECharts 配置 ====================
|
||||
const getChartOption = (item) => {
|
||||
// ==================== 生成 ECharts 配置 ====================
|
||||
const getChartOption = (item) => {
|
||||
// 计算 y 轴范围,确保 markLine 可见
|
||||
const yAxisRange = calculateYAxisRange(item.data, item.markLines);
|
||||
|
||||
|
|
@ -531,6 +534,51 @@
|
|||
},
|
||||
},
|
||||
},
|
||||
// ✅ 新增:折线图
|
||||
{
|
||||
name: item.title || '趋势',
|
||||
type: 'line',
|
||||
data: item.data || [],
|
||||
smooth: true,
|
||||
symbol: 'circle',
|
||||
symbolSize: 6,
|
||||
lineStyle: {
|
||||
color: '#ff6b6b',
|
||||
width: 2,
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#ff6b6b',
|
||||
},
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{ offset: 0, color: 'rgba(255, 107, 107, 0.3)' },
|
||||
{ offset: 1, color: 'rgba(255, 107, 107, 0.05)' },
|
||||
],
|
||||
},
|
||||
},
|
||||
emphasis: {
|
||||
focus: 'series',
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'top',
|
||||
fontSize: 10,
|
||||
color: '#ff6b6b',
|
||||
fontWeight: 500,
|
||||
formatter: (params) => {
|
||||
return params.value;
|
||||
},
|
||||
},
|
||||
// 将折线图与柱状图关联,共享 x 轴
|
||||
xAxisIndex: 0,
|
||||
yAxisIndex: 0,
|
||||
},
|
||||
],
|
||||
legend: {
|
||||
show: true,
|
||||
|
|
@ -544,6 +592,13 @@
|
|||
name: item.title || '数据',
|
||||
icon: 'roundRect',
|
||||
},
|
||||
{
|
||||
name: item.title || '趋势',
|
||||
icon: 'line',
|
||||
itemStyle: {
|
||||
color: '#ff6b6b',
|
||||
},
|
||||
},
|
||||
...(item.markLines || []).map((line) => ({
|
||||
name: line.name,
|
||||
icon: 'line',
|
||||
|
|
@ -554,14 +609,14 @@
|
|||
],
|
||||
},
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// ==================== 生命周期 ====================
|
||||
onMounted(async () => {
|
||||
// ==================== 生命周期 ====================
|
||||
onMounted(async () => {
|
||||
await loadCategories();
|
||||
});
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
onBeforeUnmount(() => {
|
||||
chartInstances.forEach((instance) => {
|
||||
if (instance._resizeHandler) {
|
||||
window.removeEventListener('resize', instance._resizeHandler);
|
||||
|
|
@ -571,103 +626,103 @@
|
|||
}
|
||||
});
|
||||
chartInstances.length = 0;
|
||||
});
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
defineExpose({
|
||||
handleSearch,
|
||||
loadChartData,
|
||||
selectedCategory,
|
||||
categoryOptions,
|
||||
selectedDimension,
|
||||
selectedDate,
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.dashboard-charts {
|
||||
.dashboard-charts {
|
||||
padding: 24px;
|
||||
background: #f0f2f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================== 筛选区域样式 ==================== */
|
||||
.filter-section {
|
||||
/* ==================== 筛选区域样式 ==================== */
|
||||
.filter-section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-card {
|
||||
.filter-card {
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
}
|
||||
|
||||
.filter-card :deep(.ant-card-body) {
|
||||
.filter-card :deep(.ant-card-body) {
|
||||
padding: 16px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
.filter-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-label {
|
||||
.filter-label {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #1d2129;
|
||||
white-space: nowrap;
|
||||
min-width: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================== 图表区域样式 ==================== */
|
||||
.chart-grid {
|
||||
/* ==================== 图表区域样式 ==================== */
|
||||
.chart-grid {
|
||||
margin: 0 -8px;
|
||||
}
|
||||
}
|
||||
|
||||
.chart-col {
|
||||
.chart-col {
|
||||
padding: 0 8px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.chart-card {
|
||||
.chart-card {
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
transition: all 0.3s ease;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.chart-card:hover {
|
||||
.chart-card:hover {
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
}
|
||||
|
||||
.chart-card :deep(.ant-card-head) {
|
||||
.chart-card :deep(.ant-card-head) {
|
||||
padding: 0 20px;
|
||||
min-height: 52px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
background: #fafafa;
|
||||
border-radius: 12px 12px 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.chart-card :deep(.ant-card-head-title) {
|
||||
.chart-card :deep(.ant-card-head-title) {
|
||||
padding: 14px 0;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.chart-card :deep(.ant-card-body) {
|
||||
.chart-card :deep(.ant-card-body) {
|
||||
padding: 16px 12px 12px 12px;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.card-header {
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.chart-title {
|
||||
.chart-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #1d2129;
|
||||
|
|
@ -676,32 +731,32 @@
|
|||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 70%;
|
||||
}
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
.chart-container {
|
||||
width: 100%;
|
||||
height: 280px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.chart-instance {
|
||||
.chart-instance {
|
||||
width: 100%;
|
||||
height: 280px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 空状态样式 */
|
||||
.empty-state {
|
||||
/* 空状态样式 */
|
||||
.empty-state {
|
||||
margin-top: 60px;
|
||||
background: #ffffff;
|
||||
padding: 60px 0;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================== 响应式调整 ==================== */
|
||||
@media screen and (max-width: 768px) {
|
||||
/* ==================== 响应式调整 ==================== */
|
||||
@media screen and (max-width: 768px) {
|
||||
.dashboard-charts {
|
||||
padding: 16px;
|
||||
}
|
||||
|
|
@ -738,9 +793,9 @@
|
|||
.chart-card :deep(.ant-card-body) {
|
||||
padding: 12px 8px 8px 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
@media screen and (max-width: 480px) {
|
||||
.chart-container {
|
||||
height: 200px;
|
||||
}
|
||||
|
|
@ -757,5 +812,5 @@
|
|||
padding: 10px 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Reference in New Issue