|
|
@@ -21,7 +21,7 @@
|
|
|
placeholder="请选择月份"
|
|
|
style="width: 150px;"
|
|
|
value-format="YYYY-MM"
|
|
|
- @change="handleMonthChange"
|
|
|
+ @change="handleDateChange"
|
|
|
/>
|
|
|
</el-form-item>
|
|
|
|
|
|
@@ -65,20 +65,22 @@
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
|
|
|
- <!-- 总体统计数据展示 -->
|
|
|
- <el-card class="statistic-card" v-if="statistics">
|
|
|
- <div class="statistic-container">
|
|
|
- <div class="statistic-item">
|
|
|
- <div class="statistic-label">设备总数:</div>
|
|
|
- <div class="statistic-value">{{ statistics.totalDevices }}</div>
|
|
|
- </div>
|
|
|
- <div class="statistic-divider"></div>
|
|
|
- <div class="statistic-item" v-for="(count, key) in statistics.trendCounts" :key="key">
|
|
|
- <div class="statistic-label">{{ key }}:</div>
|
|
|
- <div class="statistic-value">{{ count }}</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </el-card>
|
|
|
+ <!-- 双图表展示 -->
|
|
|
+ <el-row :gutter="15" style="margin-bottom: 20px;" v-if="statistics">
|
|
|
+ <!-- 趋势分析南丁格尔图 -->
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-card>
|
|
|
+ <div ref="trendChartRef" style="width: 100%; height: 250px;"></div>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ <!-- 当月停机趋势折线图 -->
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-card>
|
|
|
+ <div ref="deviceChartRef" style="width: 100%; height: 250px;"></div>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
|
|
|
<el-table v-loading="loading" :data="filteredData" @selection-change="handleSelectionChange">
|
|
|
<el-table-column type="selection" width="55" align="center"/>
|
|
|
@@ -127,7 +129,7 @@
|
|
|
|
|
|
<script setup name="CalcStop">
|
|
|
import {gzStop} from "@/api/calc/calcStop";
|
|
|
-import {getCurrentInstance, reactive, ref, toRefs} from 'vue';
|
|
|
+import {getCurrentInstance, nextTick, reactive, ref, toRefs} from 'vue';
|
|
|
import * as echarts from 'echarts';
|
|
|
|
|
|
const {proxy} = getCurrentInstance();
|
|
|
@@ -146,7 +148,12 @@ const title = ref("");
|
|
|
const currentRow = ref({}); // 添加当前行数据
|
|
|
const chartRef = ref(null);
|
|
|
const statistics = ref(null); // 添加统计数据
|
|
|
+const trendChartRef = ref(null); // 趋势图容器引用
|
|
|
+const deviceChartRef = ref(null); // 设备统计图容器引用
|
|
|
+const monthList = ref([]); // 专门用于存储月度数据
|
|
|
let chartInstance = null;
|
|
|
+let trendChartInstance = null; // 趋势图实例
|
|
|
+let deviceChartInstance = null; // 设备统计图实例
|
|
|
|
|
|
// 计算默认日期(当前时间减去31小时)
|
|
|
const getDefaultDate = () => {
|
|
|
@@ -184,6 +191,41 @@ const data = reactive({
|
|
|
|
|
|
const {queryParams, form, rules} = toRefs(data);
|
|
|
|
|
|
+/** 查询停机数据统计列表 */
|
|
|
+function getList() {
|
|
|
+ loading.value = true;
|
|
|
+ // 根据统计方式设置查询参数
|
|
|
+ if (queryParams.value.remark === 'month' && queryParams.value.dataDate) {
|
|
|
+ // 按月查询
|
|
|
+ queryParams.value.startTime = queryParams.value.dataDate + "-01";
|
|
|
+ const year = parseInt(queryParams.value.dataDate.split("-")[0]);
|
|
|
+ const month = parseInt(queryParams.value.dataDate.split("-")[1]);
|
|
|
+ const lastDay = new Date(year, month, 0).getDate();
|
|
|
+ queryParams.value.endTime = queryParams.value.dataDate + "-" + (lastDay < 10 ? "0" + lastDay : lastDay);
|
|
|
+ } else if (queryParams.value.remark === 'day') {
|
|
|
+ // 按天查询,如果未选择日期则使用默认日期
|
|
|
+ if (!queryParams.value.dataDate) {
|
|
|
+ const defaultDate = getDefaultDate();
|
|
|
+ queryParams.value.dataDate = defaultDate;
|
|
|
+ }
|
|
|
+ queryParams.value.startTime = queryParams.value.dataDate;
|
|
|
+ queryParams.value.endTime = queryParams.value.dataDate;
|
|
|
+ }
|
|
|
+
|
|
|
+ gzStop(queryParams.value).then(response => {
|
|
|
+ calcStopList.value = response.data;
|
|
|
+ filteredData.value = response.data; // 初始化过滤数据
|
|
|
+ statistics.value = response.statistics; // 保存统计数据
|
|
|
+ monthList.value = response.monthList;
|
|
|
+ loading.value = false;
|
|
|
+ // 在数据加载完成后绘制图表
|
|
|
+ nextTick(() => {
|
|
|
+ drawTrendChart();
|
|
|
+ drawDeviceChart();
|
|
|
+ });
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
// 统计方式变化处理
|
|
|
function handleRemarkChange() {
|
|
|
// 清空之前选择的日期
|
|
|
@@ -210,6 +252,9 @@ function handleRemarkChange() {
|
|
|
const lastDay = new Date(year, month, 0).getDate();
|
|
|
queryParams.value.endTime = currentMonth + "-" + (lastDay < 10 ? "0" + lastDay : lastDay);
|
|
|
}
|
|
|
+
|
|
|
+ // 统计方式改变后自动查询
|
|
|
+ handleFilter();
|
|
|
}
|
|
|
|
|
|
// 月份选择变化处理
|
|
|
@@ -233,10 +278,21 @@ function handleDateChange() {
|
|
|
if (queryParams.value.dataDate && queryParams.value.remark === 'day') {
|
|
|
queryParams.value.startTime = queryParams.value.dataDate;
|
|
|
queryParams.value.endTime = queryParams.value.dataDate;
|
|
|
+ } else if (queryParams.value.dataDate && queryParams.value.remark === 'month') {
|
|
|
+ // 设置为该月的第一天作为开始时间
|
|
|
+ queryParams.value.startTime = queryParams.value.dataDate + "-01";
|
|
|
+ // 设置为该月的最后一天作为结束时间
|
|
|
+ const year = parseInt(queryParams.value.dataDate.split("-")[0]);
|
|
|
+ const month = parseInt(queryParams.value.dataDate.split("-")[1]);
|
|
|
+ const lastDay = new Date(year, month, 0).getDate();
|
|
|
+ queryParams.value.endTime = queryParams.value.dataDate + "-" + (lastDay < 10 ? "0" + lastDay : lastDay);
|
|
|
} else {
|
|
|
queryParams.value.startTime = null;
|
|
|
queryParams.value.endTime = null;
|
|
|
}
|
|
|
+
|
|
|
+ // 日期改变后自动查询
|
|
|
+ handleFilter();
|
|
|
}
|
|
|
|
|
|
// 分析天数变化处理
|
|
|
@@ -244,35 +300,214 @@ function handleDaysChange() {
|
|
|
getList(); // 分析天数变化时重新从后端获取数据
|
|
|
}
|
|
|
|
|
|
-/** 查询停机数据统计列表 */
|
|
|
-function getList() {
|
|
|
- loading.value = true;
|
|
|
- // 根据统计方式设置查询参数
|
|
|
- if (queryParams.value.remark === 'month' && queryParams.value.dataDate) {
|
|
|
- // 按月查询
|
|
|
- queryParams.value.startTime = queryParams.value.dataDate + "-01";
|
|
|
- const year = parseInt(queryParams.value.dataDate.split("-")[0]);
|
|
|
- const month = parseInt(queryParams.value.dataDate.split("-")[1]);
|
|
|
- const lastDay = new Date(year, month, 0).getDate();
|
|
|
- queryParams.value.endTime = queryParams.value.dataDate + "-" + (lastDay < 10 ? "0" + lastDay : lastDay);
|
|
|
- } else if (queryParams.value.remark === 'day') {
|
|
|
- // 按天查询,如果未选择日期则使用默认日期
|
|
|
- if (!queryParams.value.dataDate) {
|
|
|
- const defaultDate = getDefaultDate();
|
|
|
- queryParams.value.dataDate = defaultDate;
|
|
|
- }
|
|
|
- queryParams.value.startTime = queryParams.value.dataDate;
|
|
|
- queryParams.value.endTime = queryParams.value.dataDate;
|
|
|
+// 绘制趋势分析图(南丁格尔图)
|
|
|
+function drawTrendChart() {
|
|
|
+ if (!trendChartRef.value || !statistics.value) return;
|
|
|
+
|
|
|
+ // 销毁之前的实例
|
|
|
+ if (trendChartInstance) {
|
|
|
+ trendChartInstance.dispose();
|
|
|
}
|
|
|
|
|
|
- gzStop(queryParams.value).then(response => {
|
|
|
- calcStopList.value = response.data;
|
|
|
- filteredData.value = response.data; // 初始化过滤数据
|
|
|
- statistics.value = response.statistics; // 保存统计数据
|
|
|
- loading.value = false;
|
|
|
- // 在数据加载完成后触发一次过滤,确保默认选中项生效
|
|
|
- filterData();
|
|
|
- });
|
|
|
+ // 初始化新的实例
|
|
|
+ trendChartInstance = echarts.init(trendChartRef.value);
|
|
|
+
|
|
|
+ // 准备数据
|
|
|
+ const trendData = Object.entries(statistics.value.trendCounts).map(([name, value]) => ({
|
|
|
+ name,
|
|
|
+ value
|
|
|
+ }));
|
|
|
+
|
|
|
+ // 计算总数量,用于百分比计算
|
|
|
+ const totalValue = trendData.reduce((sum, item) => sum + item.value, 0);
|
|
|
+
|
|
|
+ // 定义颜色调色板,使颜色更加协调
|
|
|
+ const colorPalette = ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de'];
|
|
|
+
|
|
|
+ // 配置图表选项
|
|
|
+ const option = {
|
|
|
+ color: colorPalette,
|
|
|
+ title: {
|
|
|
+ text: '趋势分析统计',
|
|
|
+ left: 'center'
|
|
|
+ },
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'item',
|
|
|
+ formatter: '{a} <br/>{b} : {c} ({d}%)'
|
|
|
+ },
|
|
|
+ legend: {
|
|
|
+ bottom: 10,
|
|
|
+ left: 'center',
|
|
|
+ data: trendData.map(item => item.name)
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '趋势分析',
|
|
|
+ type: 'pie',
|
|
|
+ radius: [30, 80],
|
|
|
+ center: ['50%', '50%'],
|
|
|
+ roseType: 'radius',
|
|
|
+ itemStyle: {
|
|
|
+ borderRadius: 5,
|
|
|
+ borderColor: '#fff',
|
|
|
+ borderWidth: 2
|
|
|
+ },
|
|
|
+ label: {
|
|
|
+ show: true,
|
|
|
+ formatter: (params) => {
|
|
|
+ const percentage = totalValue > 0 ? ((params.value / totalValue) * 100).toFixed(2) : 0;
|
|
|
+ return `{name|${params.name}}\n{value|${params.value}} {percentage|${percentage}%}`;
|
|
|
+ },
|
|
|
+ rich: {
|
|
|
+ name: {
|
|
|
+ fontSize: 12,
|
|
|
+ color: '#666',
|
|
|
+ lineHeight: 14
|
|
|
+ },
|
|
|
+ value: {
|
|
|
+ fontSize: 14,
|
|
|
+ fontWeight: 'bold',
|
|
|
+ color: '#333',
|
|
|
+ lineHeight: 16
|
|
|
+ },
|
|
|
+ percentage: {
|
|
|
+ fontSize: 12,
|
|
|
+ color: '#999',
|
|
|
+ lineHeight: 14
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ labelLine: {
|
|
|
+ length: 5,
|
|
|
+ length2: 10
|
|
|
+ },
|
|
|
+ data: trendData
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '设备总数',
|
|
|
+ type: 'pie',
|
|
|
+ radius: [0, 30],
|
|
|
+ center: ['50%', '50%'],
|
|
|
+ itemStyle: {
|
|
|
+ color: '#5470c6'
|
|
|
+ },
|
|
|
+ label: {
|
|
|
+ show: true,
|
|
|
+ position: 'center',
|
|
|
+ formatter: '设备总数\n{c}',
|
|
|
+ fontSize: 16,
|
|
|
+ fontWeight: 'bold',
|
|
|
+ lineHeight: 20,
|
|
|
+ rich: {
|
|
|
+ a: {
|
|
|
+ fontSize: 16,
|
|
|
+ color: '#333'
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data: [{value: statistics.value.totalDevices, name: '设备总数'}]
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+
|
|
|
+ // 设置配置项
|
|
|
+ trendChartInstance.setOption(option);
|
|
|
+}
|
|
|
+
|
|
|
+// 绘制设备统计图(当月停机趋势折线图)
|
|
|
+function drawDeviceChart() {
|
|
|
+ if (!deviceChartRef.value) return;
|
|
|
+
|
|
|
+ // 销毁之前的实例
|
|
|
+ if (deviceChartInstance) {
|
|
|
+ deviceChartInstance.dispose();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 初始化新的实例
|
|
|
+ deviceChartInstance = echarts.init(deviceChartRef.value);
|
|
|
+
|
|
|
+ // 准备数据 - 使用专门定义的monthList
|
|
|
+ let dates = [];
|
|
|
+ let times = [];
|
|
|
+ console.error(monthList.value)
|
|
|
+ // 获取monthList数据
|
|
|
+ if (monthList.value && Array.isArray(monthList.value) && monthList.value.length > 0) {
|
|
|
+ dates = monthList.value.map(item => {
|
|
|
+ // 确保item和item.date存在
|
|
|
+ return item && item.date ? item.date : '';
|
|
|
+ }).filter(date => date !== ''); // 过滤掉空值
|
|
|
+
|
|
|
+ times = monthList.value.map(item => {
|
|
|
+ // 确保item和item.times存在
|
|
|
+ return item && typeof item.times !== 'undefined' ? item.times : 0;
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果没有数据,显示提示信息
|
|
|
+ if (dates.length === 0) {
|
|
|
+ deviceChartInstance.clear();
|
|
|
+ deviceChartInstance.setOption({
|
|
|
+ title: {
|
|
|
+ text: '暂无数据',
|
|
|
+ left: 'center',
|
|
|
+ top: 'center'
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 配置图表选项
|
|
|
+ const option = {
|
|
|
+ title: {
|
|
|
+ text: '当月停机趋势',
|
|
|
+ left: 'center'
|
|
|
+ },
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'axis',
|
|
|
+ formatter: (params) => {
|
|
|
+ // 格式化日期显示,只显示日期部分
|
|
|
+ const date = params[0].axisValue.split(' ')[0];
|
|
|
+ return `${date}<br/>停机次数: ${params[0].data}`;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: 'category',
|
|
|
+ data: dates.map(date => date.split(' ')[0]), // 只显示日期部分
|
|
|
+ name: '日期'
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: 'value',
|
|
|
+ name: '停机次数'
|
|
|
+ },
|
|
|
+ series: [{
|
|
|
+ data: times,
|
|
|
+ type: 'line',
|
|
|
+ smooth: true,
|
|
|
+ itemStyle: {
|
|
|
+ color: '#5470c6'
|
|
|
+ },
|
|
|
+ areaStyle: {
|
|
|
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
+ {offset: 0, color: 'rgba(84, 112, 198, 0.3)'},
|
|
|
+ {offset: 1, color: 'rgba(84, 112, 198, 0.05)'}
|
|
|
+ ])
|
|
|
+ },
|
|
|
+ markPoint: {
|
|
|
+ data: [
|
|
|
+ {type: 'max', name: '最大值'},
|
|
|
+ {type: 'min', name: '最小值'}
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ markLine: {
|
|
|
+ data: [
|
|
|
+ {type: 'average', name: '平均值'}
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ }]
|
|
|
+ };
|
|
|
+
|
|
|
+ // 设置配置项
|
|
|
+ deviceChartInstance.setOption(option);
|
|
|
}
|
|
|
|
|
|
// 计算统计数据
|
|
|
@@ -468,7 +703,37 @@ function closeChart() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-getList();
|
|
|
+// 监听窗口大小变化,自动调整图表大小
|
|
|
+const handleResize = () => {
|
|
|
+ if (trendChartInstance) {
|
|
|
+ trendChartInstance.resize();
|
|
|
+ }
|
|
|
+ if (deviceChartInstance) {
|
|
|
+ deviceChartInstance.resize();
|
|
|
+ }
|
|
|
+ if (chartInstance) {
|
|
|
+ chartInstance.resize();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ getList();
|
|
|
+ window.addEventListener('resize', handleResize);
|
|
|
+});
|
|
|
+
|
|
|
+onBeforeUnmount(() => {
|
|
|
+ window.removeEventListener('resize', handleResize);
|
|
|
+ // 销毁图表实例
|
|
|
+ if (trendChartInstance) {
|
|
|
+ trendChartInstance.dispose();
|
|
|
+ }
|
|
|
+ if (deviceChartInstance) {
|
|
|
+ deviceChartInstance.dispose();
|
|
|
+ }
|
|
|
+ if (chartInstance) {
|
|
|
+ chartInstance.dispose();
|
|
|
+ }
|
|
|
+});
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|