严智鑫
2025-04-03 f2a5a09c879849110b42c46297ab4c080500e61d
Merge branch 'master' of http://159.223.171.199:10439/r/JiuMuMES
4个文件已修改
712 ■■■■ 已修改文件
JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/mechanicalMonitor/controller/MechanicalMonitorController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
UI-Project/src/layout/MainErpView.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
UI-Project/src/views/KanbanDisplay/kanbanDisplay.vue 628 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
UI-Project/src/views/MechanicalMonitor/mechanicalMonitor.vue 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/mechanicalMonitor/controller/MechanicalMonitorController.java
@@ -16,7 +16,7 @@
@Api(tags = "设备状态监控")
@RestController
@RequestMapping("/deviceInteraction/mechanicalMonitor")
@RequestMapping("/mechanicalMonitor")
public class MechanicalMonitorController {
    @Autowired
UI-Project/src/layout/MainErpView.vue
@@ -234,9 +234,9 @@
}
#main {
  width: 99%;
  width: 100%;
  float: right;
  height: 99%;
  height: 100%;
  background-color: #fff;
}
UI-Project/src/views/KanbanDisplay/kanbanDisplay.vue
@@ -1,10 +1,48 @@
<!--  空白页  -->
<script setup>
import { ref, onMounted } from 'vue'
import { ref, onMounted, onUnmounted, nextTick } from 'vue'
import * as echarts from 'echarts'
import request from '@/utils/request'
const dashboardRef = ref(null)
const standardWidth = 1920 // 设计稿标准宽度
const standardHeight = 1080 // 设计稿标准高度
// 计算缩放比例并应用
const setScale = () => {
  if (!dashboardRef.value) return
  const w = window.innerWidth
  const h = window.innerHeight
  // 计算宽高比例
  const wScale = w / standardWidth
  const hScale = h / standardHeight
  // 使用较小的缩放比例,确保内容完全显示
  const scale = Math.min(wScale, hScale)
  // 计算居中偏移
  const offsetX = (w - standardWidth * scale) / 2
  const offsetY = (h - standardHeight * scale) / 2
  // 应用变换
  dashboardRef.value.style.transform = `scale(${scale})`
  dashboardRef.value.style.transformOrigin = '0 0'
  dashboardRef.value.style.marginLeft = `${offsetX}px`
  dashboardRef.value.style.marginTop = `${offsetY}px`
}
// 监听窗口大小变化
const handleResize = () => {
  setScale()
  // 重新渲染所有图表
  charts.forEach(chart => {
    chart.resize()
  })
}
// 存储所有图表实例
const charts = []
const energyData = ref([])
const notCompleteData = ref([])
@@ -27,29 +65,96 @@
// 获取未完成数据
const loadNotCompleteData = async () => {
  request.post('/deviceInteraction/primitiveTask/findDayNotCompleteOutput',
      {
        "dayCount": 2
      }).then((res) => {
        if (res.code == 200) {
          notCompleteData.value = res.data;
          console.log("未完成"+res.data+"1");
        } else {
          console.error('请求当日产量数据失败:', error);
        }
      });
    {
      "dayCount": 2
    }).then((res) => {
      if (res.code == 200) {
        // 直接加载所有数据
        notCompleteData.value = res.data;
        console.log("加载数据完成,共" + res.data.length + "条");
        // 直接开始滚动
        nextTick(() => {
          startScrollingImmediately();
        });
      } else {
        console.error('请求当日产量数据失败:', error);
      }
    });
}
// 按数据条数设置滚动时间,确保完整滚动
const startScrollingImmediately = () => {
  const tableBody = document.querySelector('.el-table__body');
  const tableWrapper = document.querySelector('.el-table__body-wrapper');
  if (!tableBody || !tableWrapper) {
    console.log("找不到表格元素");
    return;
  }
  // 只有当数据超过5条时才滚动
  if (notCompleteData.value.length > 5) {
    // console.log(`数据量(${notCompleteData.value.length}条)超过5条,开始滚动`);
    // 每条数据的显示时间(秒)
    const timePerRow = 0.8; // 每条数据停留0.4秒
    // 计算总滚动时间
    const totalRows = notCompleteData.value.length;
    const scrollTime = Math.max(totalRows * timePerRow, 5); // 至少5秒
    // console.log(`数据量: ${totalRows}条, 每条${timePerRow}秒, 总滚动时间: ${scrollTime.toFixed(1)}秒`);
    // 先删除可能存在的旧样式
    const oldStyle = document.getElementById('scroll-animation-style');
    if (oldStyle) {
      document.head.removeChild(oldStyle);
    }
    // 计算表格实际高度和容器高度
    const tableHeight = tableBody.offsetHeight;
    const wrapperHeight = tableWrapper.offsetHeight;
    // 计算实际需要滚动的距离
    const scrollDistance = tableHeight - wrapperHeight;
    // console.log(`表格高度: ${tableHeight}px, 容器高度: ${wrapperHeight}px, 滚动距离: ${scrollDistance}px`);
    // 创建新样式,确保滚动到最后一行
    const style = document.createElement('style');
    style.id = 'scroll-animation-style';
    // 修改关键帧动画,确保完整滚动
    style.innerHTML = `
      @keyframes scroll-animation {
        0% { transform: translateY(0); }
        5% { transform: translateY(0); } /* 开始时停留时间 */
        90% { transform: translateY(-${scrollDistance}px); } /* 使用精确像素值确保滚动全部内容 */
        100% { transform: translateY(-${scrollDistance}px); } /* 结束时停留时间 */
      }
    `;
    document.head.appendChild(style);
    // 直接设置内联样式,先清除再应用
    tableBody.style.animation = 'none';
    tableBody.offsetHeight; // 强制重排
    tableBody.style.animation = `scroll-animation ${scrollTime}s linear infinite`;
    console.log(`滚动动画已设置,每条数据${timePerRow}秒,总计${scrollTime.toFixed(1)}秒/轮,滚动距离${scrollDistance}px`);
  } else {
    console.log(`数据量(${notCompleteData.value.length}条)不足5条,不需要滚动`);
    // 停止滚动
    tableBody.style.animation = 'none';
  }
}
// 修改图表初始化方法
const draw = (name, Option) => {
  var myChart = echarts.init(document.getElementById(name));
  myChart.setOption(Option);
}
const drawDay = (name, Option) => {
  Option.title.text = "能耗管理";
  draw(name, Option);
  const chart = echarts.init(document.getElementById(name))
  chart.setOption(Option)
  charts.push(chart)
}
// 更新能耗图表
@@ -67,41 +172,86 @@
  const energyoption = {
    title: {
      text: '能耗管理'
      text: '能耗管理',
      textStyle: {
        fontSize: 25,
        fontWeight: 'bold',
        color: 'white' // 设置标题颜色为白色
      },
    },
    tooltip: {
      trigger: 'axis',
      axisPointer: {
        type: 'cross',
        label: {
          backgroundColor: '#6a7985'
          backgroundColor: '#6a7985',
          fontSize: 16,  // 提示框文字大小
          color: 'white' // 设置提示框文字颜色为白色
        }
      }
    },
    legend: {
      data: ['能耗值']
      data: ['能耗值'],
      textStyle: {
        fontSize: 25,
        fontWeight: 'bold',
        color: 'white' // 设置图例文字颜色为白色
      }
    },
    toolbox: {
      show: true,
      feature: {
        dataZoom: {
          yAxisIndex: 'none'
        },
        dataView: { readOnly: false },
        magicType: { type: ['line', 'bar'] },
        restore: {},
        saveAsImage: {}
      },
      iconStyle: {
        color: 'white' // 设置工具框图标颜色为白色
      }
    },
    grid: {
      left: '3%',
      right: '4%',
      bottom: '3%',
      bottom: '10%',
      containLabel: true
    },
    xAxis: [
      {
        type: 'category',
        boundaryGap: false,
        data: sortedData.map(item => item.recordDate)
        data: sortedData.map(item => item.recordDate),
        axisLabel: {
          fontSize: 20,
          interval: 'auto',    // 自动计算间隔
          margin: 15,          // 与轴线的距离
          formatter: (value) => {
            // 只显示月-日
            const date = new Date(value);
            return `${date.getMonth() + 1}-${date.getDate()}`;
          },
          color: 'white' // 设置 x 轴标签颜色为白色
        },
        nameTextStyle: {
          fontSize: 20,
          color: 'white' // 设置 x 轴名称颜色为白色
        }
      }
    ],
    yAxis: [
      {
        type: 'value'
        type: 'value',
        axisLabel: {
          fontSize: 20,   // y 轴标签文字大小
          color: 'white' // 设置 y 轴标签颜色为白色
        },
        nameTextStyle: {
          fontSize: 20,   // 坐标轴名称文字大小
          color: 'white' // 设置 y 轴名称颜色为白色
        }
      }
    ],
    series: [
@@ -111,32 +261,116 @@
        areaStyle: {},
        label: {
          show: true,
          position: 'top'
          position: 'top',
          fontSize: 16,  // 数据标签文字大小
          formatter: '{c}',
          color: 'white' // 设置数据标签颜色为白色
        },
        data: sortedData.map(item => item.energyValue)
      }
    ]
  }
  drawDay('drawLineChart_day71', energyoption);
  draw('drawLineChart_day71', energyoption);
}
onMounted(() => {
  setScale()
  window.addEventListener('resize', handleResize)
  loadEnergyData();
  loadNotCompleteData();
})
onUnmounted(() => {
  window.removeEventListener('resize', handleResize)
  charts.forEach(chart => {
    chart.dispose()
  })
})
</script>
<template>
  <div class="dashboard-container" ref="dashboardRef">
    <div class="dashboard-content">
      <div style="font-weight: 800;font-size: 30px;height: 70px;line-height: 70px;border: 1px solid #ccc;text-align: center;">
        JOMOO配套工厂镜片车间生产看板
      </div>
      <div style="width:100% ;height: 880px;">
        <div style="width:100% ;height: 33.3%;border: 1px solid #ccc;">
          <div id="drawLineChart_day11" style="height: 100%;width: 30%;border: 1px solid #ccc;float: left;">日单达成率-片数</div>
          <div id="drawLineChart_day12" class="table-container">
            <div class="table-title">当日未完成量</div>
            <div class="table-scroll-wrapper">
              <el-table
                height="100%"
                :data="notCompleteData"
                :header-cell-style="{ background: '#052c52', color: 'white', textAlign: 'center' }"
                :cell-style="{ textAlign: 'center' }">
                <el-table-column prop="scanId" :label="$t('glassInfo.scanId')" />
                <el-table-column prop="notComplete" :label="$t('glassInfo.notCompleteCount')" />
                <el-table-column
                  prop="area_sum"
                  :label="$t('glassInfo.notCompleteArea')"
                  :formatter="row => row.area_sum ? Number(row.area_sum).toFixed(2) : '0.00'" />
              </el-table>
            </div>
          </div>
          <div id="drawLineChart_day71" style="height: 100%;width: 40%;border: 1px solid #ccc;float: left;">能耗管理-按天显示(手输)
          </div>
        </div>
        <div style="width:100% ;height: 37.5%;border: 1px solid #ccc;">
          <div id="drawLineChart_day31" style="height: 100%;width: 100%;border: 1px solid #ccc;">两线生产对比-片数</div>
        </div>
        <div style="width:100% ;height: 37.5%;border: 1px solid #ccc;">
          <div id="drawLineChart_day51" style="height: 100%;width: 80%;border: 1px solid #ccc;float: left;">计划量-片数、平方</div>
          <div id="drawLineChart_day91" style="height: 100%;width: 20%;float: left;">
            <div style="font-weight: 700;font-size: 20px;height: 30px;line-height: 30px;text-align: center;border: 1px solid #ccc;">总计划量-片数、平方</div>
            <div id="textDay" style="font-size: 20px;height: 30px;margin-left: 20px;margin-top: 20px;">日期:2023-03-01  - 2023-03-01</div>
            <div id="textprice" style="font-size: 20px;height: 30px;margin-left: 20px;margin-top: 20px;">片数:25</div>
            <div id="textarea" style="font-size: 20px;height: 30px;margin-left: 20px;margin-top: 20px;">平方数:2999</div>
          </div>
        </div>
      </div>
      <!-- <div style="width:33% ;height: 880px;border: 1px solid #ccc;">
        <div id="drawLineChart_day1" style="height: 300px;width: 25%;border: 1px solid #ccc;float: left;"></div>
        <div id="drawLineChart_day2" style="height: 300px;width: 25%;border: 1px solid #ccc;float: left;"></div>
      </div> -->
    </div>
  </div>
</template>
<script>
export default {
  mounted() {
    const OptionDayMode = {
      title: {
        text: '计划量看板'
        text: '计划量看板',
        textStyle: {
          fontSize: 25,
          fontWeight: 'bold',
          color: 'white' // 设置标题颜色为白色
        }
      },
      tooltip: {
        trigger: 'axis'
        trigger: 'axis',
        axisPointer: {
          label: {
            fontSize: 16,
            color: 'white' // 设置提示框文字颜色为白色
          }
        }
      },
      legend: {},
      legend: {
        textStyle: {
          fontSize: 20,
          fontWeight: 'bold',
          color: 'white' // 设置图例文字颜色为白色
        }
      },
      toolbox: {
        show: true,
        feature: {
@@ -147,61 +381,79 @@
          magicType: { type: ['line', 'bar'] },
          restore: {},
          saveAsImage: {}
        },
        iconStyle: {
          color: 'white' // 设置工具框图标颜色为白色
        }
      },
      grid: {
        left: '3%',
        right: '4%',
        bottom: '10%',
        containLabel: true
      },
      xAxis: {
        type: 'category',
        boundaryGap: false,
        data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
        axisLabel: {
          fontSize: 20,
          interval: 'auto',
          margin: 15,
          formatter: (value, index) => {
            // 如果是日期格式
            if (value.includes('-')) {
              // 对第一个日期显示完整年月日
              if (index === 0) {
                return value;  // 返回完整日期 (例如: 2024-03-21)
              }
              // 其他日期只显示月-日
              return value.split('-').slice(1).join('-');  // (例如: 03-21)
            }
            return value;
          },
          color: 'white' // 设置 x 轴标签颜色为白色
        },
        nameTextStyle: {
          fontSize: 20,
          color: 'white' // 设置 x 轴名称颜色为白色
        }
      },
      yAxis: {
        type: 'value',
        axisLabel: {
          formatter: '{value} '
          fontSize: 20,
          formatter: '{value} ',
          color: 'white' // 设置 y 轴标签颜色为白色
        },
        nameTextStyle: {
          fontSize: 20,
          color: 'white' // 设置 y 轴名称颜色为白色
        }
      },
      series: [
        {
          name: '平方',
          type: 'line',
          data: [10.3, 11.9, 13.9, 19, 12.8, 12, 9],
          markPoint: {
            data: [
              { type: 'max', name: 'Max' },
              { type: 'min', name: 'Min' }
            ]
          label: {
            show: true,
            fontSize: 16,
            formatter: (params) => {
              // 保留两位小数
              return params.value ? Number(params.value).toFixed(2) : '0.00';
            },
            color: 'white' // 设置数据标签颜色为白色
          },
          markLine: {
            data: [{ type: 'average', name: 'Avg' }]
          }
          lineStyle: {
            color: 'blue'
          },
        },
        {
          name: '片数',
          type: 'line',
          data: [1, -2, 2, 5, 3, 2, 0],
          markPoint: {
            data: [{ name: '周最低', value: -2, xAxis: 1, yAxis: -1.5 }]
          },
          markLine: {
            data: [
              { type: 'average', name: 'Avg' },
              [
                {
                  symbol: 'none',
                  x: '90%',
                  yAxis: 'max'
                },
                {
                  symbol: 'circle',
                  label: {
                    position: 'start',
                    formatter: 'Max'
                  },
                  type: 'max',
                  name: '最高点'
                }
              ]
            ]
          label: {
            show: true,
            fontSize: 16,
            color: 'white' // 设置数据标签颜色为白色
          }
        }
      ]
@@ -210,10 +462,20 @@
      tooltip: {
        trigger: 'axis',
        axisPointer: {
          type: 'shadow'
          type: 'shadow',
          label: {
            fontSize: 16,
            color: 'white' // 设置提示框文字颜色为白色
          }
        }
      },
      legend: {},
      legend: {
        textStyle: {
          fontSize: 20,
          fontWeight: 'bold',
          color: 'white' // 设置图例文字颜色为白色
        }
      },
      toolbox: {
        show: true,
        feature: {
@@ -224,63 +486,93 @@
          magicType: { type: ['line', 'bar'] },
          restore: {},
          saveAsImage: {}
        },
        iconStyle: {
          color: 'white' // 设置工具框图标颜色为白色
        }
      },
      grid: {
        left: '3%',
        right: '4%',
        bottom: '3%',
        bottom: '10%',
        containLabel: true
      },
      xAxis: [
        {
          type: 'category',
          data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
          axisLabel: {
            fontSize: 20,
            interval: 'auto',
            margin: 15,
            formatter: (value, index) => {
              // 如果是日期格式
              if (value.includes('-')) {
                // 对第一个日期显示完整年月日
                if (index === 0) {
                  return value;  // 返回完整日期 (例如: 2024-03-21)
                }
                // 其他日期只显示月-日
                return value.split('-').slice(1).join('-');  // (例如: 03-21)
              }
              return value;
            },
            color: 'white' // 设置 x 轴标签颜色为白色
          },
          nameTextStyle: {
            fontSize: 20,
            color: 'white' // 设置 x 轴名称颜色为白色
          }
        }
      ],
      yAxis: [
        {
          type: 'value'
          type: 'value',
          axisLabel: {
            fontSize: 20,
            color: 'white' // 设置 y 轴标签颜色为白色
          },
          nameTextStyle: {
            fontSize: 20,
            color: 'white' // 设置 y 轴名称颜色为白色
          }
        }
      ],
      series: [
        {
          name: '计划量',
          type: 'bar',
          emphasis: {
            focus: 'series'
          },
          barWidth: '40%',  // 相同宽度
          label: {
            show: true,
            formatter: (params) => params.value + '片'
          },
          data: [1000, 1000, 1000, 1000, 1000, 1000, 1000]
            fontSize: 16,
            formatter: (params) => params.value,
            color: 'white',
            position: 'top'
          }
        },
        {
          name: '一线',
          type: 'bar',
          stack: 'Search Engine',
          emphasis: {
            focus: 'series'
          },
          barWidth: '40%',
          label: {
            show: true,
            formatter: (params) => params.value + '片'
            fontSize: 16,
            formatter: (params) => params.value,
            color: 'white',
            position: 'top'
          },
          data: [400, 450, 500, 490, 460, 380, 210]
        },
        {
          name: '二线',
          type: 'bar',
          stack: 'Search Engine',
          barWidth: '40%',
          label: {
            show: true,
            formatter: (params) => params.value + '片'
            fontSize: 16,
            formatter: (params) => params.value,
            color: 'white',
            position: 'top'
          },
          emphasis: {
            focus: 'series'
          },
          data: [500, 400, 300, 400, 400, 290, 700]
        }
      ]
    };
@@ -313,7 +605,7 @@
          console.error('请求日产量-月数据失败:', error);
        }
      });
      //请求计划量
    //请求计划量
    request.post('/deviceInteraction/primitiveTask/findPlannedQuantity',
      {
        "dayCount": 30
@@ -321,24 +613,24 @@
        if (res.code == 200) {
          const modeOptions = res.data;
          this.drawYear('drawLineChart_day51', OptionDayMode, modeOptions);
          let textDay=document.getElementById('textDay');
          let textprice=document.getElementById('textprice');
          let textarea=document.getElementById('textarea');
          let textDay = document.getElementById('textDay');
          let textprice = document.getElementById('textprice');
          let textarea = document.getElementById('textarea');
          let y_pingfang = res.data.map(v => { return v.area_sum });
          let y_pianshu = res.data.map(v => { return v.task_quantity_sum });
          let y_pingfang_sum = 0;
          let y_pianshu_sum =0;
          for(let i=0;i<y_pingfang.length;i++){
            y_pingfang_sum+=y_pingfang[i];
          let y_pianshu_sum = 0;
          for (let i = 0; i < y_pingfang.length; i++) {
            y_pingfang_sum += y_pingfang[i];
          }
          for(let i=0;i<y_pianshu.length;i++){
            y_pianshu_sum+=y_pianshu[i];
          for (let i = 0; i < y_pianshu.length; i++) {
            y_pianshu_sum += y_pianshu[i];
          }
          textDay.innerHTML="日期:"+res.data[0].CreateDate +  "-" +res.data[res.data.length-1].CreateDate;
          textprice.innerHTML="片数:"+y_pianshu_sum;
          textarea.innerHTML="平方数:"+y_pingfang_sum;
          textDay.innerHTML = "日期:" + res.data[0].CreateDate + " - " + res.data[res.data.length - 1].CreateDate;
          textprice.innerHTML = "片数:" + y_pianshu_sum;
          textarea.innerHTML = "平方数:" + Number(y_pingfang_sum).toFixed(2);
          // this.drawYear('drawLineChart_day51', OptionDayMode, modeOptions);
        } else {
          console.error('请求计划量-月数据失败:', error);
@@ -352,7 +644,7 @@
      myChart.setOption(Option);
    },
    drawDay(name, Option, data) {
      console.log(data);
      // console.log(data);
      //Option.title.text="日看板";
      //日看板- 计划量,一线完成,二线完成(片数)
      let x_data = data.map(v => { return v.date });
@@ -382,52 +674,37 @@
}
</script>
<template>
  <div>
    <div style="font-weight: 800;font-size: 30px;height: 70px;line-height: 70px;border: 1px solid #ccc;text-align: center;">
      JOOMO镜片制造中心驾驶舱
    </div>
    <div style="width:100% ;height: 880px;">
      <div style="width:100% ;height: 33.3%;border: 1px solid #ccc;">
        <div id="drawLineChart_day11" style="height: 100%;width: 20%;border: 1px solid #ccc;float: left;">日单达成率-片数</div>
        <div id="drawLineChart_day12" style="height: 100%;width: 30%;max-height: 260px;border: 1px solid #ccc;float: left;">
          <!-- 表格内容详情 -->
          <div style="font-weight: 700;font-size: 20px;height: 30px;line-height: 30px;border: 1px solid #ccc;text-align: center;">当日未完成量</div>
          <el-table :data="notCompleteData" stripe
            height="260px"
            :header-cell-style="{ background: '#F2F3F5 ', color: '#1D2129', textAlign: 'center' }"
            :cell-style="{ textAlign: 'center' }">
            <!-- <el-table-column type="selection" min-width="30" /> -->
            <el-table-column prop="scanId" :label="$t('glassInfo.scanId')" />
            <el-table-column prop="notComplete" :label="$t('glassInfo.notCompleteCount')" />
            <el-table-column prop="area_sum" :label="$t('glassInfo.notCompleteArea')" />
          </el-table>
        </div>
        <div id="drawLineChart_day71" style="height: 100%;width: 50%;border: 1px solid #ccc;float: left;">能耗管理-按天显示(手输)
        </div>
      </div>
      <div style="width:100% ;height: 33.3%;border: 1px solid #ccc;">
        <div id="drawLineChart_day31" style="height: 100%;width: 100%;border: 1px solid #ccc;">两线生产对比-片数</div>
      </div>
      <div style="width:100% ;height: 33.3%;border: 1px solid #ccc;">
        <div id="drawLineChart_day51" style="height: 100%;width: 80%;border: 1px solid #ccc;float: left;">计划量-片数、平方</div>
        <div id="drawLineChart_day91" style="height: 100%;width: 20%;float: left;">
          <div style="font-weight: 700;font-size: 20px;height: 30px;line-height: 30px;text-align: center;border: 1px solid #ccc;">总计划量-片数、平方</div>
          <div id="textDay" style="font-size: 20px;height: 30px;margin-left: 20px;margin-top: 20px;">日期:2023-03-01  - 2023-03-01</div>
          <div id="textprice" style="font-size: 20px;height: 30px;margin-left: 20px;margin-top: 20px;">片数:25</div>
          <div id="textarea" style="font-size: 20px;height: 30px;margin-left: 20px;margin-top: 20px;">平方数:2999</div>
        </div>
      </div>
    </div>
    <!-- <div style="width:33% ;height: 880px;border: 1px solid #ccc;">
      <div id="drawLineChart_day1" style="height: 300px;width: 25%;border: 1px solid #ccc;float: left;"></div>
      <div id="drawLineChart_day2" style="height: 300px;width: 25%;border: 1px solid #ccc;float: left;"></div>
    </div> -->
  </div>
</template>
<style scoped>
.dashboard-container {
  position: absolute;
  width: 1920px; /* 设计稿宽度 */
  background: linear-gradient(to bottom, #001f3f, #0074d9d7);
  color: white;
  overflow: hidden;
  transition: transform 0.3s ease-out, margin 0.3s ease-out;
}
.dashboard-content {
  width: 100%;
  height: 100%;
}
:deep(.el-table__header th) {
  background: #052c52!important;
  color: white!important;
  font-size: large;
}
:deep(.el-table) {
  background: #0b3d6f;
  color: white;
}
:deep(.el-table__body tr) {
  background: #0b3d6f;
  color: rgb(3, 160, 181);
  font-size: 23px;
}
/*0b3d6f*/
.float {
  float: left;
}
@@ -441,4 +718,53 @@
.chart {
  height: 400px;
}
/* 确保图表容器内的echarts实例能够正确显示 */
:deep(.echarts) {
  width: 100% !important;
  height: 100% !important;
}
.table-container {
  height: 100%;
  width: 30%;
  border: 1px solid #ccc;
  float: left;
  display: flex;
  flex-direction: column;
}
.table-title {
  font-weight: bold;
  font-size: 20px;
  padding: 10px;
  text-align: center;
  background-color: #052c52;
  color: white;
}
.table-scroll-wrapper {
  flex: 1;
  overflow: hidden;
  position: relative;
}
/* 强制隐藏滚动条但允许滚动内容 */
:deep(.el-table__body-wrapper) {
  overflow: hidden !important;
}
/* 鼠标悬停时暂停动画 */
:deep(.el-table__body-wrapper:hover .el-table__body) {
  animation-play-state: paused !important;
}
/* 表格字体颜色*/
:deep(.el-table__body tr) {
  color: white;
}
:deep(.el-table__body tr:hover > td) {
  background-color: #1a4d7f !important;
}
</style>
UI-Project/src/views/MechanicalMonitor/mechanicalMonitor.vue
@@ -1,45 +1,25 @@
<script setup>
import { ref, onMounted, onUnmounted, computed } from 'vue';
import axios from 'axios';
import request from '@/utils/request';
const devices = ref([]);
const ws = ref(null);
const activeTab = ref('line1');
const initWebSocket = () => {
    const wsUrl = `ws://${window.location.host}/api/talk/mechanicalMonitor`;
    ws.value = new WebSocket(wsUrl);
    ws.value.onmessage = (event) => {
        const data = JSON.parse(event.data);
        if (data.type === 'status_change') {
            updateDeviceStatus(data.data);
const getMechanicalStatus = () => {
    return request({
        url: '/deviceInteraction/mechanicalMonitor/getMechanicalStatus',
        method: 'post',
        headers: {
            'Content-Type': 'application/json'
        }
    };
    ws.value.onclose = () => {
        console.log('WebSocket连接关闭');
        setTimeout(initWebSocket, 5000);
    };
};
const updateDeviceStatus = (newStatus) => {
    const device = devices.value.find(d => d.deviceId === newStatus.deviceId);
    if (device) {
        Object.assign(device, {
            ...newStatus,
            showAlarmInfo: device.showAlarmInfo,
            alarmTime: newStatus.alarmTime ? new Date(newStatus.alarmTime).toLocaleString() : null,
            disconnectTime: newStatus.disconnectTime ? new Date(newStatus.disconnectTime).toLocaleString() : null
        });
    }
    });
};
const fetchDeviceStatus = async () => {
    try {
        const response = await axios.post('/api/deviceInteraction/mechanicalMonitor/getMechanicalStatus');
        if (response.data.code === 200) {
            const statusData = response.data.data.mechanicalStatus;
        const response = await getMechanicalStatus();
        if (response.code === 200) {
            const statusData = response.data.mechanicalStatus;
            devices.value = statusData.map(device => ({
                ...device,
                showAlarmInfo: false,
@@ -48,7 +28,7 @@
            }));
        }
    } catch (error) {
        console.error('获取设备状态失败:', error);
        console.error('获取设备状态失败:', error.message || error);
    }
};
@@ -84,21 +64,17 @@
onMounted(() => {
    fetchDeviceStatus();
    initWebSocket();
});
onUnmounted(() => {
    if (ws.value) {
        ws.value.close();
    }
    const timer = setInterval(fetchDeviceStatus, 30000);
    onUnmounted(() => {
        clearInterval(timer);
    });
});
</script>
<template>
    <div class="monitoring-container">
        <h1>九牧设备连接及故障报警监控</h1>
        <!-- 添加标签切换组件 -->
        <div class="tab-container">
            <div 
                class="tab-item" 
@@ -115,12 +91,23 @@
                二线
            </div>
        </div>
        <!-- 添加调试信息 -->
        <div v-if="devices.length === 0">暂无设备数据</div>
        <div v-else>
            <p>总设备数量: {{ devices.length }}</p>
            <p>一线设备数量: {{ groupedDevices.line1.length }}</p>
            <p>二线设备数量: {{ groupedDevices.line2.length }}</p>
        </div>
        <!-- 修改生产线显示逻辑 -->
        <!-- 一线设备 -->
        <div v-show="activeTab === 'line1'" class="line-section">
            <h2 class="line-title">一线</h2>
            <div class="device-grid">
                <div v-for="device in groupedDevices.line1" :key="device.id" class="device-panel" @click="toggleAlarmInfo(device)">
                <div v-for="device in groupedDevices.line1"
                     :key="device.deviceId"
                     class="device-panel"
                     @click="toggleAlarmInfo(device)">
                    <div class="device-image">
                        <img :src="deviceIcon(device)" alt="设备图标">
                        <p v-if="device.status === 1" class="status-text normal-status">正常</p>
@@ -148,6 +135,7 @@
            </div>
        </div>
        <!-- 二线设备 -->
        <div v-show="activeTab === 'line2'" class="line-section">
            <h2 class="line-title">二线</h2>
            <div class="device-grid">
@@ -186,7 +174,7 @@
.monitoring-container {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    padding: 20px;
    max-width: 1200px;
    max-width: 1600px;
    margin: 0 auto;
    margin-bottom: 60px;
}
@@ -212,7 +200,7 @@
.device-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    gap: 15px;
    margin-bottom: 20px;
}