Przeglądaj źródła

我觉得可以了

wukai 3 tygodni temu
rodzic
commit
9e86205da4
2 zmienionych plików z 191 dodań i 64 usunięć
  1. 9 0
      src/api/dye/hour.js
  2. 182 64
      src/views/dye/hour/calc.vue

+ 9 - 0
src/api/dye/hour.js

@@ -9,6 +9,15 @@ export function listHour(query) {
     })
 }
 
+// 查询小时统计数据列表
+export function calcHour(query) {
+    return request({
+        url: '/dye/hour/calc',
+        method: 'get',
+        params: query
+    })
+}
+
 // 查询小时统计数据详细
 export function getHour(chId) {
     return request({

+ 182 - 64
src/views/dye/hour/calc.vue

@@ -56,7 +56,7 @@
                 placeholder="请选择产线(最多2条)"
                 style="width: 180px;"
                 @change="handleLineSelectionChange"
-                >
+            >
               <el-option
                   v-for="line in allLines"
                   :key="line"
@@ -128,13 +128,58 @@
         </el-col>
       </el-row>
     </el-card>
+    <!-- 显著性分析结果展示区域 -->
+    <el-card style="margin-bottom: 15px;" v-if="significantData && significantData.length > 0">
+      <div slot="header">
+        <span>Mann-Whitney U检验结果</span>
+      </div>
+      
+      <!-- 折叠面板 -->
+      <el-collapse v-model="activeCollapseNames">
+        <el-collapse-item name="significance-results">
+          <template #title>
+            <span style="font-weight: bold;">显著性分析摘要</span>
+            <el-tag size="mini" style="margin-left: 10px;">{{ significantData.length }} 个显著差异</el-tag>
+          </template>
+          
+          <!-- 统计说明 -->
+          <el-alert
+            title="统计说明"
+            description="P值:表示两个设备参数分布差异的显著性概率,P<0.05认为差异显著;U值:Mann-Whitney U检验统计量,反映两组数据的秩和差异"
+            type="info"
+            show-icon
+            :closable="false"
+            style="margin-bottom: 10px;"
+          />
+          
+          <!-- 详细表格 -->
+          <el-table :data="significantData" height="300" style="width: 100%" stripe>
+            <el-table-column prop="typeName" label="设备类型"></el-table-column>
+            <el-table-column prop="paraName" label="参数名称"></el-table-column>
+            <el-table-column prop="deviceName1" label="设备1"></el-table-column>
+            <el-table-column prop="deviceName2" label="设备2"></el-table-column>
+            <el-table-column prop="result" label="显著性结果" width="100">
+              <template #default="scope">
+                <el-tag :type="scope.row.result === '显著' ? 'danger' : 'success'">{{ scope.row.result }}</el-tag>
+              </template>
+            </el-table-column>
+            <el-table-column label="P值" width="100">
+              <template #default="scope">
+                {{ scope.row.pvalue ? scope.row.pvalue.toFixed(6) : '' }}
+              </template>
+            </el-table-column>
+            <el-table-column prop="uvalue" label="U值" width="100"></el-table-column>
+          </el-table>
+        </el-collapse-item>
+      </el-collapse>
+    </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 style="margin-bottom: 15px; height: 350px;">
+          <div ref="chartRef0" style="width: 100%; height: 320px;"></div>
         </el-card>
         <el-card style="margin-bottom: 15px;">
           <el-table :data="rzLineList" height="400">
@@ -151,8 +196,8 @@
 
       <!-- 右侧表格 -->
       <el-col :span="12">
-        <el-card style="margin-bottom: 15px;">
-          <div ref="chartRef1" style="width: 100%; height: 400px;"></div>
+        <el-card style="margin-bottom: 15px; height: 350px;">
+          <div ref="chartRef1" style="width: 100%; height: 320px;"></div>
         </el-card>
         <el-card style="margin-bottom: 15px;">
           <el-table :data="rzLineList1" height="400">
@@ -168,7 +213,7 @@
       </el-col>
     </el-row>
 
-        <!-- 分钟级数据弹窗 -->
+    <!-- 分钟级数据弹窗 -->
     <el-dialog
         :title="minuteDialogTitle"
         v-model="minuteDialogVisible"
@@ -185,7 +230,8 @@
           <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="getMinuteTableColumnLabel(minuteDataLabel0, minuteDataUnit0)" 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 +244,8 @@
           <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="getMinuteTableColumnLabel(minuteDataLabel1, minuteDataUnit1)" 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>
@@ -212,7 +259,7 @@ import * as echarts from 'echarts';
 import {addRzLine, delRzLine, getRzLine, 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 {calcHour, listHour} from "@/api/dye/hour.js";
 import {nextTick, ref} from 'vue';
 
 
@@ -253,6 +300,10 @@ const minuteDataUnit1 = ref(''); // 右侧分钟级数据单位
 const tableRef0 = ref(null);
 const tableRef1 = ref(null);
 
+// 显著性分析相关变量
+const significantData = ref([]); // 存储显著性分析结果(仅显著的)
+const activeCollapseNames = ref([]); // 控制折叠面板展开状态
+
 const data = reactive({
   form: {},
   queryParams: {
@@ -279,7 +330,8 @@ const data = reactive({
 const selectedEquipmentType = ref('');
 const selectedEquipmentParam = ref('');
 const selectedMetrics = ref({});
-const selectedLines = ref(['5', '6']); // 默认选中5号和6号产线
+// 修改默认选中的产线为空数组
+const selectedLines = ref([]);
 const equipmentList = ref({});
 const equipmentTypeList = ref([]);
 const equipmentParamOptions = ref([]);
@@ -289,6 +341,11 @@ const oldSelectLines = ref([]);
 
 const {queryParams, form, rules} = toRefs(data);
 
+// 显示详情弹窗
+/* function showDetailDialog() {
+  detailDialogVisible.value = true;
+} */
+
 // 按产线分组的数据
 const groupedRzLineList = computed(() => {
   const grouped = {};
@@ -350,6 +407,9 @@ function navigateDay(offset) {
 
 /** 查询染整线产线小时统计数据列表 */
 function getList() {
+  // 初始化标记设为false
+  window.isInitialized = false;
+
   // 先获取设备类型列表
   listDeviceTypes({pageSize: 10000}).then(response => {
     equipmentTypeList.value = response.rows;
@@ -366,10 +426,17 @@ function getList() {
       selectedEquipmentType.value = response.rows[0].typeId;
       // 触发设备类型变化事件,加载对应的参数
       handleEquipmentTypeChange(selectedEquipmentType.value);
-     } else if (selectedEquipmentType.value) {
+    } else if (selectedEquipmentType.value) {
       // 如果已有设备类型,直接触发参数变化
       handleEquipmentTypeChange(selectedEquipmentType.value);
     }
+
+    // 在设备类型和参数加载完成后,默认选择5号和6号产线
+    if (selectedLines.value.length === 0) {
+      selectedLines.value = ['5', '6'];
+      // 获取设备列表
+      getDeviceList();
+    }
   });
 }
 
@@ -385,10 +452,17 @@ function difference(arr1, arr2) {
 function getDeviceList() {
   // 检查是否选择了产线
   if (selectedLines.value.length === 0) {
-    proxy.$modal.msgWarning("请至少选择一条产线进行对比");
+    // 初始化时不要弹出提示,只有用户主动操作时才提示
+    // 通过检查是否已完成初始化来判断是否是用户主动操作
+    // isInitialized标志表示是否已完成初始化过程
+    if (window.isInitialized) {
+      proxy.$modal.msgWarning("请至少选择一条产线进行对比");
+    }
     return;
   }
-  if (selectedLines.value.length > 2) {
+
+  // 只有在非初始化状态下才检查产线数量限制
+  if (window.isInitialized && 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));
@@ -396,8 +470,8 @@ function getDeviceList() {
     return;
   }
 
-  // 处理取消选择产线的情况
-  if (selectedLines.value.length < oldSelectLines.value.length) {
+  // 处理取消选择产线的情况(仅在非初始化状态下)
+  if (window.isInitialized && selectedLines.value.length < oldSelectLines.value.length) {
     // 取消了一条产线
     let tmp = difference(oldSelectLines.value, selectedLines.value);
     // 清除取消产线的相关设备选择
@@ -411,13 +485,13 @@ function getDeviceList() {
     return;
   }
 
-  // 检查是否选择了设备类型和参数
+  // 检查是否选择了设备类型和参数(即使在初始化过程中也需要检查)
   if (!selectedEquipmentType.value) {
-    proxy.$modal.msgError("请先选择设备类型");
+    // 初始化过程中不提示错误
     return;
   }
   if (!selectedEquipmentParam.value) {
-    proxy.$modal.msgError("请先选择设备参数");
+    // 初始化过程中不提示错误
     return;
   }
 
@@ -461,17 +535,17 @@ function getDeviceList() {
           }
         }
       }
-      
+
       loadedCount++;
-      
+
       // 只有当所有设备列表都加载完成后再决定是否更新数据
       if (loadedCount === totalLines) {
         oldSelectLines.value = JSON.parse(JSON.stringify(selectedLines.value));
-        
+
         // 如果需要更新数据或者已经选择了产线和设备,检查是否所有产线都已设置设备
         if (needUpdateData || (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']) {
@@ -487,20 +561,28 @@ function getDeviceList() {
           }
 
           // 如果所有产线都已设置设备,则更新数据
+          // 只有在所有线路都有设备时才更新数据,避免重复调用
           if (allLinesHaveDevices) {
             // 防止重复调用
             clearTimeout(window.updateQueryDataTimer);
             window.updateQueryDataTimer = setTimeout(() => {
               updateQueryData();
             }, 100);
-          } else if (needUpdateData) {
-            // 如果有新设置的设备,也更新数据
+          }
+          // 当needUpdateData为true时才调用updateQueryData
+          else if (needUpdateData) {
+            // 防止重复调用
             clearTimeout(window.updateQueryDataTimer);
             window.updateQueryDataTimer = setTimeout(() => {
               updateQueryData();
             }, 100);
           }
         }
+
+        // 标记初始化完成
+        if (!window.isInitialized) {
+          window.isInitialized = true;
+        }
       }
     }).catch(error => {
       loadedCount++;
@@ -510,6 +592,20 @@ function getDeviceList() {
 }
 
 function updateQueryData() {
+  // 清除之前的定时器,防止重复调用
+  if (window.updateQueryDataTimer) {
+    clearTimeout(window.updateQueryDataTimer);
+    window.updateQueryDataTimer = null;
+  }
+  let calcPara = {
+    date: queryParams.value.workDay,
+    line1: selectedLines.value[0],
+    line2: selectedLines.value[1]
+  }
+  calcHour(calcPara).then(res => {
+    // 处理显著性分析结果(后台已过滤,全是显著结果)
+    significantData.value = res.data || [];
+  });
   initChart();
   rzLineList.value = [];
   rzLineList1.value = [];
@@ -550,7 +646,7 @@ function updateQueryData() {
   // 情况2:选择了两条产线,每条产线选择一个设备进行对比
   else if (selectedLines.value.length == 2) {
     let loadedCount = 0;
-    
+
     // 查询第一条产线设备的数据
     if (selectedMetrics.value[selectedLines.value[0]]) {
       queryPara['line'] = selectedLines.value[0];
@@ -681,21 +777,23 @@ function initMinuteChart0(minuteData, targetData) {
         itemHeight: 10
       },
       grid: {
-        left: '3%',
-        right: '4%',
+        left: '8%',   // 增加左边距,确保y轴标签完整显示
+        right: '8%',  // 增加右边距
         top: '25%',
-        bottom: 20,
+        bottom: 40,
         containLabel: true
       },
       xAxis: {
         type: 'category',
         boundaryGap: false,
         data: timePoints,
-        name: '分钟'
+        name: '分钟',
+        nameGap: 20
       },
       yAxis: {
         type: 'value',
-        name: targetData.paraName + (unit ? ' (' + unit + ')' : '')
+        name: targetData.paraName + (unit ? ' (' + unit + ')' : ''),
+        nameGap: 40  // 增加y轴名称与轴的距离
       },
       series: [{
         name: targetData.deviceName + '-' + targetData.paraName + (unit ? ' (' + unit + ')' : ''),
@@ -703,15 +801,18 @@ function initMinuteChart0(minuteData, targetData) {
         data: completeValues,
         smooth: true,
         showSymbol: false,
+        itemStyle: {
+          color: '#5470c6'  // 蓝色系
+        },
         markPoint: {
           data: [
-            { type: 'max', name: '最大值' },
-            { type: 'min', name: '最小值' }
+            {type: 'max', name: '最大值'},
+            {type: 'min', name: '最小值'}
           ]
         },
         markLine: {
           data: [
-            { type: 'average', name: '平均值' }
+            {type: 'average', name: '平均值'}
           ]
         }
       }]
@@ -781,21 +882,23 @@ function initMinuteChart1(minuteData, targetData) {
         itemHeight: 10
       },
       grid: {
-        left: '3%',
-        right: '4%',
+        left: '8%',   // 增加左边距,确保y轴标签完整显示
+        right: '8%',  // 增加右边距
         top: '25%',
-        bottom: 20,
+        bottom: 40,
         containLabel: true
       },
       xAxis: {
         type: 'category',
         boundaryGap: false,
         data: timePoints,
-        name: '分钟'
+        name: '分钟',
+        nameGap: 20
       },
       yAxis: {
         type: 'value',
-        name: targetData.paraName + (unit ? ' (' + unit + ')' : '')
+        name: targetData.paraName + (unit ? ' (' + unit + ')' : ''),
+        nameGap: 40  // 增加y轴名称与轴的距离
       },
       series: [{
         name: targetData.deviceName + '-' + targetData.paraName + (unit ? ' (' + unit + ')' : ''),
@@ -803,15 +906,18 @@ function initMinuteChart1(minuteData, targetData) {
         data: completeValues,
         smooth: true,
         showSymbol: false,
+        itemStyle: {
+          color: '#91cc75'  // 绿色系
+        },
         markPoint: {
           data: [
-            { type: 'max', name: '最大值' },
-            { type: 'min', name: '最小值' }
+            {type: 'max', name: '最大值'},
+            {type: 'min', name: '最小值'}
           ]
         },
         markLine: {
           data: [
-            { type: 'average', name: '平均值' }
+            {type: 'average', name: '平均值'}
           ]
         }
       }]
@@ -870,21 +976,23 @@ function updateChart() {
         itemHeight: 10
       },
       grid: {
-        left: '3%',
-        right: '4%',
+        left: '8%',   // 增加左边距,确保y轴标签完整显示
+        right: '8%',  // 增加右边距
         top: '25%',
-        bottom: 20,
+        bottom: 40,
         containLabel: true
       },
       xAxis: {
         type: 'category',
         boundaryGap: false,
         data: hours,
-        name: '时间'
+        name: '时间',
+        nameGap: 20
       },
       yAxis: {
         type: 'value',
-        name: rzLineList.value[0].paraName + (unit ? ' (' + unit + ')' : '')
+        name: rzLineList.value[0].paraName + (unit ? ' (' + unit + ')' : ''),
+        nameGap: 40  // 增加y轴名称与轴的距离
       },
       series: [{
         name: rzLineList.value[0].deviceName,
@@ -892,15 +1000,18 @@ function updateChart() {
         data: values,
         smooth: true,
         showSymbol: false,
+        itemStyle: {
+          color: '#5470c6'  // 蓝色系
+        },
         markPoint: {
           data: [
-            { type: 'max', name: '最大值' },
-            { type: 'min', name: '最小值' }
+            {type: 'max', name: '最大值'},
+            {type: 'min', name: '最小值'}
           ]
         },
         markLine: {
           data: [
-            { type: 'average', name: '平均值' }
+            {type: 'average', name: '平均值'}
           ]
         }
       }]
@@ -991,21 +1102,23 @@ function updateChart1() {
         itemHeight: 10
       },
       grid: {
-        left: '3%',
-        right: '4%',
+        left: '8%',   // 增加左边距,确保y轴标签完整显示
+        right: '8%',  // 增加右边距
         top: '25%',
-        bottom: 20,
+        bottom: 40,
         containLabel: true
       },
       xAxis: {
         type: 'category',
         boundaryGap: false,
         data: hours,
-        name: '时间'
+        name: '时间',
+        nameGap: 20
       },
       yAxis: {
         type: 'value',
-        name: rzLineList1.value[0].paraName + (unit ? ' (' + unit + ')' : '')
+        name: rzLineList1.value[0].paraName + (unit ? ' (' + unit + ')' : ''),
+        nameGap: 40  // 增加y轴名称与轴的距离
       },
       series: [{
         name: rzLineList1.value[0].deviceName,
@@ -1013,15 +1126,18 @@ function updateChart1() {
         data: values,
         smooth: true,
         showSymbol: false,
+        itemStyle: {
+          color: '#91cc75'  // 绿色系
+        },
         markPoint: {
           data: [
-            { type: 'max', name: '最大值' },
-            { type: 'min', name: '最小值' }
+            {type: 'max', name: '最大值'},
+            {type: 'min', name: '最小值'}
           ]
         },
         markLine: {
           data: [
-            { type: 'average', name: '平均值' }
+            {type: 'average', name: '平均值'}
           ]
         }
       }]
@@ -1272,9 +1388,9 @@ onMounted(() => {
   });
 
   // 确保在DOM准备好后更新数据
-  setTimeout(() => {
-    updateQueryData();
-  }, 100);
+  // setTimeout(() => {
+  //   updateQueryData();
+  // }, 100);
 });
 
 onUnmounted(() => {
@@ -1356,10 +1472,11 @@ function resetQuery() {
   queryParams.value.workDay = `${year}-${month}-${day}`;
 
   // 重置产线和设备选择
-  selectedLines.value = [];
+  selectedLines.value = ['5', '6']; // 重置为默认的5号和6号产线
   selectedMetrics.value = {};
   equipmentList.value = {};
 
+  // 用户主动点击重置按钮时调用handleQuery,这会触发数据更新
   handleQuery();
 }
 
@@ -1387,10 +1504,10 @@ function handleEquipmentTypeChange(val) {
       if (selectedType.dyeTypeParaList.length > 0 && !selectedEquipmentParam.value) {
         selectedEquipmentParam.value = selectedType.dyeTypeParaList[0].paraCode;
         // 触发设备参数变化事件
-        handleEquipmentParamChange();
+        handleEquipmentParamChange(); // 不传参数,让函数自己判断是否是初始化状态
       } else if (selectedEquipmentParam.value) {
         // 如果已有参数,直接触发设备列表更新
-        handleEquipmentParamChange();
+        handleEquipmentParamChange(); // 不传参数,让函数自己判断是否是初始化状态
       }
     } else {
       equipmentParamOptions.value = [];
@@ -1407,7 +1524,7 @@ function handleEquipmentParamChange() {
   equipmentList.value = {};
   selectedMetrics.value = {};
 
-  // 获取新设备列表
+  // 获取新设备列表,让用户主动操作时调用
   getDeviceList();
 }
 
@@ -1422,6 +1539,7 @@ function handleLineSelectionChange(val) {
   if (val.length === 0) {
     selectedMetrics.value = {};
   }
+  // 用户主动操作时调用getDeviceList
   getDeviceList();
 }