Browse Source

增加堆垛机和加弹机的模拟展示

wukai 5 months ago
parent
commit
0833ce83e8
2 changed files with 1558 additions and 0 deletions
  1. 779 0
      src/views/calc/calcStop/ddStop.vue
  2. 779 0
      src/views/calc/calcStop/jtStop.vue

+ 779 - 0
src/views/calc/calcStop/ddStop.vue

@@ -0,0 +1,779 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="统计方式" prop="remark">
+        <el-select
+            v-model="queryParams.remark"
+            placeholder="请选择统计方式"
+            clearable
+            style="width: 150px;"
+            @change="handleRemarkChange"
+        >
+          <el-option label="按月" value="month"></el-option>
+          <el-option label="按天" value="day"></el-option>
+        </el-select>
+      </el-form-item>
+
+      <el-form-item label="选择月份" prop="dataDate" v-if="queryParams.remark === 'month'">
+        <el-date-picker
+            v-model="queryParams.dataDate"
+            type="month"
+            placeholder="请选择月份"
+            style="width: 150px;"
+            value-format="YYYY-MM"
+            @change="handleDateChange"
+        />
+      </el-form-item>
+
+      <el-form-item label="选择日期" prop="dataDate" v-if="queryParams.remark === 'day'">
+        <el-date-picker
+            v-model="queryParams.dataDate"
+            type="date"
+            placeholder="请选择日期"
+            style="width: 150px;"
+            value-format="YYYY-MM-DD"
+            @change="handleDateChange"
+        />
+      </el-form-item>
+
+      <el-form-item label="机台号" prop="deviceId">
+        <el-input
+            v-model="queryParams.deviceId"
+            placeholder="请输入机台号"
+            clearable
+            @input="handleDeviceIdChange"
+        />
+      </el-form-item>
+      <el-form-item label="分析结果" prop="result">
+        <el-select
+            v-model="queryParams.result"
+            placeholder="请选择分析结果"
+            clearable
+            style="width: 150px;"
+            @change="handleResultChange"
+        >
+          <el-option label="平稳" value="平稳"></el-option>
+          <el-option label="上升" value="上升"></el-option>
+          <el-option label="明显上升" value="明显上升"></el-option>
+          <el-option label="下降" value="下降"></el-option>
+          <el-option label="明显下降" value="明显下降"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleFilter">搜索</el-button>
+        <el-button icon="Refresh" @click="resetFilter">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 双图表展示 -->
+    <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"/>
+      <!--      <el-table-column label="ID" align="center" prop="id" />-->
+      <el-table-column label="机台号" align="center" prop="deviceId"/>
+      <el-table-column label="数据量" align="center" prop="dataNum"/>
+      <el-table-column label="斜率" align="center" prop="slope">
+        <template #default="scope">
+          {{ (scope.row.slope).toFixed(2) }}
+        </template>
+      </el-table-column>
+      <el-table-column label="标准差" align="center" prop="stdDev">
+        <template #default="scope">
+          {{ (scope.row.stdDev).toFixed(2) }}
+        </template>
+      </el-table-column>
+      <el-table-column label="趋势分析" align="center" prop="result">
+        <template #default="scope">
+          <el-link type="primary" @click="handleResultClick(scope.row)">{{ scope.row.result }}</el-link>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 图表弹窗 -->
+    <el-dialog :title="'设备[' + currentRow.deviceId + ']分析结果详情'" v-model="chartOpen" width="800px"
+               append-to-body>
+      <div style="text-align: center; margin: 20px 0;">
+        <p>设备名称: {{ currentRow.deviceName }}</p>
+        <p>分析结果: {{ currentRow.result }}</p>
+      </div>
+      <div v-if="currentRow.list && currentRow.list.length > 0">
+        <!-- 使用ECharts展示折线图 -->
+        <div ref="chartRef" style="width: 100%; height: 400px;"></div>
+      </div>
+      <div v-else>
+        <p style="text-align: center;">暂无详细数据</p>
+      </div>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="closeChart">关 闭</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="CalcStop">
+import {gzStop} from "@/api/calc/calcStop";
+import {getCurrentInstance, nextTick, reactive, ref, toRefs} from 'vue';
+import * as echarts from 'echarts';
+
+const {proxy} = getCurrentInstance();
+
+const calcStopList = ref([]);
+const filteredData = ref([]);
+const open = ref(false);
+const chartOpen = ref(false);  // 添加图表弹窗状态
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+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 = () => {
+  const now = new Date();
+  const defaultDate = new Date(now.getTime() - 31 * 60 * 60 * 1000);
+  return defaultDate.toISOString().split('T')[0]; // 格式化为 YYYY-MM-DD
+};
+
+// 获取当前年月
+const getCurrentMonth = () => {
+  const now = new Date();
+  const year = now.getFullYear();
+  const month = (now.getMonth() + 1).toString().padStart(2, '0');
+  return `${year}-${month}`;
+};
+
+const data = reactive({
+  form: {},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 1000,
+    deviceId: null,
+    dataDate: getDefaultDate(),
+    hour: null,
+    startTime: getDefaultDate(),
+    endTime: getDefaultDate(),
+    stopType: 6,
+    result: "",  // 设置默认选中值
+    remark: "day", // 统计方式: month-按月, day-按天,默认按天
+    selectedMonth: null, // 选择的月份(已废弃,使用dataDate替代)
+    selectedDate: null  // 选择的日期(已废弃,使用dataDate替代)
+  },
+  rules: {}
+});
+
+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() {
+  // 清空之前选择的日期
+  queryParams.value.dataDate = null;
+  // 重置其他查询条件
+  queryParams.value.deviceId = null;
+  queryParams.value.result = "";
+
+  // 如果切换到按天统计,设置默认日期
+  if (queryParams.value.remark === 'day') {
+    const defaultDate = getDefaultDate();
+    queryParams.value.dataDate = defaultDate;
+    queryParams.value.startTime = defaultDate;
+    queryParams.value.endTime = defaultDate;
+  }
+  // 如果切换到按月统计,设置默认月份
+  else if (queryParams.value.remark === 'month') {
+    const currentMonth = getCurrentMonth();
+    queryParams.value.dataDate = currentMonth;
+    queryParams.value.startTime = currentMonth + "-01";
+    // 设置为该月的最后一天作为结束时间
+    const year = parseInt(currentMonth.split("-")[0]);
+    const month = parseInt(currentMonth.split("-")[1]);
+    const lastDay = new Date(year, month, 0).getDate();
+    queryParams.value.endTime = currentMonth + "-" + (lastDay < 10 ? "0" + lastDay : lastDay);
+  }
+
+  // 统计方式改变后自动查询
+  handleFilter();
+}
+
+// 月份选择变化处理
+function handleMonthChange() {
+  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;
+  }
+}
+
+// 日期选择变化处理
+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();
+}
+
+// 分析天数变化处理
+function handleDaysChange() {
+  getList(); // 分析天数变化时重新从后端获取数据
+}
+
+// 绘制趋势分析图(南丁格尔图)
+function drawTrendChart() {
+  if (!trendChartRef.value || !statistics.value) return;
+
+  // 销毁之前的实例
+  if (trendChartInstance) {
+    trendChartInstance.dispose();
+  }
+
+  // 初始化新的实例
+  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);
+}
+
+// 计算统计数据
+function calculateStatistics(data) {
+  if (!data || !Array.isArray(data)) {
+    return;
+  }
+
+  // 计算设备总数
+  const totalDevices = data.length;
+
+  // 统计各趋势的数量
+  const trendCounts = {
+    "": 0,
+    "上升": 0,
+    "平稳": 0,
+    "下降": 0,
+    "明显下降": 0
+  };
+
+  data.forEach(item => {
+    if (trendCounts.hasOwnProperty(item.result)) {
+      trendCounts[item.result]++;
+    }
+  });
+
+  // 只有在没有从后端获取到统计数据时才使用计算的统计数据
+  if (!statistics.value) {
+    statistics.value = {
+      totalDevices,
+      trendCounts
+    };
+  }
+}
+
+// 机台号变化处理
+function handleDeviceIdChange() {
+  filterData();
+}
+
+// 分析结果变化处理
+function handleResultChange() {
+  filterData();
+}
+
+/** 过滤操作 */
+function handleFilter() {
+  getList();
+}
+
+/** 重置过滤操作 */
+function resetFilter() {
+  proxy.resetForm("queryRef");
+  queryParams.value.deviceId = null;
+  queryParams.value.result = ""; // 重置时也保持默认选中
+  queryParams.value.remark = 'day'; // 重置为按天统计
+  queryParams.value.dataDate = getDefaultDate(); // 重置为默认日期
+  queryParams.value.startTime = getDefaultDate(); // 重置为默认日期
+  queryParams.value.endTime = getDefaultDate(); // 重置为默认日期
+  filterData(); // 改为调用filterData而不是getList()
+}
+
+// 过滤数据
+function filterData() {
+  if (!calcStopList.value || !Array.isArray(calcStopList.value)) {
+    filteredData.value = [];
+    return;
+  }
+
+  // 如果没有过滤条件,返回所有数据
+  if (!queryParams.value.deviceId && !queryParams.value.result) {
+    filteredData.value = calcStopList.value;
+    // 根据完整数据重新计算统计数据
+    calculateStatistics(calcStopList.value);
+    return;
+  }
+
+  filteredData.value = calcStopList.value.filter(item => {
+    // 根据机台号过滤(数字模糊匹配)
+    if (queryParams.value.deviceId &&
+        item.deviceId &&
+        item.deviceId.toString().indexOf(queryParams.value.deviceId) === -1) {
+      return false;
+    }
+
+    // 根据分析结果过滤
+    if (queryParams.value.result &&
+        item.result !== queryParams.value.result) {
+      return false;
+    }
+
+    return true;
+  });
+
+  // 根据过滤后的数据重新计算统计数据
+  calculateStatistics(filteredData.value);
+}
+
+/** 处理分析结果点击事件 */
+function handleResultClick(row) {
+  currentRow.value = row;
+  chartOpen.value = true;
+
+  // 在弹窗打开后初始化图表
+  setTimeout(() => {
+    initChart();
+  }, 100);
+}
+
+// 初始化图表
+function initChart() {
+  if (chartRef.value) {
+    // 销毁之前的实例
+    if (chartInstance) {
+      chartInstance.dispose();
+    }
+
+    // 初始化新的实例
+    chartInstance = echarts.init(chartRef.value);
+
+    // 准备数据
+    let dates = currentRow.value.list.map(item => item.date);
+    const times = currentRow.value.list.map(item => item.times);
+
+    // 如果是按月统计,只显示日期部分,不显示时间
+    if (queryParams.value.remark === 'month') {
+      dates = dates.map(date => {
+        // 只保留日期部分 YYYY-MM-DD
+        if (date.includes(' ')) {
+          return date.split(' ')[0];
+        }
+        return date;
+      });
+    }
+
+    // 配置图表选项
+    const option = {
+      title: {
+        text: '异常次数趋势图',
+        left: 'center'
+      },
+      tooltip: {
+        trigger: 'axis',
+        formatter: function (params) {
+          // 如果是按月统计,提示框中也只显示日期
+          if (queryParams.value.remark === 'month') {
+            const date = params[0].axisValue;
+            const count = params[0].data;
+            return `${date}<br />次数: ${count}`;
+          }
+          return params[0].axisValue + '<br />' + params[0].seriesName + ': ' + params[0].data;
+        }
+      },
+      xAxis: {
+        type: 'category',
+        data: dates,
+        name: '日期'
+      },
+      yAxis: {
+        type: 'value',
+        name: '次数(次)'
+      },
+      series: [{
+        data: times,
+        type: 'line',
+        smooth: true,
+        markPoint: {
+          data: [
+            {type: 'max', name: '最大值'},
+            {type: 'min', name: '最小值'}
+          ]
+        },
+        markLine: {
+          data: [
+            {type: 'average', name: '平均值'}
+          ]
+        }
+      }]
+    };
+
+    // 设置配置项
+    chartInstance.setOption(option);
+  }
+}
+
+/** 关闭图表弹窗 */
+function closeChart() {
+  chartOpen.value = false;
+  // 销毁图表实例
+  if (chartInstance) {
+    chartInstance.dispose();
+    chartInstance = null;
+  }
+}
+
+// 监听窗口大小变化,自动调整图表大小
+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>
+.statistic-card {
+  margin-bottom: 20px;
+  background-color: #f5f7fa;
+  border: 1px solid #ebeef5;
+  border-radius: 4px;
+}
+
+.statistic-container {
+  display: flex;
+  align-items: center;
+  flex-wrap: wrap;
+}
+
+.statistic-item {
+  display: flex;
+  align-items: center;
+  margin-right: 20px;
+  margin-bottom: 10px;
+}
+
+.statistic-label {
+  font-weight: bold;
+  margin-right: 5px;
+  color: #606266;
+}
+
+.statistic-value {
+  font-size: 16px;
+  font-weight: bold;
+  color: #409eff;
+}
+
+.statistic-divider {
+  width: 1px;
+  height: 20px;
+  background-color: #dcdfe6;
+  margin-right: 20px;
+  margin-bottom: 10px;
+}
+</style>

+ 779 - 0
src/views/calc/calcStop/jtStop.vue

@@ -0,0 +1,779 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="统计方式" prop="remark">
+        <el-select
+            v-model="queryParams.remark"
+            placeholder="请选择统计方式"
+            clearable
+            style="width: 150px;"
+            @change="handleRemarkChange"
+        >
+          <el-option label="按月" value="month"></el-option>
+          <el-option label="按天" value="day"></el-option>
+        </el-select>
+      </el-form-item>
+
+      <el-form-item label="选择月份" prop="dataDate" v-if="queryParams.remark === 'month'">
+        <el-date-picker
+            v-model="queryParams.dataDate"
+            type="month"
+            placeholder="请选择月份"
+            style="width: 150px;"
+            value-format="YYYY-MM"
+            @change="handleDateChange"
+        />
+      </el-form-item>
+
+      <el-form-item label="选择日期" prop="dataDate" v-if="queryParams.remark === 'day'">
+        <el-date-picker
+            v-model="queryParams.dataDate"
+            type="date"
+            placeholder="请选择日期"
+            style="width: 150px;"
+            value-format="YYYY-MM-DD"
+            @change="handleDateChange"
+        />
+      </el-form-item>
+
+      <el-form-item label="机台号" prop="deviceId">
+        <el-input
+            v-model="queryParams.deviceId"
+            placeholder="请输入机台号"
+            clearable
+            @input="handleDeviceIdChange"
+        />
+      </el-form-item>
+      <el-form-item label="分析结果" prop="result">
+        <el-select
+            v-model="queryParams.result"
+            placeholder="请选择分析结果"
+            clearable
+            style="width: 150px;"
+            @change="handleResultChange"
+        >
+          <el-option label="平稳" value="平稳"></el-option>
+          <el-option label="上升" value="上升"></el-option>
+          <el-option label="明显上升" value="明显上升"></el-option>
+          <el-option label="下降" value="下降"></el-option>
+          <el-option label="明显下降" value="明显下降"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleFilter">搜索</el-button>
+        <el-button icon="Refresh" @click="resetFilter">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 双图表展示 -->
+    <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"/>
+      <!--      <el-table-column label="ID" align="center" prop="id" />-->
+      <el-table-column label="机台号" align="center" prop="deviceId"/>
+      <el-table-column label="数据量" align="center" prop="dataNum"/>
+      <el-table-column label="斜率" align="center" prop="slope">
+        <template #default="scope">
+          {{ (scope.row.slope).toFixed(2) }}
+        </template>
+      </el-table-column>
+      <el-table-column label="标准差" align="center" prop="stdDev">
+        <template #default="scope">
+          {{ (scope.row.stdDev).toFixed(2) }}
+        </template>
+      </el-table-column>
+      <el-table-column label="趋势分析" align="center" prop="result">
+        <template #default="scope">
+          <el-link type="primary" @click="handleResultClick(scope.row)">{{ scope.row.result }}</el-link>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 图表弹窗 -->
+    <el-dialog :title="'设备[' + currentRow.deviceId + ']分析结果详情'" v-model="chartOpen" width="800px"
+               append-to-body>
+      <div style="text-align: center; margin: 20px 0;">
+        <p>设备名称: {{ currentRow.deviceName }}</p>
+        <p>分析结果: {{ currentRow.result }}</p>
+      </div>
+      <div v-if="currentRow.list && currentRow.list.length > 0">
+        <!-- 使用ECharts展示折线图 -->
+        <div ref="chartRef" style="width: 100%; height: 400px;"></div>
+      </div>
+      <div v-else>
+        <p style="text-align: center;">暂无详细数据</p>
+      </div>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="closeChart">关 闭</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="CalcStop">
+import {gzStop} from "@/api/calc/calcStop";
+import {getCurrentInstance, nextTick, reactive, ref, toRefs} from 'vue';
+import * as echarts from 'echarts';
+
+const {proxy} = getCurrentInstance();
+
+const calcStopList = ref([]);
+const filteredData = ref([]);
+const open = ref(false);
+const chartOpen = ref(false);  // 添加图表弹窗状态
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+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 = () => {
+  const now = new Date();
+  const defaultDate = new Date(now.getTime() - 31 * 60 * 60 * 1000);
+  return defaultDate.toISOString().split('T')[0]; // 格式化为 YYYY-MM-DD
+};
+
+// 获取当前年月
+const getCurrentMonth = () => {
+  const now = new Date();
+  const year = now.getFullYear();
+  const month = (now.getMonth() + 1).toString().padStart(2, '0');
+  return `${year}-${month}`;
+};
+
+const data = reactive({
+  form: {},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 1000,
+    deviceId: null,
+    dataDate: getDefaultDate(),
+    hour: null,
+    startTime: getDefaultDate(),
+    endTime: getDefaultDate(),
+    stopType: 7,
+    result: "",  // 设置默认选中值
+    remark: "day", // 统计方式: month-按月, day-按天,默认按天
+    selectedMonth: null, // 选择的月份(已废弃,使用dataDate替代)
+    selectedDate: null  // 选择的日期(已废弃,使用dataDate替代)
+  },
+  rules: {}
+});
+
+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() {
+  // 清空之前选择的日期
+  queryParams.value.dataDate = null;
+  // 重置其他查询条件
+  queryParams.value.deviceId = null;
+  queryParams.value.result = "";
+
+  // 如果切换到按天统计,设置默认日期
+  if (queryParams.value.remark === 'day') {
+    const defaultDate = getDefaultDate();
+    queryParams.value.dataDate = defaultDate;
+    queryParams.value.startTime = defaultDate;
+    queryParams.value.endTime = defaultDate;
+  }
+  // 如果切换到按月统计,设置默认月份
+  else if (queryParams.value.remark === 'month') {
+    const currentMonth = getCurrentMonth();
+    queryParams.value.dataDate = currentMonth;
+    queryParams.value.startTime = currentMonth + "-01";
+    // 设置为该月的最后一天作为结束时间
+    const year = parseInt(currentMonth.split("-")[0]);
+    const month = parseInt(currentMonth.split("-")[1]);
+    const lastDay = new Date(year, month, 0).getDate();
+    queryParams.value.endTime = currentMonth + "-" + (lastDay < 10 ? "0" + lastDay : lastDay);
+  }
+
+  // 统计方式改变后自动查询
+  handleFilter();
+}
+
+// 月份选择变化处理
+function handleMonthChange() {
+  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;
+  }
+}
+
+// 日期选择变化处理
+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();
+}
+
+// 分析天数变化处理
+function handleDaysChange() {
+  getList(); // 分析天数变化时重新从后端获取数据
+}
+
+// 绘制趋势分析图(南丁格尔图)
+function drawTrendChart() {
+  if (!trendChartRef.value || !statistics.value) return;
+
+  // 销毁之前的实例
+  if (trendChartInstance) {
+    trendChartInstance.dispose();
+  }
+
+  // 初始化新的实例
+  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);
+}
+
+// 计算统计数据
+function calculateStatistics(data) {
+  if (!data || !Array.isArray(data)) {
+    return;
+  }
+
+  // 计算设备总数
+  const totalDevices = data.length;
+
+  // 统计各趋势的数量
+  const trendCounts = {
+    "": 0,
+    "上升": 0,
+    "平稳": 0,
+    "下降": 0,
+    "明显下降": 0
+  };
+
+  data.forEach(item => {
+    if (trendCounts.hasOwnProperty(item.result)) {
+      trendCounts[item.result]++;
+    }
+  });
+
+  // 只有在没有从后端获取到统计数据时才使用计算的统计数据
+  if (!statistics.value) {
+    statistics.value = {
+      totalDevices,
+      trendCounts
+    };
+  }
+}
+
+// 机台号变化处理
+function handleDeviceIdChange() {
+  filterData();
+}
+
+// 分析结果变化处理
+function handleResultChange() {
+  filterData();
+}
+
+/** 过滤操作 */
+function handleFilter() {
+  getList();
+}
+
+/** 重置过滤操作 */
+function resetFilter() {
+  proxy.resetForm("queryRef");
+  queryParams.value.deviceId = null;
+  queryParams.value.result = ""; // 重置时也保持默认选中
+  queryParams.value.remark = 'day'; // 重置为按天统计
+  queryParams.value.dataDate = getDefaultDate(); // 重置为默认日期
+  queryParams.value.startTime = getDefaultDate(); // 重置为默认日期
+  queryParams.value.endTime = getDefaultDate(); // 重置为默认日期
+  filterData(); // 改为调用filterData而不是getList()
+}
+
+// 过滤数据
+function filterData() {
+  if (!calcStopList.value || !Array.isArray(calcStopList.value)) {
+    filteredData.value = [];
+    return;
+  }
+
+  // 如果没有过滤条件,返回所有数据
+  if (!queryParams.value.deviceId && !queryParams.value.result) {
+    filteredData.value = calcStopList.value;
+    // 根据完整数据重新计算统计数据
+    calculateStatistics(calcStopList.value);
+    return;
+  }
+
+  filteredData.value = calcStopList.value.filter(item => {
+    // 根据机台号过滤(数字模糊匹配)
+    if (queryParams.value.deviceId &&
+        item.deviceId &&
+        item.deviceId.toString().indexOf(queryParams.value.deviceId) === -1) {
+      return false;
+    }
+
+    // 根据分析结果过滤
+    if (queryParams.value.result &&
+        item.result !== queryParams.value.result) {
+      return false;
+    }
+
+    return true;
+  });
+
+  // 根据过滤后的数据重新计算统计数据
+  calculateStatistics(filteredData.value);
+}
+
+/** 处理分析结果点击事件 */
+function handleResultClick(row) {
+  currentRow.value = row;
+  chartOpen.value = true;
+
+  // 在弹窗打开后初始化图表
+  setTimeout(() => {
+    initChart();
+  }, 100);
+}
+
+// 初始化图表
+function initChart() {
+  if (chartRef.value) {
+    // 销毁之前的实例
+    if (chartInstance) {
+      chartInstance.dispose();
+    }
+
+    // 初始化新的实例
+    chartInstance = echarts.init(chartRef.value);
+
+    // 准备数据
+    let dates = currentRow.value.list.map(item => item.date);
+    const times = currentRow.value.list.map(item => item.times);
+
+    // 如果是按月统计,只显示日期部分,不显示时间
+    if (queryParams.value.remark === 'month') {
+      dates = dates.map(date => {
+        // 只保留日期部分 YYYY-MM-DD
+        if (date.includes(' ')) {
+          return date.split(' ')[0];
+        }
+        return date;
+      });
+    }
+
+    // 配置图表选项
+    const option = {
+      title: {
+        text: '异常次数趋势图',
+        left: 'center'
+      },
+      tooltip: {
+        trigger: 'axis',
+        formatter: function (params) {
+          // 如果是按月统计,提示框中也只显示日期
+          if (queryParams.value.remark === 'month') {
+            const date = params[0].axisValue;
+            const count = params[0].data;
+            return `${date}<br />次数: ${count}`;
+          }
+          return params[0].axisValue + '<br />' + params[0].seriesName + ': ' + params[0].data;
+        }
+      },
+      xAxis: {
+        type: 'category',
+        data: dates,
+        name: '日期'
+      },
+      yAxis: {
+        type: 'value',
+        name: '次数(次)'
+      },
+      series: [{
+        data: times,
+        type: 'line',
+        smooth: true,
+        markPoint: {
+          data: [
+            {type: 'max', name: '最大值'},
+            {type: 'min', name: '最小值'}
+          ]
+        },
+        markLine: {
+          data: [
+            {type: 'average', name: '平均值'}
+          ]
+        }
+      }]
+    };
+
+    // 设置配置项
+    chartInstance.setOption(option);
+  }
+}
+
+/** 关闭图表弹窗 */
+function closeChart() {
+  chartOpen.value = false;
+  // 销毁图表实例
+  if (chartInstance) {
+    chartInstance.dispose();
+    chartInstance = null;
+  }
+}
+
+// 监听窗口大小变化,自动调整图表大小
+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>
+.statistic-card {
+  margin-bottom: 20px;
+  background-color: #f5f7fa;
+  border: 1px solid #ebeef5;
+  border-radius: 4px;
+}
+
+.statistic-container {
+  display: flex;
+  align-items: center;
+  flex-wrap: wrap;
+}
+
+.statistic-item {
+  display: flex;
+  align-items: center;
+  margin-right: 20px;
+  margin-bottom: 10px;
+}
+
+.statistic-label {
+  font-weight: bold;
+  margin-right: 5px;
+  color: #606266;
+}
+
+.statistic-value {
+  font-size: 16px;
+  font-weight: bold;
+  color: #409eff;
+}
+
+.statistic-divider {
+  width: 1px;
+  height: 20px;
+  background-color: #dcdfe6;
+  margin-right: 20px;
+  margin-bottom: 10px;
+}
+</style>