Selaa lähdekoodia

解决参数单位和权限问题

wukai 5 kuukautta sitten
vanhempi
commit
aada6fa43d

+ 2 - 3
src/views/dye/device/index.vue

@@ -116,11 +116,10 @@
       <!--      <el-table-column label="设备路径" align="center" prop="devicePath"/>-->
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template #default="scope">
-          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['dye:device:edit']">
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)">
             修改
           </el-button>
-          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
-                     v-hasPermi="['dye:device:remove']">删除
+          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)">删除
           </el-button>
         </template>
       </el-table-column>

+ 6 - 2
src/views/dye/energy/index.vue

@@ -68,6 +68,7 @@
 <!--      <el-table-column label="能源ID" align="center" prop="engId" />-->
       <el-table-column label="能源编码" align="center" prop="engCode" />
       <el-table-column label="能源名称" align="center" prop="engName" />
+      <el-table-column label="数据单位" align="center" prop="updatedBy" />
       <el-table-column label="产线标准" align="center" prop="lineStand">
         <template #default="scope">
           <dict-tag :options="line_stand" :value="scope.row.lineStand"/>
@@ -88,8 +89,8 @@
 <!--      <el-table-column label="备注" align="center" prop="remark" />-->
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template #default="scope">
-          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['dye:energy:edit']">修改</el-button>
-          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['dye:energy:remove']">删除</el-button>
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)">修改</el-button>
+          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)">删除</el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -111,6 +112,9 @@
         <el-form-item label="能源名称" prop="engName">
           <el-input v-model="form.engName" placeholder="请输入能源名称" />
         </el-form-item>
+        <el-form-item label="数据单位" prop="updatedBy">
+          <el-input v-model="form.updatedBy" placeholder="数据单位" />
+        </el-form-item>
         <el-form-item label="产线标准" prop="lineStand">
           <el-select v-model="form.lineStand" placeholder="请选择产线标准">
             <el-option

+ 85 - 23
src/views/dye/hour/calc.vue

@@ -140,9 +140,9 @@
           <el-table :data="rzLineList" height="400">
             <el-table-column label="小时" align="center" prop="hour" width="60"/>
             <el-table-column label="设备" align="center" prop="deviceName" width="360"/>
-            <el-table-column :label="rzLineList.length>0 ? rzLineList[0].paraName : ''" align="center">
+            <el-table-column :label="getTableColumnLabel(rzLineList)" align="center">
               <template #default="scope">
-                {{ scope.row.paraValue }}
+                {{ scope.row.paraValue }}{{ scope.row.updatedBy ? ' (' + scope.row.updatedBy + ')' : '' }}
               </template>
             </el-table-column>
           </el-table>
@@ -158,9 +158,9 @@
           <el-table :data="rzLineList1" height="400">
             <el-table-column label="小时" align="center" prop="hour" width="60"/>
             <el-table-column label="设备" align="center" prop="deviceName" width="360"/>
-            <el-table-column :label="rzLineList.length>0 ? rzLineList[0].paraName : ''" align="center">
+            <el-table-column :label="getTableColumnLabel(rzLineList1)" align="center">
               <template #default="scope">
-                {{ scope.row.paraValue }}
+                {{ scope.row.paraValue }}{{ scope.row.updatedBy ? ' (' + scope.row.updatedBy + ')' : '' }}
               </template>
             </el-table-column>
           </el-table>
@@ -185,7 +185,7 @@
           <el-card style="margin-bottom: 15px;">
             <el-table :data="minuteTableData0" height="400">
               <el-table-column prop="time" label="分钟" width="100" align="center"></el-table-column>
-              <el-table-column prop="value" :label="minuteDataLabel0" align="center"></el-table-column>
+              <el-table-column prop="value" :label="getMinuteTableColumnLabel(minuteDataLabel0, minuteDataUnit0)" align="center"></el-table-column>
             </el-table>
           </el-card>
         </el-col>
@@ -198,7 +198,7 @@
           <el-card style="margin-bottom: 15px;">
             <el-table :data="minuteTableData1" height="400">
               <el-table-column prop="time" label="分钟" width="100" align="center"></el-table-column>
-              <el-table-column prop="value" :label="minuteDataLabel1" align="center"></el-table-column>
+              <el-table-column prop="value" :label="getMinuteTableColumnLabel(minuteDataLabel1, minuteDataUnit1)" align="center"></el-table-column>
             </el-table>
           </el-card>
         </el-col>
@@ -241,11 +241,13 @@ const minuteChartRef0 = ref(null);
 let minuteChartInstance0 = null;
 const minuteTableData0 = ref([]);
 const minuteDataLabel0 = ref('');
+const minuteDataUnit0 = ref(''); // 左侧分钟级数据单位
 // 右侧分钟级数据
 const minuteChartRef1 = ref(null);
 let minuteChartInstance1 = null;
 const minuteTableData1 = ref([]);
 const minuteDataLabel1 = ref('');
+const minuteDataUnit1 = ref(''); // 右侧分钟级数据单位
 
 // 表格引用
 const tableRef0 = ref(null);
@@ -365,8 +367,6 @@ function getList() {
       // 触发设备类型变化事件,加载对应的参数
       handleEquipmentTypeChange(selectedEquipmentType.value);
     }
-
-
   });
 }
 
@@ -508,6 +508,7 @@ function updateQueryData() {
       queryPara['line'] = line;
       queryPara['deviceId'] = selectedMetrics.value[line + '_0'];
       listHour(queryPara).then(res => {
+        console.log('listHour response 0:', res); // 调试信息
         rzLineList.value = res.rows;
         nextTick(() => {
           updateChart();
@@ -517,6 +518,7 @@ function updateQueryData() {
       // 查询第二个设备的数据
       queryPara['deviceId'] = selectedMetrics.value[line + '_1'];
       listHour(queryPara).then(res => {
+        console.log('listHour response 1:', res); // 调试信息
         rzLineList1.value = res.rows;
         nextTick(() => {
           updateChart1();
@@ -531,6 +533,7 @@ function updateQueryData() {
       queryPara['line'] = selectedLines.value[0];
       queryPara['deviceId'] = selectedMetrics.value[selectedLines.value[0]];
       listHour(queryPara).then(res => {
+        console.log('listHour response 0 (2 lines):', res); // 调试信息
         rzLineList.value = res.rows;
         nextTick(() => {
           updateChart();
@@ -543,6 +546,7 @@ function updateQueryData() {
       queryPara['line'] = selectedLines.value[1];
       queryPara['deviceId'] = selectedMetrics.value[selectedLines.value[1]];
       listHour(queryPara).then(res => {
+        console.log('listHour response 1 (2 lines):', res); // 调试信息
         rzLineList1.value = res.rows;
         nextTick(() => {
           updateChart1();
@@ -597,9 +601,13 @@ function initMinuteChart0(minuteData, targetData) {
       }
     });
 
+    // 获取单位信息
+    const param = equipmentParamOptions.value.find(p => p.paraCode === selectedEquipmentParam.value);
+    const unit = param ? param.updatedBy : '';
+
     const option = {
       title: {
-        text: targetData.deviceName + ' ' + targetData.paraName,
+        text: targetData.deviceName + ' ' + targetData.paraName + (unit ? ' (' + unit + ')' : ''),
         left: 'center'
       },
       tooltip: {
@@ -608,7 +616,11 @@ function initMinuteChart0(minuteData, targetData) {
           let result = params[0].axisValue + '分<br/>';
           params.forEach(param => {
             let valueText = '';
-            valueText = param.value !== null ? param.value : '无数据';
+            if (param.value !== null) {
+              valueText = unit ? param.value + ' (' + unit + ')' : param.value;
+            } else {
+              valueText = '无数据';
+            }
             result += `<div style="display:flex;align-items:center;">
               <span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${param.color};"></span>
               ${param.seriesName}: ${valueText}
@@ -640,10 +652,10 @@ function initMinuteChart0(minuteData, targetData) {
       },
       yAxis: {
         type: 'value',
-        name: targetData.paraName
+        name: targetData.paraName + (unit ? ' (' + unit + ')' : '')
       },
       series: [{
-        name: targetData.deviceName + '-' + targetData.paraName,
+        name: targetData.deviceName + '-' + targetData.paraName + (unit ? ' (' + unit + ')' : ''),
         type: 'line',
         data: completeValues,
         smooth: true,
@@ -677,9 +689,13 @@ function initMinuteChart1(minuteData, targetData) {
       }
     });
 
+    // 获取单位信息
+    const param = equipmentParamOptions.value.find(p => p.paraCode === selectedEquipmentParam.value);
+    const unit = param ? param.updatedBy : '';
+
     const option = {
       title: {
-        text: targetData.deviceName + ' ' + targetData.paraName,
+        text: targetData.deviceName + ' ' + targetData.paraName + (unit ? ' (' + unit + ')' : ''),
         left: 'center'
       },
       tooltip: {
@@ -688,7 +704,11 @@ function initMinuteChart1(minuteData, targetData) {
           let result = params[0].axisValue + '分<br/>';
           params.forEach(param => {
             let valueText = '';
-            valueText = param.value !== null ? param.value : '无数据';
+            if (param.value !== null) {
+              valueText = unit ? param.value + ' (' + unit + ')' : param.value;
+            } else {
+              valueText = '无数据';
+            }
             result += `<div style="display:flex;align-items:center;">
               <span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${param.color};"></span>
               ${param.seriesName}: ${valueText}
@@ -720,10 +740,10 @@ function initMinuteChart1(minuteData, targetData) {
       },
       yAxis: {
         type: 'value',
-        name: targetData.paraName
+        name: targetData.paraName + (unit ? ' (' + unit + ')' : '')
       },
       series: [{
-        name: targetData.deviceName + '-' + targetData.paraName,
+        name: targetData.deviceName + '-' + targetData.paraName + (unit ? ' (' + unit + ')' : ''),
         type: 'line',
         data: completeValues,
         smooth: true,
@@ -741,9 +761,13 @@ function updateChart() {
     const hours = rzLineList.value.map(item => item.hour.toString().padStart(2, '0') + ':00');
     const values = rzLineList.value.map(item => item.paraValue);
 
+    // 获取单位信息
+    const param = equipmentParamOptions.value.find(p => p.paraCode === selectedEquipmentParam.value);
+    const unit = param ? param.updatedBy : '';
+
     const option = {
       title: {
-        text: rzLineList.value[0].deviceName + ' ' + rzLineList.value[0].paraName,
+        text: rzLineList.value[0].deviceName + ' ' + rzLineList.value[0].paraName + (unit ? ' (' + unit + ')' : ''),
         left: 'center'
       },
       tooltip: {
@@ -752,7 +776,11 @@ function updateChart() {
           let result = params[0].axisValue + '<br/>';
           params.forEach(param => {
             let valueText = '';
-            valueText = param.value !== null ? param.value : '无数据';
+            if (param.value !== null) {
+              valueText = unit ? param.value + ' (' + unit + ')' : param.value;
+            } else {
+              valueText = '无数据';
+            }
             result += `<div style="display:flex;align-items:center;">
               <span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${param.color};"></span>
               ${param.seriesName}: ${valueText}
@@ -784,7 +812,7 @@ function updateChart() {
       },
       yAxis: {
         type: 'value',
-        name: rzLineList.value[0].paraName
+        name: rzLineList.value[0].paraName + (unit ? ' (' + unit + ')' : '')
       },
       series: [{
         name: rzLineList.value[0].deviceName,
@@ -837,9 +865,13 @@ function updateChart1() {
     const hours = rzLineList1.value.map(item => item.hour.toString().padStart(2, '0') + ':00');
     const values = rzLineList1.value.map(item => item.paraValue);
 
+    // 获取单位信息
+    const param = equipmentParamOptions.value.find(p => p.paraCode === selectedEquipmentParam.value);
+    const unit = param ? param.updatedBy : '';
+
     const option = {
       title: {
-        text: rzLineList1.value[0].deviceName + ' ' + rzLineList1.value[0].paraName,
+        text: rzLineList1.value[0].deviceName + ' ' + rzLineList1.value[0].paraName + (unit ? ' (' + unit + ')' : ''),
         left: 'center'
       },
       tooltip: {
@@ -848,7 +880,11 @@ function updateChart1() {
           let result = params[0].axisValue + '<br/>';
           params.forEach(param => {
             let valueText = '';
-            valueText = param.value !== null ? param.value : '无数据';
+            if (param.value !== null) {
+              valueText = unit ? param.value + ' (' + unit + ')' : param.value;
+            } else {
+              valueText = '无数据';
+            }
             result += `<div style="display:flex;align-items:center;">
               <span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${param.color};"></span>
               ${param.seriesName}: ${valueText}
@@ -880,7 +916,7 @@ function updateChart1() {
       },
       yAxis: {
         type: 'value',
-        name: rzLineList1.value[0].paraName
+        name: rzLineList1.value[0].paraName + (unit ? ' (' + unit + ')' : '')
       },
       series: [{
         name: rzLineList1.value[0].deviceName,
@@ -967,6 +1003,10 @@ function handleChartClick(params, chartType) {
       // 设置对话框标题
       minuteDialogTitle.value = `小时 ${hour} 的分钟级数据对比`;
 
+      // 获取单位信息
+      const param = equipmentParamOptions.value.find(p => p.paraCode === selectedEquipmentParam.value);
+      const unit = param ? param.updatedBy : '';
+
       // 处理左侧设备的分钟级数据
       if (targetData0 && targetData0.paraMValue) {
         let minuteData0;
@@ -993,6 +1033,7 @@ function handleChartClick(params, chartType) {
           });
         }
         minuteDataLabel0.value = targetData0.paraName;
+        minuteDataUnit0.value = unit || ''; // 设置单位
 
         // 初始化左侧分钟级图表
         nextTick(() => {
@@ -1006,6 +1047,7 @@ function handleChartClick(params, chartType) {
         // 如果没有数据,清空左侧内容
         minuteTableData0.value = Array.from({length: 60}, (_, i) => ({time: i.toString(), value: null}));
         minuteDataLabel0.value = '';
+        minuteDataUnit0.value = ''; // 清空单位
         if (minuteChartInstance0) {
           minuteChartInstance0.dispose();
           minuteChartInstance0 = null;
@@ -1038,6 +1080,7 @@ function handleChartClick(params, chartType) {
           });
         }
         minuteDataLabel1.value = targetData1.paraName;
+        minuteDataUnit1.value = unit || ''; // 设置单位
 
         // 初始化右侧分钟级图表
         nextTick(() => {
@@ -1051,6 +1094,7 @@ function handleChartClick(params, chartType) {
         // 如果没有数据,清空右侧内容
         minuteTableData1.value = Array.from({length: 60}, (_, i) => ({time: i.toString(), value: null}));
         minuteDataLabel1.value = '';
+        minuteDataUnit1.value = ''; // 清空单位
         if (minuteChartInstance1) {
           minuteChartInstance1.dispose();
           minuteChartInstance1 = null;
@@ -1218,12 +1262,14 @@ function handleEquipmentTypeChange(val) {
   if (val) {
     // 在设备类型列表中找到当前选中的设备类型
     const selectedType = equipmentTypeList.value.find(item => item.typeId === val);
+    // 查找选中的参数信息
     if (selectedType && selectedType.dyeTypeParaList) {
       // 提取设备参数选项
       equipmentParamOptions.value = selectedType.dyeTypeParaList.map(item => {
         return {
           paraCode: item.paraCode,
-          paraName: item.paraName
+          paraName: item.paraName,
+          updatedBy: item.updatedBy // 保存单位信息
         };
       });
 
@@ -1325,4 +1371,20 @@ function handleExport() {
 }
 
 getList();
+
+const getTableColumnLabel = (list) => {
+  if (list && list.length > 0 && list[0]) {
+    const item = list[0];
+    // 从参数选项中查找对应的单位信息
+    const param = equipmentParamOptions.value.find(p => p.paraCode === selectedEquipmentParam.value);
+    const unit = param ? param.updatedBy : '';
+    return item.paraName + (unit ? ' (' + unit + ')' : '');
+  }
+  return '';
+};
+
+const getMinuteTableColumnLabel = (label, unit) => {
+  return label + (unit ? ' (' + unit + ')' : '');
+};
+
 </script>

+ 79 - 79
src/views/dye/line/calc.vue

@@ -58,20 +58,20 @@
           <el-table :data="lineDataList0" height="400">
             <el-table-column label="小时" align="center" prop="hour" width="60"/>
             <el-table-column label="产线" align="center" prop="line" width="60"/>
-            <el-table-column 
-              label="速度(米/min)" 
-              align="center" 
-              prop="speed" 
+            <el-table-column
+              label="速度(m/min)"
+              align="center"
+              prop="speed"
               v-if="selectedMetrics.includes('速度')"/>
-            <el-table-column 
-              label="电量(kW·h)" 
-              align="center" 
-              prop="energy" 
+            <el-table-column
+              label="电量(kW·h)"
+              align="center"
+              prop="energy"
               v-if="selectedMetrics.includes('电量')"/>
-            <el-table-column 
-              label="电流(A)" 
-              align="center" 
-              prop="amp" 
+            <el-table-column
+              label="电流(A)"
+              align="center"
+              prop="amp"
               v-if="selectedMetrics.includes('电流')"/>
           </el-table>
         </el-card>
@@ -86,20 +86,20 @@
           <el-table :data="lineDataList1" height="400">
             <el-table-column label="小时" align="center" prop="hour" width="60"/>
             <el-table-column label="产线" align="center" prop="line" width="60"/>
-            <el-table-column 
-              label="速度(米/min)" 
-              align="center" 
-              prop="speed" 
+            <el-table-column
+              label="速度(m/min)"
+              align="center"
+              prop="speed"
               v-if="selectedMetrics.includes('速度')"/>
-            <el-table-column 
-              label="电量(kW·h)" 
-              align="center" 
-              prop="energy" 
+            <el-table-column
+              label="电量(kW·h)"
+              align="center"
+              prop="energy"
               v-if="selectedMetrics.includes('电量')"/>
-            <el-table-column 
-              label="电流(A)" 
-              align="center" 
-              prop="amp" 
+            <el-table-column
+              label="电流(A)"
+              align="center"
+              prop="amp"
               v-if="selectedMetrics.includes('电流')"/>
           </el-table>
         </el-card>
@@ -123,20 +123,20 @@
           <el-card style="margin-bottom: 15px;">
             <el-table :data="minuteTableData0" height="400">
               <el-table-column prop="time" label="分钟" width="100" align="center"></el-table-column>
-              <el-table-column 
-                prop="speed" 
-                label="速度(米/min)" 
-                align="center" 
+              <el-table-column
+                prop="speed"
+                label="速度(m/min)"
+                align="center"
                 v-if="selectedMetrics.includes('速度')"></el-table-column>
-              <el-table-column 
-                prop="energy" 
-                label="电量(kW·h)" 
-                align="center" 
+              <el-table-column
+                prop="energy"
+                label="电量(kW·h)"
+                align="center"
                 v-if="selectedMetrics.includes('电量')"></el-table-column>
-              <el-table-column 
-                prop="amp" 
-                label="电流(A)" 
-                align="center" 
+              <el-table-column
+                prop="amp"
+                label="电流(A)"
+                align="center"
                 v-if="selectedMetrics.includes('电流')"></el-table-column>
             </el-table>
           </el-card>
@@ -150,20 +150,20 @@
           <el-card style="margin-bottom: 15px;">
             <el-table :data="minuteTableData1" height="400">
               <el-table-column prop="time" label="分钟" width="100" align="center"></el-table-column>
-              <el-table-column 
-                prop="speed" 
-                label="速度(米/min)" 
-                align="center" 
+              <el-table-column
+                prop="speed"
+                label="速度(m/min)"
+                align="center"
                 v-if="selectedMetrics.includes('速度')"></el-table-column>
-              <el-table-column 
-                prop="energy" 
-                label="电量(kW·h)" 
-                align="center" 
+              <el-table-column
+                prop="energy"
+                label="电量(kW·h)"
+                align="center"
                 v-if="selectedMetrics.includes('电量')"></el-table-column>
-              <el-table-column 
-                prop="amp" 
-                label="电流(A)" 
-                align="center" 
+              <el-table-column
+                prop="amp"
+                label="电流(A)"
+                align="center"
                 v-if="selectedMetrics.includes('电流')"></el-table-column>
             </el-table>
           </el-card>
@@ -488,7 +488,7 @@ function updateChart0() {
         params.forEach(param => {
           let valueText = '';
           if (param.seriesName.includes('速度')) {
-            valueText = param.value !== null ? param.value + ' (/min)' : '无数据';
+            valueText = param.value !== null ? param.value + ' (m/min)' : '无数据';
           } else if (param.seriesName.includes('电量')) {
             valueText = param.value !== null ? param.value + ' (kW·h)' : '无数据';
           } else if (param.seriesName.includes('电流')) {
@@ -635,7 +635,7 @@ function updateChart1() {
         params.forEach(param => {
           let valueText = '';
           if (param.seriesName.includes('速度')) {
-            valueText = param.value !== null ? param.value + ' (/min)' : '无数据';
+            valueText = param.value !== null ? param.value + ' (m/min)' : '无数据';
           } else if (param.seriesName.includes('电量')) {
             valueText = param.value !== null ? param.value + ' (kW·h)' : '无数据';
           } else if (param.seriesName.includes('电流')) {
@@ -724,7 +724,7 @@ function handleChartClick(params, chartType) {
   // 查找完整的时间信息
   let fullDate = '';
   let hour = '';
-  
+
   let targetData = null;
   if (targetDataList.length > 0) {
     // 在目标数据列表中查找匹配的数据
@@ -771,10 +771,10 @@ function handleChartClick(params, chartType) {
     // 解析速度分钟级数据
     if (selectedMetrics.value.includes('速度') && targetData.speedM) {
       try {
-        const parsedSpeedM = typeof targetData.speedM === 'string' 
-          ? JSON.parse(targetData.speedM) 
+        const parsedSpeedM = typeof targetData.speedM === 'string'
+          ? JSON.parse(targetData.speedM)
           : targetData.speedM;
-        
+
         if (Array.isArray(parsedSpeedM)) {
           parsedSpeedM.forEach(item => {
             speedData.push({
@@ -791,10 +791,10 @@ function handleChartClick(params, chartType) {
     // 解析电量分钟级数据
     if (selectedMetrics.value.includes('电量') && targetData.energyM) {
       try {
-        const parsedEnergyM = typeof targetData.energyM === 'string' 
-          ? JSON.parse(targetData.energyM) 
+        const parsedEnergyM = typeof targetData.energyM === 'string'
+          ? JSON.parse(targetData.energyM)
           : targetData.energyM;
-        
+
         if (Array.isArray(parsedEnergyM)) {
           parsedEnergyM.forEach(item => {
             energyData.push({
@@ -811,10 +811,10 @@ function handleChartClick(params, chartType) {
     // 解析电流分钟级数据
     if (selectedMetrics.value.includes('电流') && targetData.ampM) {
       try {
-        const parsedAmpM = typeof targetData.ampM === 'string' 
-          ? JSON.parse(targetData.ampM) 
+        const parsedAmpM = typeof targetData.ampM === 'string'
+          ? JSON.parse(targetData.ampM)
           : targetData.ampM;
-        
+
         if (Array.isArray(parsedAmpM)) {
           parsedAmpM.forEach(item => {
             ampData.push({
@@ -834,25 +834,25 @@ function handleChartClick(params, chartType) {
   const otherEnergyData = [];
   const otherAmpData = [];
   let otherLine = '';
-  
+
   // 确定另一个图表的数据源
   const otherDataList = chartType === 'chart0' ? lineDataList1.value : lineDataList0.value;
   if (otherDataList.length > 0) {
     otherLine = otherDataList[0].line;
-    
+
     // 查找相同时间点的数据
     const otherTargetData = otherDataList.find(item =>
       `${item.hour.toString().padStart(2, '0')}:00` === timePoint
     );
-    
+
     if (otherTargetData) {
       // 解析另一个图表的速度分钟级数据
       if (selectedMetrics.value.includes('速度') && otherTargetData.speedM) {
         try {
-          const parsedSpeedM = typeof otherTargetData.speedM === 'string' 
-            ? JSON.parse(otherTargetData.speedM) 
+          const parsedSpeedM = typeof otherTargetData.speedM === 'string'
+            ? JSON.parse(otherTargetData.speedM)
             : otherTargetData.speedM;
-          
+
           if (Array.isArray(parsedSpeedM)) {
             parsedSpeedM.forEach(item => {
               otherSpeedData.push({
@@ -869,10 +869,10 @@ function handleChartClick(params, chartType) {
       // 解析另一个图表的电量分钟级数据
       if (selectedMetrics.value.includes('电量') && otherTargetData.energyM) {
         try {
-          const parsedEnergyM = typeof otherTargetData.energyM === 'string' 
-            ? JSON.parse(otherTargetData.energyM) 
+          const parsedEnergyM = typeof otherTargetData.energyM === 'string'
+            ? JSON.parse(otherTargetData.energyM)
             : otherTargetData.energyM;
-          
+
           if (Array.isArray(parsedEnergyM)) {
             parsedEnergyM.forEach(item => {
               otherEnergyData.push({
@@ -889,10 +889,10 @@ function handleChartClick(params, chartType) {
       // 解析另一个图表的电流分钟级数据
       if (selectedMetrics.value.includes('电流') && otherTargetData.ampM) {
         try {
-          const parsedAmpM = typeof otherTargetData.ampM === 'string' 
-            ? JSON.parse(otherTargetData.ampM) 
+          const parsedAmpM = typeof otherTargetData.ampM === 'string'
+            ? JSON.parse(otherTargetData.ampM)
             : otherTargetData.ampM;
-          
+
           if (Array.isArray(parsedAmpM)) {
             parsedAmpM.forEach(item => {
               otherAmpData.push({
@@ -913,7 +913,7 @@ function handleChartClick(params, chartType) {
   minuteTableData0.value = [];
   // 右侧表格显示另一个图表的数据
   minuteTableData1.value = [];
-  
+
   for (let i = 0; i < 60; i++) {
     // 左侧表格数据(点击的图表数据)
     const rowData0 = { time: i.toString() };
@@ -930,7 +930,7 @@ function handleChartClick(params, chartType) {
       rowData0.amp = ampItem ? parseFloat(ampItem.value) : null;
     }
     minuteTableData0.value.push(rowData0);
-    
+
     // 右侧表格数据(另一个图表数据)
     const rowData1 = { time: i.toString() };
     if (selectedMetrics.value.includes('速度')) {
@@ -1034,7 +1034,7 @@ function initMinuteChart0(speedData, energyData, ampData, lineName) {
           params.forEach(param => {
             let valueText = '';
             if (param.seriesName.includes('速度')) {
-              valueText = param.value !== null ? param.value + ' (/min)' : '无数据';
+              valueText = param.value !== null ? param.value + ' (m/min)' : '无数据';
             } else if (param.seriesName.includes('电量')) {
               valueText = param.value !== null ? param.value + ' (kW·h)' : '无数据';
             } else if (param.seriesName.includes('电流')) {
@@ -1108,7 +1108,7 @@ function initMinuteChart1(speedData, energyData, ampData, lineName) {
           completeSpeedData[index] = item.value !== null ? parseFloat(item.value) : null;
         }
       });
-      
+
       series.push({
         name: '速度',
         type: 'line',
@@ -1128,7 +1128,7 @@ function initMinuteChart1(speedData, energyData, ampData, lineName) {
           completeEnergyData[index] = item.value !== null ? parseFloat(item.value) : null;
         }
       });
-      
+
       series.push({
         name: '电量',
         type: 'line',
@@ -1148,7 +1148,7 @@ function initMinuteChart1(speedData, energyData, ampData, lineName) {
           completeAmpData[index] = item.value !== null ? parseFloat(item.value) : null;
         }
       });
-      
+
       series.push({
         name: '电流',
         type: 'line',
@@ -1171,7 +1171,7 @@ function initMinuteChart1(speedData, energyData, ampData, lineName) {
           params.forEach(param => {
             let valueText = '';
             if (param.seriesName.includes('速度')) {
-              valueText = param.value !== null ? param.value + ' (/min)' : '无数据';
+              valueText = param.value !== null ? param.value + ' (m/min)' : '无数据';
             } else if (param.seriesName.includes('电量')) {
               valueText = param.value !== null ? param.value + ' (kW·h)' : '无数据';
             } else if (param.seriesName.includes('电流')) {

+ 16 - 11
src/views/dye/type/index.vue

@@ -122,6 +122,11 @@
               <el-input v-model="scope.row.paraName" placeholder="请输入参数名称" />
             </template>
           </el-table-column>
+          <el-table-column label="数据单位" prop="paraAlarm" width="150">
+            <template #default="scope">
+              <el-input v-model="scope.row.updatedBy" placeholder="数据单位" />
+            </template>
+          </el-table-column>
           <el-table-column label="参数表达式" prop="paraExp" width="300">
             <template #default="scope">
               <el-input v-model="scope.row.paraExp" type="textarea" placeholder="请输入参数表达式" />
@@ -144,17 +149,17 @@
               </el-select>
             </template>
           </el-table-column>
-          <el-table-column label="独立配置" prop="lineStand" width="150">
-            <template #default="scope">
-              <el-switch
-                  v-model="scope.row.customConfig"
-                  active-value="Y"
-                  inactive-value="N"
-                  active-text="是"
-                  inactive-text="否">
-              </el-switch>
-            </template>
-          </el-table-column>
+<!--          <el-table-column label="独立配置" prop="lineStand" width="150">-->
+<!--            <template #default="scope">-->
+<!--              <el-switch-->
+<!--                  v-model="scope.row.customConfig"-->
+<!--                  active-value="Y"-->
+<!--                  inactive-value="N"-->
+<!--                  active-text="是"-->
+<!--                  inactive-text="否">-->
+<!--              </el-switch>-->
+<!--            </template>-->
+<!--          </el-table-column>-->
         </el-table>
       </el-form>
       <template #footer>

+ 0 - 1313
src/views/dyeing/gyfx/index.vue

@@ -1,1313 +0,0 @@
-<template>
-  <div class="app-container">
-    <!-- 头部操作区域 -->
-    <el-card style="margin-bottom: 15px;">
-      <el-row :gutter="15" align="middle">
-        <!-- 时间选择 -->
-        <el-col :span="8">
-          <div style="display: flex; align-items: center; justify-content: center;">
-            <el-button icon="ArrowLeft" @click="navigateDay(-1)" size="small" style="margin-right: 10px;"></el-button>
-            <el-date-picker clearable
-                            v-model="queryParams.dataDate"
-                            type="date"
-                            value-format="YYYY-MM-DD"
-                            placeholder="请选择日期"
-                            style="width: 120px"
-                            size="small"
-                            @change="handleQuery">
-            </el-date-picker>
-            <el-button icon="ArrowRight" @click="navigateDay(1)" size="small" style="margin-left: 10px;"></el-button>
-          </div>
-        </el-col>
-
-        <!-- 设备类型和参数选择 -->
-        <el-col :span="10">
-          <div style="display: flex; align-items: center; flex-wrap: nowrap; gap: 10px;">
-            <span style="white-space: nowrap;">设备类型:</span>
-            <el-select v-model="selectedEquipmentType" placeholder="设备类型" size="small" @change="handleEquipmentTypeChange" clearable style="flex: 1; min-width: 100px;">
-              <el-option
-                v-for="item in equipmentTypeOptions"
-                :key="item.typeId"
-                :label="item.typeName"
-                :value="item.typeId">
-              </el-option>
-            </el-select>
-
-            <span style="white-space: nowrap; margin-left: 10px;">参数:</span>
-            <el-select v-model="selectedEquipmentParam" placeholder="设备参数" size="small" @change="handleEquipmentParamChange" clearable style="flex: 1; min-width: 100px;">
-              <el-option
-                v-for="item in equipmentParamOptions"
-                :key="item.paraCode"
-                :label="item.paraName"
-                :value="item.paraCode">
-              </el-option>
-            </el-select>
-          </div>
-        </el-col>
-
-        <!-- 产线选择 -->
-        <el-col :span="6">
-          <div style="display: flex; align-items: center;">
-            <span style="white-space: nowrap; margin-right: 10px;">产线:</span>
-            <el-select
-              v-model="selectedLines"
-              multiple
-              collapse-tags
-              collapse-tags-tooltip
-              placeholder="请选择产线"
-              size="small"
-              @change="handleLineSelectionChange"
-              style="flex: 1;">
-              <el-option
-                v-for="line in allLines"
-                :key="line"
-                :label="line + '#产线'"
-                :value="line">
-              </el-option>
-            </el-select>
-          </div>
-        </el-col>
-      </el-row>
-    </el-card>
-
-    <!-- 产线和设备选择详情区域 -->
-    <el-card style="margin-bottom: 15px;" v-if="selectedLines.length > 0">
-      <!-- 同产线设备对比(选择一条产线时) -->
-      <div v-if="selectedLines.length === 1" style="display: flex; align-items: center; flex-wrap: wrap; gap: 15px; padding: 10px;">
-        <span style="font-weight: bold;">同产线设备对比:</span>
-        <span>{{ selectedLines[0] }}#产线</span>
-        <el-select
-          v-model="selectedMetrics[selectedLines[0] + '_0']"
-          placeholder="设备1"
-          size="small"
-          @change="updateQueryData"
-          style="width: 180px;"
-          clearable>
-          <el-option
-            v-for="item in equipmentList[selectedLines[0]]"
-            :key="item.id"
-            :label="item.name"
-            :value="item.id">
-          </el-option>
-        </el-select>
-        <span>VS</span>
-        <el-select
-          v-model="selectedMetrics[selectedLines[0] + '_1']"
-          placeholder="设备2"
-          size="small"
-          @change="updateQueryData"
-          style="width: 180px;"
-          clearable>
-          <el-option
-            v-for="item in equipmentList[selectedLines[0]]"
-            :key="item.id"
-            :label="item.name"
-            :value="item.id">
-          </el-option>
-        </el-select>
-      </div>
-
-      <!-- 跨产线设备对比(选择两条产线时) -->
-      <div v-if="selectedLines.length === 2" style="display: flex; align-items: center; flex-wrap: wrap; gap: 15px; padding: 10px;">
-        <template v-for="(line, index) in selectedLines" :key="line">
-          <div v-if="index > 0" style="width: 1px; height: 24px; background-color: #dcdfe6; margin: 0 10px;"></div>
-          <span style="font-weight: bold;">{{ index === 0 ? '产线A' : '产线B' }}:</span>
-          <span>{{ line }}#产线</span>
-          <el-select
-            v-model="selectedMetrics[line]"
-            placeholder="请选择设备"
-            size="small"
-            @change="updateQueryData"
-            style="width: 180px;"
-            clearable>
-            <el-option
-              v-for="item in equipmentList[line]"
-              :key="item.id"
-              :label="item.name"
-              :value="item.id">
-            </el-option>
-          </el-select>
-        </template>
-      </div>
-    </el-card>
-
-    <!-- 折线图和表格左右布局 -->
-    <el-row :gutter="15">
-      <!-- 左侧折线图 -->
-      <el-col :span="12">
-        <el-card style="margin-bottom: 15px;">
-          <div ref="chartRef0" style="width: 100%; height: 400px;"></div>
-        </el-card>
-         <el-card style="margin-bottom: 15px;">
-          <el-table :data="rzLineList" height="400" :span-method="spanMethod" ref="tableRef0">
-            <el-table-column label="小时" align="center" prop="hour" width="60" />
-            <el-table-column label="设备" align="center" prop="deviceName" width="360" />
-            <el-table-column :label="rzLineList.length>0 ? rzLineList[0].paraName : ''" align="center" >
-              <template  #default="scope">
-                {{ scope.row.paraValue }}
-              </template>
-            </el-table-column>
-          </el-table>
-        </el-card>
-      </el-col>
-
-      <!-- 右侧表格 -->
-      <el-col :span="12">
-        <el-card style="margin-bottom: 15px;">
-          <div ref="chartRef1" style="width: 100%; height: 400px;"></div>
-        </el-card>
-         <el-card style="margin-bottom: 15px;">
-          <el-table :data="rzLineList1" height="400" :span-method="spanMethod" ref="tableRef1">
-            <el-table-column label="小时" align="center" prop="hour" width="60" />
-            <el-table-column label="设备" align="center" prop="deviceName" width="360" />
-            <el-table-column :label="rzLineList.length>0 ? rzLineList[0].paraName : ''" align="center" >
-              <template  #default="scope">
-                {{ scope.row.paraValue }}
-              </template>
-            </el-table-column>
-          </el-table>
-        </el-card>
-      </el-col>
-    </el-row>
-
-    <!-- 分钟级数据弹窗 -->
-    <el-dialog
-      :title="minuteDialogTitle"
-      v-model="minuteDialogVisible"
-      width="80%"
-      :before-close="handleMinuteDialogClose"
-      append-to-body
-    >
-      <el-row :gutter="15">
-        <!-- 左侧分钟级折线图 -->
-        <el-col :span="12">
-          <el-card style="margin-bottom: 15px;">
-            <div ref="minuteChartRef0" style="width: 100%; height: 400px;"></div>
-          </el-card>
-          <el-card style="margin-bottom: 15px;">
-            <el-table :data="minuteTableData0" height="400">
-              <el-table-column prop="time" label="分钟" width="100" align="center"></el-table-column>
-              <el-table-column prop="value" :label="minuteDataLabel0" align="center"></el-table-column>
-            </el-table>
-          </el-card>
-        </el-col>
-
-        <!-- 右侧分钟级折线图 -->
-        <el-col :span="12">
-          <el-card style="margin-bottom: 15px;">
-            <div ref="minuteChartRef1" style="width: 100%; height: 400px;"></div>
-          </el-card>
-          <el-card style="margin-bottom: 15px;">
-            <el-table :data="minuteTableData1" height="400">
-              <el-table-column prop="time" label="分钟" width="100" align="center"></el-table-column>
-              <el-table-column prop="value" :label="minuteDataLabel1" align="center"></el-table-column>
-            </el-table>
-          </el-card>
-        </el-col>
-      </el-row>
-    </el-dialog>
-  </div>
-</template>
-
-<script setup name="gyfx">
-import * as echarts from 'echarts';
-import { listRzLine, getRzLine, delRzLine, addRzLine, updateRzLine } from "@/api/dyeing/rzLine";
-import { listDeviceTypes } from "@/api/dyeing/gyfx"; // 添加导入listDeviceTypes接口
-import { listDevice } from "@/api/dye/device";
-import {listHour} from "@/api/dye/hour.js";
-import { ref, nextTick } from 'vue';
-import { initTableScrollSync } from "@/utils/tableSync.js"; // 引入表格滚动同步工具
-
-const { proxy } = getCurrentInstance();
-
-const rzLineList = ref([]);
-const rzLineList1 = ref([]);
-const open = 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 chartRef0 = ref(null);
-const chartRef1 = ref(null);
-let chartInstance0 = null;
-let chartInstance1 = null;
-
-// 分钟级数据相关变量
-const minuteDialogVisible = ref(false);
-const minuteDialogTitle = ref('');
-// 左侧分钟级数据
-const minuteChartRef0 = ref(null);
-let minuteChartInstance0 = null;
-const minuteTableData0 = ref([]);
-const minuteDataLabel0 = ref('');
-// 右侧分钟级数据
-const minuteChartRef1 = ref(null);
-let minuteChartInstance1 = null;
-const minuteTableData1 = ref([]);
-const minuteDataLabel1 = ref('');
-
-// 表格引用和同步状态
-const tableRef0 = ref(null);
-const tableRef1 = ref(null);
-const isSyncing = ref(false); // 防止循环触发
-let cleanups = []; // 存储清理函数
-
-const data = reactive({
-  form: {},
-  queryParams: {
-    pageNum: 1,
-    pageSize: 10000,
-    dataDate: new Date(new Date().getTime() - 24 * 60 * 60 * 1000).Format('yyyy-MM-dd'),
-    hour: null,
-    lines: null,
-    openRate: null,
-    length: null,
-    tmp: null,
-    speed: null,
-    energy: null,
-    amp: null,
-    createdBy: null,
-    createdTime: null,
-    updatedBy: null,
-    updatedTime: null,
-    remark: null
-  },
-  rules: {
-  }
-});
-
-const selectedEquipmentType = ref('');
-const selectedEquipmentParam = ref('');
-const selectedMetrics = ref({});
-const selectedLines = ref([]);  // 多条产线选择
-const equipmentList = ref({});
-const equipmentTypeList = ref([]);
-const equipmentParamOptions = ref([]);
-const equipmentTypeOptions = ref([]);
-const allLines = ref(['1', '2', '3', '4', '5', '6', '7', '8']);
-const oldSelectLines = ref([]);
-
-const { queryParams, form, rules } = toRefs(data);
-
-// 按产线分组的数据
-const groupedRzLineList = computed(() => {
-  const grouped = {};
-  rzLineList.value.forEach(item => {
-    if (!grouped[item.line]) {
-      grouped[item.line] = [];
-    }
-    grouped[item.line].push(item);
-  });
-  // 按产线编号排序
-  const sortedGrouped = {};
-  Object.keys(grouped).sort().forEach(key => {
-    sortedGrouped[key] = grouped[key];
-  });
-  return sortedGrouped;
-});
-
-// 合并单元格处理函数
-const spanMethod = ({ row, column, rowIndex, columnIndex }) => {
-  if (columnIndex === 0) { // 小时列
-    // 获取当前行小时值
-    const currentHour = row.hour;
-
-    // 计算当前小时值第一次出现的位置
-    let firstIndex = -1;
-    for (let i = 0; i < rzLineList.value.length; i++) {
-      if (rzLineList.value[i].hour === currentHour) {
-        firstIndex = i;
-        break;
-      }
-    }
-
-    // 如果当前行是该小时值第一次出现的位置
-    if (firstIndex === rowIndex) {
-      // 计算该小时值连续出现的次数
-      let spanCount = 0;
-      for (let i = firstIndex; i < rzLineList.value.length; i++) {
-        if (rzLineList.value[i].hour === currentHour) {
-          spanCount++;
-        } else {
-          break;
-        }
-      }
-      return [spanCount, 1];
-    } else {
-      // 如果不是第一次出现,隐藏该单元格
-      return [0, 0];
-    }
-  }
-  return [1, 1]; // 其他列不合并
-};
-function navigateDay(offset) {
-  const currentDate = new Date(queryParams.value.dataDate);
-  currentDate.setDate(currentDate.getDate() + offset);
-  queryParams.value.dataDate = currentDate.toISOString().split('T')[0];
-  handleQuery();
-}
-/** 查询染整线产线小时统计数据列表 */
-function getList() {
-  // 先获取设备类型列表
-  listDeviceTypes({pageSize: 10000}).then(response => {
-    equipmentTypeList.value = response.rows;
-    // 提取设备类型选项
-    equipmentTypeOptions.value = response.rows.map(item => {
-      return {
-        typeId: item.typeId,
-        typeName: item.typeName
-      };
-    });
-
-    // 默认选择第一条设备类型
-    if (response.rows.length > 0 && !selectedEquipmentType.value) {
-      selectedEquipmentType.value = response.rows[0].typeId;
-      // 触发设备类型变化事件,加载对应的参数
-      handleEquipmentTypeChange(selectedEquipmentType.value);
-    }
-    
-    // 初始化主表滚动同步
-    nextTick(() => {
-      initMainTableScrollSync();
-    });
-  });
-}
-
-function difference(arr1, arr2) {
-  const set2 = new Set(arr2);
-  return arr1.filter(item => !set2.has(item));
-}
-
-/**
- * 获取设备列表
- * @returns {void}
- */
-function getDeviceList(){
-  // 检查是否选择了产线
-  if (selectedLines.value.length === 0) {
-    proxy.$modal.msgWarning("请至少选择一条产线进行对比");
-    return;
-  }
-  if (selectedLines.value.length > 2) {
-    let tmp = difference(selectedLines.value, oldSelectLines.value);
-    selectedLines.value = selectedLines.value.filter(item => !tmp.includes(item));
-    oldSelectLines.value = JSON.parse(JSON.stringify(selectedLines.value));
-    proxy.$modal.msgWarning("最多只能选择两条产线进行对比");
-    return;
-  }
-
-  // 处理取消选择产线的情况
-  if (selectedLines.value.length < oldSelectLines.value.length) {
-    // 取消了一条产线
-    let tmp = difference(oldSelectLines.value, selectedLines.value);
-    // 清除取消产线的相关设备选择
-    if (selectedMetrics.value[tmp[0]]) {
-      selectedMetrics.value[tmp[0]] = '';
-    }
-    // 如果是单一产线情况,清除相关的设备选择
-    if (selectedMetrics.value[tmp[0] + '_0']) selectedMetrics.value[tmp[0] + '_0'] = '';
-    if (selectedMetrics.value[tmp[0] + '_1']) selectedMetrics.value[tmp[0] + '_1'] = '';
-    updateQueryData();
-  }
-
-  // 检查是否选择了设备类型和参数
-  if (!selectedEquipmentType.value) {
-    proxy.$modal.msgError("请先选择设备类型");
-    return;
-  }
-  if (!selectedEquipmentParam.value) {
-    proxy.$modal.msgError("请先选择设备参数");
-    return;
-  }
-
-  // 为所有选中的产线获取设备列表
-  selectedLines.value.forEach(line => {
-    listDevice({
-      pageSize: 10000,
-      pageNum: 1,
-      paraCode: selectedEquipmentParam.value,
-      typeId: selectedEquipmentType.value,
-      line: line
-    }).then(response => {
-      // 提取设备参数选项
-      equipmentList.value[line] = response.rows.map(item => {
-        return {
-          id: item.deviceId,
-          name: item.deviceName
-        };
-      });
-      
-      // 默认选中第一台设备
-      let needUpdateData = false;
-      if (response.rows.length > 0) {
-        // 如果是单条产线情况,设置同产线设备对比的第一台设备
-        if (selectedLines.value.length === 1) {
-          const lineKey = selectedLines.value[0];
-          if (!selectedMetrics.value[lineKey + '_0']) {
-            selectedMetrics.value[lineKey + '_0'] = response.rows[0].deviceId;
-            needUpdateData = true;
-          }
-        } 
-        // 如果是两条产线情况,设置对应产线的第一台设备
-        else if (selectedLines.value.length === 2) {
-          if (!selectedMetrics.value[line]) {
-            selectedMetrics.value[line] = response.rows[0].deviceId;
-            needUpdateData = true;
-          }
-        }
-      }
-      
-      // 如果设置了默认设备,则更新数据
-      if (needUpdateData) {
-        updateQueryData();
-      }
-    });
-  });
-
-  oldSelectLines.value = JSON.parse(JSON.stringify(selectedLines.value));
-  // 如果选择了产线,更新图表
-  if (selectedLines.value.length >= 1 && Object.keys(selectedMetrics.value).length > 0) {
-    // 检查是否所有产线都已设置设备,如果是则更新数据
-    let allLinesHaveDevices = true;
-    if (selectedLines.value.length === 1) {
-      const lineKey = selectedLines.value[0];
-      if (!selectedMetrics.value[lineKey + '_0']) {
-        allLinesHaveDevices = false;
-      }
-    } else if (selectedLines.value.length === 2) {
-      for (const line of selectedLines.value) {
-        if (!selectedMetrics.value[line]) {
-          allLinesHaveDevices = false;
-          break;
-        }
-      }
-    }
-    
-    if (allLinesHaveDevices) {
-      updateQueryData();
-    }
-  }
-}
-
-function updateQueryData() {
-  initChart();
-  rzLineList.value = [];
-  rzLineList1.value = [];
-
-  let queryPara = {
-    paraCode: selectedEquipmentParam.value,
-    typeId: selectedEquipmentType.value,
-    dataDate: queryParams.value.dataDate,
-    pageSize: 10000,
-    pageNum: 1,
-  };
-
-  // 情况1:选择了一条产线,需要比较该产线下的两个设备
-  if (selectedLines.value.length == 1) {
-    const line = selectedLines.value[0];
-    // 检查是否选择了两个设备进行对比
-    if (selectedMetrics.value[line + '_0'] && selectedMetrics.value[line + '_1']) {
-      // 查询第一个设备的数据
-      queryPara['line'] = line;
-      queryPara['deviceId'] = selectedMetrics.value[line + '_0'];
-      listHour(queryPara).then(res => {
-        rzLineList.value = res.rows;
-        nextTick(() => {
-          updateChart();
-        });
-      });
-
-      // 查询第二个设备的数据
-      queryPara['deviceId'] = selectedMetrics.value[line + '_1'];
-      listHour(queryPara).then(res => {
-        rzLineList1.value = res.rows;
-        nextTick(() => {
-          updateChart1();
-        });
-      });
-    }
-  }
-  // 情况2:选择了两条产线,每条产线选择一个设备进行对比
-  else if (selectedLines.value.length == 2) {
-    // 查询第一条产线设备的数据
-    if (selectedMetrics.value[selectedLines.value[0]]) {
-      queryPara['line'] = selectedLines.value[0];
-      queryPara['deviceId'] = selectedMetrics.value[selectedLines.value[0]];
-      listHour(queryPara).then(res => {
-        rzLineList.value = res.rows;
-        nextTick(() => {
-          updateChart();
-        });
-      });
-    }
-
-    // 查询第二条产线设备的数据
-    if (selectedMetrics.value[selectedLines.value[1]]) {
-      queryPara['line'] = selectedLines.value[1];
-      queryPara['deviceId'] = selectedMetrics.value[selectedLines.value[1]];
-      listHour(queryPara).then(res => {
-        rzLineList1.value = res.rows;
-        nextTick(() => {
-          updateChart1();
-        });
-      });
-    }
-  }
-}
-
-// 初始化图表
-function initChart() {
-  if (chartInstance0) {
-    chartInstance0.dispose();
-  }
-  if (chartInstance1) {
-    chartInstance1.dispose();
-  }
-  if (chartRef0.value) {
-    chartInstance0 = echarts.init(chartRef0.value);
-  }
-  if (chartRef1.value) {
-    chartInstance1 = echarts.init(chartRef1.value);
-  }
-  //建立图表联动
-  if (chartInstance0 && chartInstance1) {
-    echarts.connect([
-      chartInstance0,
-      chartInstance1,
-    ]);
-  }
-}
-
-// 初始化分钟级数据图表
-function initMinuteChart0(minuteData, targetData) {
-  if (minuteChartInstance0) {
-    minuteChartInstance0.dispose();
-  }
-
-  if (minuteChartRef0.value) {
-    minuteChartInstance0 = echarts.init(minuteChartRef0.value);
-
-    // 准备分钟级数据
-    const timePoints = minuteData.map(item => item.time);
-    const values = minuteData.map(item => item.value);
-
-    const option = {
-      title: {
-        text: targetData.deviceName + ' ' + targetData.paraName,
-        left: 'center'
-      },
-      tooltip: {
-        trigger: 'axis',
-        formatter: function (params) {
-          let result = params[0].axisValue + '分<br/>';
-          params.forEach(param => {
-            let valueText = '';
-            valueText = param.value !== null ? param.value : '无数据';
-            result += `<div style="display:flex;align-items:center;">
-              <span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${param.color};"></span>
-              ${param.seriesName}: ${valueText}
-            </div>`;
-          });
-          return result;
-        }
-      },
-      legend:{
-        top: 40 ,
-        left: 'center',
-        textStyle: {
-          fontSize: 10
-        },
-        itemWidth: 10,
-        itemHeight: 10
-      },
-      grid: {
-        left: '3%',
-        right: '4%',
-        top: '25%',
-        bottom: 20,
-        containLabel: true
-      },
-      xAxis: {
-        type: 'category',
-        boundaryGap: false,
-        data: timePoints
-      },
-      yAxis: {
-        type: 'value',
-        name: targetData.paraName
-      },
-      series: [{
-        name: targetData.deviceName + '-' + targetData.paraName,
-        type: 'line',
-        data: values,
-        smooth: true,
-        showSymbol: false
-      }]
-    };
-
-    minuteChartInstance0.setOption(option);
-  }
-}
-
-// 初始化分钟级数据图表1
-function initMinuteChart1(minuteData, targetData) {
-  if (minuteChartInstance1) {
-    minuteChartInstance1.dispose();
-  }
-
-  if (minuteChartRef1.value) {
-    minuteChartInstance1 = echarts.init(minuteChartRef1.value);
-
-    // 准备分钟级数据
-    const timePoints = minuteData.map(item => item.time);
-    const values = minuteData.map(item => item.value);
-
-    const option = {
-      title: {
-        text: targetData.deviceName + ' ' + targetData.paraName,
-        left: 'center'
-      },
-      tooltip: {
-        trigger: 'axis',
-        formatter: function (params) {
-          let result = params[0].axisValue + '分<br/>';
-          params.forEach(param => {
-            let valueText = '';
-            valueText = param.value !== null ? param.value : '无数据';
-            result += `<div style="display:flex;align-items:center;">
-              <span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${param.color};"></span>
-              ${param.seriesName}: ${valueText}
-            </div>`;
-          });
-          return result;
-        }
-      },
-      legend:{
-        top: 40 ,
-        left: 'center',
-        textStyle: {
-          fontSize: 10
-        },
-        itemWidth: 10,
-        itemHeight: 10
-      },
-      grid: {
-        left: '3%',
-        right: '4%',
-        top: '25%',
-        bottom: 20,
-        containLabel: true
-      },
-      xAxis: {
-        type: 'category',
-        boundaryGap: false,
-        data: timePoints
-      },
-      yAxis: {
-        type: 'value',
-        name: targetData.paraName
-      },
-      series: [{
-        name: targetData.deviceName + '-' + targetData.paraName,
-        type: 'line',
-        data: values,
-        smooth: true,
-        showSymbol: false
-      }]
-    };
-
-    minuteChartInstance1.setOption(option);
-  }
-}
-
-// 更新图表0
-function updateChart() {
-  if (chartInstance0 && rzLineList.value.length > 0) {
-    const hours = rzLineList.value.map(item => item.hour.toString().padStart(2, '0') + ':00');
-    const values = rzLineList.value.map(item => item.paraValue);
-
-    const option = {
-      title: {
-        text: rzLineList.value[0].deviceName + ' ' + rzLineList.value[0].paraName,
-        left: 'center'
-      },
-      tooltip: {
-        trigger: 'axis',
-        formatter: function (params) {
-          let result = params[0].axisValue + '<br/>';
-          params.forEach(param => {
-            let valueText = '';
-            valueText = param.value !== null ? param.value : '无数据';
-            result += `<div style="display:flex;align-items:center;">
-              <span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${param.color};"></span>
-              ${param.seriesName}: ${valueText}
-            </div>`;
-          });
-          return result;
-        }
-      },
-      legend:{
-        top: 40 ,
-        left: 'center',
-        textStyle: {
-          fontSize: 10
-        },
-        itemWidth: 10,
-        itemHeight: 10
-      },
-      grid: {
-        left: '3%',
-        right: '4%',
-        top: '25%',
-        bottom: 20,
-        containLabel: true
-      },
-      xAxis: {
-        type: 'category',
-        boundaryGap: false,
-        data: hours
-      },
-      yAxis: {
-        type: 'value',
-        name: rzLineList.value[0].paraName
-      },
-      series: [{
-        name: rzLineList.value[0].deviceName,
-        type: 'line',
-        data: values,
-        smooth: true,
-        showSymbol: false
-      }]
-    };
-
-    chartInstance0.setOption(option);
-
-    // 先移除之前的点击事件监听,避免重复绑定
-    chartInstance0.off('click');
-    // 添加点击事件监听
-    chartInstance0.on('click', (params) => {
-      handleChartClick(params, 'chart0');
-    });
-  } else if (chartInstance0) {
-    // 如果没有数据,清空图表
-    chartInstance0.setOption({
-      title: {
-        text: '暂无数据',
-        left: 'center',
-        top: 'center'
-      },
-      xAxis: {
-        type: 'category',
-        data: []
-      },
-      yAxis: {
-        type: 'value'
-      },
-      series: []
-    });
-
-    // 移除点击事件监听
-    chartInstance0.off('click');
-  }
-  
-  // 更新数据后重新初始化表格滚动同步
-  nextTick(() * {
-    initMainTableScrollSync();
-  });
-}
-
-// 更新图表1
-function updateChart1() {
-  if (chartInstance1 && rzLineList1.value.length > 0) {
-    const hours = rzLineList1.value.map(item => item.hour.toString().padStart(2, '0') + ':00');
-    const values = rzLineList1.value.map(item => item.paraValue);
-
-    const option = {
-      title: {
-        text: rzLineList1.value[0].deviceName + ' ' + rzLineList1.value[0].paraName,
-        left: 'center'
-      },
-      tooltip: {
-        trigger: 'axis',
-        formatter: function (params) {
-          let result = params[0].axisValue + '<br/>';
-          params.forEach(param => {
-            let valueText = '';
-            valueText = param.value !== null ? param.value : '无数据';
-            result += `<div style="display:flex;align-items:center;">
-              <span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${param.color};"></span>
-              ${param.seriesName}: ${valueText}
-            </div>`;
-          });
-          return result;
-        }
-      },
-      legend:{
-        top: 40 ,
-        left: 'center',
-        textStyle: {
-          fontSize: 10
-        },
-        itemWidth: 10,
-        itemHeight: 10
-      },
-      grid: {
-        left: '3%',
-        right: '4%',
-        top: '25%',
-        bottom: 20,
-        containLabel: true
-      },
-      xAxis: {
-        type: 'category',
-        boundaryGap: false,
-        data: hours
-      },
-      yAxis: {
-        type: 'value',
-        name: rzLineList1.value[0].paraName
-      },
-      series: [{
-        name: rzLineList1.value[0].deviceName,
-        type: 'line',
-        data: values,
-        smooth: true,
-        showSymbol: false
-      }]
-    };
-
-    chartInstance1.setOption(option);
-
-    // 先移除之前的点击事件监听,避免重复绑定
-    chartInstance1.off('click');
-    // 添加点击事件监听
-    chartInstance1.on('click', (params) => {
-      handleChartClick(params, 'chart1');
-    });
-  } else if (chartInstance1) {
-    // 如果没有数据,清空图表
-    chartInstance1.setOption({
-      title: {
-        text: '暂无数据',
-        left: 'center',
-        top: 'center'
-      },
-      xAxis: {
-        type: 'category',
-        data: []
-      },
-      yAxis: {
-        type: 'value'
-      },
-      series: []
-    });
-
-    // 移除点击事件监听
-    chartInstance1.off('click');
-  }
-  
-  // 更新数据后重新初始化表格滚动同步
-  nextTick(() => {
-    initMainTableScrollSync();
-  });
-}
-
-// 图表点击事件处理函数
-function handleChartClick(params, chartType) {
-  // 获取点击的小时
-  const hour = params.name;
-
-  // 查找对应小时的数据(无论点击的是哪个图表,都要显示两个设备的数据)
-  // 尝试多种匹配方式来查找数据
-  let targetData0 = null;
-  let targetData1 = null;
-
-  // 对于第一个数据集
-  for (let i = 0; i < rzLineList.value.length; i++) {
-    const item = rzLineList.value[i];
-    const itemHour = item.hour.toString().padStart(2, '0');
-    const clickedHour = hour.replace(':00', ''); // 去掉可能的 ':00' 后缀
-
-    if (itemHour === clickedHour) {
-      targetData0 = item;
-      break;
-    }
-  }
-
-  // 对于第二个数据集
-  for (let i = 0; i < rzLineList1.value.length; i++) {
-    const item = rzLineList1.value[i];
-    const itemHour = item.hour.toString().padStart(2, '0');
-    const clickedHour = hour.replace(':00', ''); // 去掉可能的 ':00' 后缀
-
-    if (itemHour === clickedHour) {
-      targetData1 = item;
-      break;
-    }
-  }
-
-  // 检查两个设备是否都有对应小时的数据
-  if ((targetData0 && targetData0.paraMValue) || (targetData1 && targetData1.paraMValue)) {
-    try {
-      // 设置对话框标题
-      minuteDialogTitle.value = `小时 ${hour} 的分钟级数据对比`;
-
-      // 处理左侧设备的分钟级数据
-      if (targetData0 && targetData0.paraMValue) {
-        let minuteData0;
-        try {
-          minuteData0 = typeof targetData0.paraMValue === 'string'
-            ? JSON.parse(targetData0.paraMValue)
-            : targetData0.paraMValue;
-        } catch (e) {
-          // 尝试其他格式
-          if (Array.isArray(targetData0.paraMValue)) {
-            minuteData0 = targetData0.paraMValue;
-          } else {
-            minuteData0 = [];
-          }
-        }
-
-        // 设置左侧分钟级数据
-        minuteTableData0.value = minuteData0.map(item => ({
-          time: item.time,
-          value: item.value
-        }));
-        minuteDataLabel0.value = targetData0.paraName;
-
-        // 初始化左侧分钟级图表
-        nextTick(() => {
-          initMinuteChart0(minuteData0, targetData0);
-          // 建立分钟级图表联动
-          if (minuteChartInstance0 && minuteChartInstance1) {
-            echarts.connect([minuteChartInstance0, minuteChartInstance1]);
-          }
-          
-          // 初始化表格滚动同步
-          initMainTableScrollSync();
-        });
-      } else {
-        // 如果没有数据,清空左侧内容
-        minuteTableData0.value = [];
-        minuteDataLabel0.value = '';
-        if (minuteChartInstance0) {
-          minuteChartInstance0.dispose();
-          minuteChartInstance0 = null;
-        }
-      }
-
-      // 处理右侧设备的分钟级数据
-      if (targetData1 && targetData1.paraMValue) {
-        let minuteData1;
-        try {
-          minuteData1 = typeof targetData1.paraMValue === 'string'
-            ? JSON.parse(targetData1.paraMValue)
-            : targetData1.paraMValue;
-        } catch (e) {
-          // 尝试其他格式
-          if (Array.isArray(targetData1.paraMValue)) {
-            minuteData1 = targetData1.paraMValue;
-          } else {
-            minuteData1 = [];
-          }
-        }
-
-        // 设置右侧分钟级数据
-        minuteTableData1.value = minuteData1.map(item => ({
-          time: item.time,
-          value: item.value
-        }));
-        minuteDataLabel1.value = targetData1.paraName;
-
-        // 初始化右侧分钟级图表
-        nextTick(() => {
-          initMinuteChart1(minuteData1, targetData1);
-          // 建立分钟级图表联动
-          if (minuteChartInstance0 && minuteChartInstance1) {
-            echarts.connect([minuteChartInstance0, minuteChartInstance1]);
-          }
-          
-          // 初始化表格滚动同步
-          initMainTableScrollSync();
-        });
-      } else {
-        // 如果没有数据,清空右侧内容
-        minuteTableData1.value = [];
-        minuteDataLabel1.value = '';
-        if (minuteChartInstance1) {
-          minuteChartInstance1.dispose();
-          minuteChartInstance1 = null;
-        }
-      }
-
-      // 显示对话框
-      showMinuteDialog();
-    } catch (error) {
-      proxy.$modal.msgError("数据解析失败");
-    }
-  } else {
-    // 显示提示信息
-    proxy.$modal.msgWarning("该小时没有分钟级数据");
-  }
-}
-
-// 窗口大小改变时重置图表大小
-function resizeChart() {
-  if (chartInstance0) {
-    chartInstance0.resize();
-  }
-  if (chartInstance1) {
-    chartInstance1.resize();
-  }
-  if (minuteChartInstance0) {
-    minuteChartInstance0.resize();
-  }
-  if (minuteChartInstance1) {
-    minuteChartInstance1.resize();
-  }
-}
-
-// 关闭分钟级数据弹窗
-function handleMinuteDialogClose() {
-  minuteDialogVisible.value = false;
-}
-
-// 显示分钟级数据弹窗
-function showMinuteDialog() {
-  minuteDialogVisible.value = true;
-}
-
-// 初始化主表表格滚动同步
-function initMainTableScrollSync() {
-  // 清理之前的事件监听器
-  cleanups.forEach(cleanup => cleanup());
-  cleanups = [];
-  
-  // 初始化新的滚动同步
-  const newCleanups = initTableScrollSync(tableRef0, tableRef1, isSyncing);
-  cleanups = newCleanups;
-}
-
-onMounted(() => {
-  initChart();
-  window.addEventListener('resize', resizeChart);
-
-  // 默认选择所有产线
-  //selectedLines.value = [...allLines.value];
-
-  // 初始加载数据
-  getList();
-
-  // 添加一个微任务确保图表正确初始化
-  nextTick(() => {
-    if (!chartInstance0 && chartRef0.value) {
-      chartInstance0 = echarts.init(chartRef0.value);
-    }
-    if (!chartInstance1 && chartRef1.value) {
-      chartInstance1 = echarts.init(chartRef1.value);
-    }
-    
-    // 初始化主表滚动同步
-    initMainTableScrollSync();
-  });
-});
-
-onUnmounted(() => {
-  window.removeEventListener('resize', resizeChart);
-  if (chartInstance0) {
-    chartInstance0.dispose();
-  }
-  if (chartInstance1) {
-    chartInstance1.dispose();
-  }
-  if (minuteChartInstance0) {
-    minuteChartInstance0.dispose();
-  }
-  if (minuteChartInstance1) {
-    minuteChartInstance1.dispose();
-  }
-  
-  // 清理表格滚动同步事件监听器
-  cleanups.forEach(cleanup => cleanup());
-});
-
-onActivated(() => {
-  resizeChart();
-});
-
-// 取消按钮
-function cancel() {
-  open.value = false;
-  reset();
-}
-
-// 表单重置
-function reset() {
-  form.value = {
-    id: null,
-    dataDate: null,
-    hour: null,
-    line: null,
-    openRate: null,
-    length: null,
-    tmp: null,
-    speed: null,
-    energy: null,
-    amp: null,
-    createdBy: null,
-    createdTime: null,
-    updatedBy: null,
-    updatedTime: null,
-    remark: null
-  };
-  proxy.resetForm("rzLineRef");
-}
-
-/** 搜索按钮操作 */
-function handleQuery() {
-  queryParams.value.pageNum = 1;
-  // 检查查询条件
-  if (!queryParams.value.dataDate) {
-    proxy.$modal.msgWarning("请选择日期");
-    return;
-  }
-  // 不要重置已选择的产线和设备,仅更新数据
-  updateQueryData();
-}
-
-/** 重置按钮操作 */
-function resetQuery() {
-  proxy.resetForm("queryRef");
-  // 设置默认日期为当前日期
-  const now = new Date();
-  const year = now.getFullYear();
-  const month = (now.getMonth() + 1).toString().padStart(2, '0');
-  const day = now.getDate().toString().padStart(2, '0');
-  queryParams.value.dataDate = `${year}-${month}-${day}`;
-
-  // 重置产线和设备选择
-  selectedLines.value = [];
-  selectedMetrics.value = {};
-  equipmentList.value = {};
-
-  handleQuery();
-}
-// 处理设备类型变化
-function handleEquipmentTypeChange(val) {
-  // 清空已选的设备参数
-  selectedEquipmentParam.value = '';
-
-  // 如果有选择设备类型,则更新设备参数选项
-  if (val) {
-    // 在设备类型列表中找到当前选中的设备类型
-    const selectedType = equipmentTypeList.value.find(item => item.typeId === val);
-    if (selectedType && selectedType.dyeTypeParaList) {
-      // 提取设备参数选项
-      equipmentParamOptions.value = selectedType.dyeTypeParaList.map(item => {
-        return {
-          paraCode: item.paraCode,
-          paraName: item.paraName
-        };
-      });
-
-      // 默认选择第一条设备参数
-      if (selectedType.dyeTypeParaList.length > 0 && !selectedEquipmentParam.value) {
-        selectedEquipmentParam.value = selectedType.dyeTypeParaList[0].paraCode;
-        // 触发设备参数变化事件
-        handleEquipmentParamChange();
-      }
-    } else {
-      equipmentParamOptions.value = [];
-    }
-  } else {
-    // 如果没有选择设备类型,清空设备参数选项
-    equipmentParamOptions.value = [];
-  }
-}
-
-// 处理设备参数变化
-function handleEquipmentParamChange() {
-  // 清空设备列表和已选择的设备
-  equipmentList.value = {};
-  selectedMetrics.value = {};
-  
-  // 获取新设备列表
-  getDeviceList();
-}
-
-// 处理产线选择变化
-function handleLineSelectionChange(val) {
-  if (val.length > 2) {
-    // 限制最多选择两条产线
-    selectedLines.value = val.slice(0, 2);
-    proxy.$modal.msgWarning("最多只能选择两条产线进行对比");
-  }
-  // 当取消选择所有产线时,清空相关设备选择
-  if (val.length === 0) {
-    selectedMetrics.value = {};
-  }
-  getDeviceList();
-}
-
-/** 新增按钮操作 */
-function handleAdd() {
-  reset();
-  open.value = true;
-  title.value = "添加染整线产线小时统计数据";
-}
-
-/** 修改按钮操作 */
-function handleUpdate(row) {
-  reset();
-  const _id = row.id || ids.value
-  getRzLine(_id).then(response => {
-    form.value = response.data;
-    open.value = true;
-    title.value = "修改染整线产线小时统计数据";
-  });
-}
-
-/** 提交按钮 */
-function submitForm() {
-  proxy.$refs["rzLineRef"].validate(valid => {
-    if (valid) {
-      if (form.value.id != null) {
-        updateRzLine(form.value).then(response => {
-          proxy.$modal.msgSuccess("修改成功");
-          open.value = false;
-          getList();
-        });
-      } else {
-        addRzLine(form.value).then(response => {
-          proxy.$modal.msgSuccess("新增成功");
-          open.value = false;
-          getList();
-        });
-      }
-    }
-  });
-}
-
-/** 删除按钮操作 */
-function handleDelete(row) {
-  const _ids = row.id || ids.value;
-  proxy.$modal.confirm('是否确认删除染整线产线小时统计数据编号为"' + _ids + '"的数据项?').then(function() {
-    return delRzLine(_ids);
-  }).then(() => {
-    getList();
-    proxy.$modal.msgSuccess("删除成功");
-  }).catch(() => {});
-}
-
-/** 导出按钮操作 */
-function handleExport() {
-  proxy.download('dyeing/rzLine/export', {
-    ...queryParams.value
-  }, `rzLine_${new Date().getTime()}.xlsx`)
-}
-
-getList();
-</script>