Procházet zdrojové kódy

2023-02-07 update

1. 新增温度曲线分析页,
2. 条真prepare process 的默认激活chart功能
moccus před 2 roky
rodič
revize
eeb9c8ba49

+ 398 - 0
src/pages/dataAnalysis/hotAnalysis/components/current-scatter-chart.json

@@ -0,0 +1,398 @@
+
+{
+	"color": [
+			"#1C99FF",
+			"#FF8700",
+			"#e6b600d9",
+			"#0098d9",
+			"#3D54BE",
+			"#005eaa",
+			"#cda819",
+			"#32a487"
+	],
+	"textStyle": {},
+	"title": {
+			"textStyle": {
+					"color": "#333333"
+			},
+			"subtextStyle": {
+					"color": "#aaaaaa"
+			}
+	},
+	"line": {
+			"itemStyle": {
+					"borderWidth": 1
+			},
+			"lineStyle": {
+					"width": 2
+			},
+			"symbolSize": 4,
+			"symbol": "emptyCircle",
+			"smooth": false
+	},
+	"radar": {
+			"itemStyle": {
+					"borderWidth": 1
+			},
+			"lineStyle": {
+					"width": 2
+			},
+			"symbolSize": 4,
+			"symbol": "emptyCircle",
+			"smooth": false
+	},
+	"bar": {
+			"itemStyle": {
+					"barBorderWidth": 0,
+					"barBorderColor": "#ccc"
+			}
+	},
+	"pie": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"scatter": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"boxplot": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"parallel": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"sankey": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"funnel": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"gauge": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"candlestick": {
+			"itemStyle": {
+					"color": "#c12e34",
+					"color0": "#2b821d",
+					"borderColor": "#c12e34",
+					"borderColor0": "#2b821d",
+					"borderWidth": 1
+			}
+	},
+	"graph": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			},
+			"lineStyle": {
+					"width": 1,
+					"color": "#aaaaaa"
+			},
+			"symbolSize": 4,
+			"symbol": "emptyCircle",
+			"smooth": false,
+			"color": [
+					"#c12e34",
+					"#e6b600",
+					"#0098d9",
+					"#50ec39",
+					"#005eaa",
+					"#339ca8",
+					"#cda819",
+					"#32a487"
+			],
+			"label": {
+					"color": "#eeeeee"
+			}
+	},
+	"map": {
+			"itemStyle": {
+					"areaColor": "#ddd",
+					"borderColor": "#eee",
+					"borderWidth": 0.5
+			},
+			"label": {
+					"color": "#c12e34"
+			},
+			"emphasis": {
+					"itemStyle": {
+							"areaColor": "#e6b600",
+							"borderColor": "#ddd",
+							"borderWidth": 1
+					},
+					"label": {
+							"color": "#c12e34"
+					}
+			}
+	},
+	"geo": {
+			"itemStyle": {
+					"areaColor": "#ddd",
+					"borderColor": "#eee",
+					"borderWidth": 0.5
+			},
+			"label": {
+					"color": "#c12e34"
+			},
+			"emphasis": {
+					"itemStyle": {
+							"areaColor": "#e6b600",
+							"borderColor": "#ddd",
+							"borderWidth": 1
+					},
+					"label": {
+							"color": "#c12e34"
+					}
+			}
+	},
+	"categoryAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#333"
+					}
+			},
+			"axisTick": {
+					"show": true,
+					"lineStyle": {
+							"color": "#333"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#333"
+			},
+			"splitLine": {
+					"show": false,
+					"lineStyle": {
+							"color": [
+									"#ccc"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.3)",
+									"rgba(200,200,200,0.3)"
+							]
+					}
+			}
+	},
+	"valueAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#838383"
+					}
+			},
+			"axisTick": {
+					"show": true,
+					"lineStyle": {
+							"color": "#838383"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#838383"
+			},
+			"splitLine": {
+					"show": true,
+					"lineStyle": {
+							"color": [
+									"#ccc"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.3)",
+									"rgba(200,200,200,0.3)"
+							]
+					}
+			}
+	},
+	"logAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#333"
+					}
+			},
+			"axisTick": {
+					"show": true,
+					"lineStyle": {
+							"color": "#333"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#333"
+			},
+			"splitLine": {
+					"show": true,
+					"lineStyle": {
+							"color": [
+									"#ccc"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.3)",
+									"rgba(200,200,200,0.3)"
+							]
+					}
+			}
+	},
+	"timeAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#333"
+					}
+			},
+			"axisTick": {
+					"show": true,
+					"lineStyle": {
+							"color": "#333"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#333"
+			},
+			"splitLine": {
+					"show": true,
+					"lineStyle": {
+							"color": [
+									"#ccc"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.3)",
+									"rgba(200,200,200,0.3)"
+							]
+					}
+			}
+	},
+	"toolbox": {
+			"iconStyle": {
+					"borderColor": "#06467c"
+			},
+			"emphasis": {
+					"iconStyle": {
+							"borderColor": "#4187c2"
+					}
+			},
+			"textStyle": {
+				"color": "#838383"
+			}
+	},
+	"legend": {
+			"textStyle": {
+					"color": "#838383"
+			}
+	},
+	"tooltip": {
+			"axisPointer": {
+					"lineStyle": {
+							"color": "#cccccc",
+							"width": 1
+					},
+					"crossStyle": {
+							"color": "#cccccc",
+							"width": 1
+					}
+			}
+	},
+	"timeline": {
+			"lineStyle": {
+					"color": "#005eaa",
+					"width": 1
+			},
+			"itemStyle": {
+					"color": "#005eaa",
+					"borderWidth": 1
+			},
+			"controlStyle": {
+					"color": "#005eaa",
+					"borderColor": "#005eaa",
+					"borderWidth": 0.5
+			},
+			"checkpointStyle": {
+					"color": "#005eaa",
+					"borderColor": "#316bc2"
+			},
+			"label": {
+					"color": "#005eaa"
+			},
+			"emphasis": {
+					"itemStyle": {
+							"color": "#005eaa"
+					},
+					"controlStyle": {
+							"color": "#005eaa",
+							"borderColor": "#005eaa",
+							"borderWidth": 0.5
+					},
+					"label": {
+							"color": "#005eaa"
+					}
+			}
+	},
+	"visualMap": {
+			"color": [
+					"#1790cf",
+					"#a2d4e6"
+			]
+	},
+	"dataZoom": {
+			"backgroundColor": "rgba(47,69,84,0)",
+			"dataBackgroundColor": "rgba(47,69,84,0.3)",
+			"fillerColor": "rgba(167,183,204,0.4)",
+			"handleColor": "#a7b7cc",
+			"handleSize": "100%",
+			"textStyle": {
+					"color": "#333333"
+			}
+	},
+	"markPoint": {
+			"label": {
+					"color": "#eeeeee"
+			},
+			"emphasis": {
+					"label": {
+							"color": "#eeeeee"
+					}
+			}
+	}
+}

+ 366 - 0
src/pages/dataAnalysis/hotAnalysis/components/current-scatter-chart.vue

@@ -0,0 +1,366 @@
+<template>
+  <div class="chart" :id="id"></div>
+</template>
+
+<script>
+import util from "@tools/util";
+import partten from "@tools/partten";
+import * as echarts from "echarts";
+import chartTheme from './current-scatter-chart.json'
+
+export default {
+  name: 'currentScatterChart',
+  props: {
+    // 图表宽度
+    width: {
+      type: String,
+      default: "100%",
+    },
+    // 图表高度
+    height: {
+      type: String,
+      default: "350px",
+    },
+    // 图表主标题
+    chartTitle: {
+      type: String,
+      default: "自定义图表组件",
+    },
+    // X 轴配置项
+    xAxisData: {
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+    // Y 轴配置项
+    yAxisData: {
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+    dataSet: {
+      type: String,
+      default: ''
+    },
+    // 图表核心数据
+    seriesData: {
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+    // 是否显示图表图例
+    showLegend: {
+      type: Boolean,
+      default: true,
+    },
+    // 是否默认采用笔刷模式
+    brushSelected: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  data() {
+    return {
+      id: "",
+      chart: null,
+      color: [
+        "#05bb4c",
+        "#4b55ae",
+        "#fa8c16",
+        "#f8de5b",
+        "#1a93cf",
+        "#c531c7",
+        "#bd3338",
+      ],
+      theme: 'light'
+    };
+  },
+  watch: {
+    height(){
+      if(this.chart){
+          this.chart.resize()
+      }
+    }
+  },
+  methods: {
+    resize() {},
+    initChart() {
+      const that = this;
+      echarts.registerTheme('chartTheme', chartTheme)
+      let myChart = echarts.init(document.getElementById(this.id), 'chartTheme');
+      that.chart = myChart
+      //指定图表的配置项和数据
+      const option = {
+        //标题
+        title: {
+          text: that.chartTitle,
+          right: 440,
+          top: 4,
+          textStyle: {
+            fontSize: 14,
+            color: that.theme === "dark" ? partten.getColor("grayl") : "#000",
+          },
+        },
+        // backgroundColor:
+        //   that.theme === "dark"
+        //     ? "rgba(0,0,0,0.4)"
+        //     : "rgba(255,255,255,0.5)",
+        //工具箱
+        color: [
+            "#3D54BE",
+            "rgb(255,0,0)",
+            "#a1a1a1",
+            "#0098d9",
+            "#FF8700",
+            "#005eaa",
+            "#cda819",
+            "#32a487"
+        ],
+        toolbox: {
+          show: true,
+          x: "right",
+          position: [10, 10],
+          // backgroundColor:'rgba(0,0,0,0.4)',
+          borderColor: partten.getColor("gray"),
+          textStyle: {
+            fontSize: util.vh(16),
+            color: partten.getColor("gray")
+          },
+          iconStyle: {
+            borderColor:partten.getColor("gray")
+          },
+          emphasis: {
+            iconStyle: {
+              borderColor:partten.getColor("gray")
+            },
+          },
+        },
+        tooltip: {
+          trigger: "item",
+          axisPointer: {
+            type: "cross",
+          },
+          backgroundColor: "rgba(0,0,0,0.4)",
+          borderColor: partten.getColor("gray"),
+          textStyle: {
+            fontSize: util.vh(16),
+            color: "#fff",
+          },
+          formatter(params) {
+            return params.value?.x
+              ? `${params.seriesName}<br />风速:${params.value.x}m/s<br />功率:${params.value.y}kW`
+              : `${params.name}`;
+          },
+        },
+        brush: {
+          seriesIndex: [2,3],
+          yAxisIndex: 0,
+          transformable: true,
+          throttleType: "debounce",
+          throttleDelay: 1000,
+          removeOnClick: true,
+          brushType: "polygon",
+          brushMode: "multiple",
+          brushStyle: {
+            borderWidth: 1,
+            borderColor: "#ff2424",
+          },
+        },
+        dataZoom: [
+          {
+            type: "inside", //图表下方的伸缩条
+            show: false, //是否显示
+            realtime: true, //拖动时,是否实时更新系列的视图
+            start: 0, //伸缩条开始位置(1-100),可以随时更改
+            end: 100, //伸缩条结束位置(1-100),可以随时更改
+          },
+          {
+            type: "slider", //图表下方的伸缩条
+            show: false, //是否显示
+            realtime: true, //拖动时,是否实时更新系列的视图
+            start: 0, //伸缩条开始位置(1-100),可以随时更改
+            end: 100, //伸缩条结束位置(1-100),可以随时更改
+          },
+        ],
+        textStyle: {
+          fontSize: util.vh(16),
+          color: that.theme === "dark" ? "#fff" : "#000",
+        },
+        //图例-每一条数据的名字
+        legend: {
+          show: that.showLegend,
+          data: [ "拟合功率", "保证功率","无用点", "有用点", "Cp值"],
+          right: "120",
+          top: "5",
+          // icon: "circle",
+          itemWidth: 6,
+          inactiveColor:
+            that.theme === "dark"
+              ? partten.getColor("gray")
+              : "#000",
+          textStyle: {
+            color:
+              that.theme === "dark"
+                ? partten.getColor("grayl")
+                : "#000",
+            fontSize: 12,
+          },
+          
+        },
+        visualMap: [{
+            type: 'continuous',
+            min: -40,
+            max: 50,
+            dimension: 2,
+            orient: 'vertical',
+            right: 4,
+            top: 50,
+            itemHeight: 600,
+            text: ['50', '-40'],
+            calculable: false,
+            range: [-40,50],
+            inRange: {
+              color: ['#000', 'rgb(75,11,106)','rgb(133,33,106)','rgb(176,49,92)','rgb(210,70,69)','rgb(235,100,42)','rgb(247,126,21)','rgb(252,183,28)', 'rgb(249,252,156)']
+            },
+            outOfRange: {
+              color: ['#eee', '#eee']
+            }
+        }],
+        grid: {
+          top: 48,
+          left: 40,
+          right: 40,
+          bottom: 24,
+        },
+        //x轴
+        xAxis: [
+          {
+            name: 'm/s',
+            nameTextStyle: {
+              color: '#838383'
+            },
+            type: "value",
+            boundaryGap: false,
+            data: that.xAxisData || [],
+            min: 0,
+            max: 25,
+            interval: 1,
+            axisLabel: {
+              formatter: "{value}",
+            },
+            splitLine: {
+              show: false,
+            },
+            textStyle: {
+              color:
+                that.theme === "dark"
+                  ? partten.getColor("gray")
+                  : "#000",
+            },
+          },
+        ],
+        //y轴没有显式设置,根据值自动生成y轴
+        yAxis: [{
+          splitLine: { show: false },
+          position: 'left',
+          min: 0,
+          name: 'kW',
+          nameTextStyle: {
+            color: '#838383'
+          }
+        }, {
+          splitLine: { show: false },
+          position: 'right',
+          min: 0,
+        }],
+        animation: true,
+        dataset: that.dataSet.length? JSON.parse(that.dataSet) : [],
+        //数据-data是最终要显示的数据
+        series: that.seriesData,
+      };
+
+      that.resize = function () {
+        myChart.resize();
+      };
+
+      window.addEventListener("resize", that.resize);
+
+      myChart.setOption(option);
+      if (that.brushSelected) {
+        myChart.dispatchAction({
+          type: "takeGlobalCursor",
+          // 如果想变为“可刷选状态”,必须设置。不设置则会关闭“可刷选状态”。
+          key: "brush",
+          brushOption: {
+            seriesIndex: [2,3],
+            yAxisIndex: 0,
+            transformable: true,
+            throttleType: "debounce",
+            throttleDelay: 1000,
+            removeOnClick: true,
+            brushType: "polygon",
+            brushMode: "multiple",
+            brushStyle: {
+              borderWidth: 1,
+              color: "rgba(255,36,36,0.2)",
+              borderColor: "#ff2424",
+            },
+          },
+        });
+      }
+      myChart.off("brushSelected");
+      myChart.on("brushSelected", (params) => {
+        that.$emit("getSelected", params.batch || []);
+      });
+      myChart.off('click')
+      myChart.on('click', params => {
+          console.log(params)
+          if(params.componentType === 'markArea'){
+            myChart.dispatchAction({
+              type: 'brush',
+              areas: [
+                {
+                  xAxisIndex: 0,
+                  brushType: 'lineX',
+                  coordRange: [params.data.coord[0][0], params.data.coord[1][0]]
+                },
+              ]
+            });
+          }
+        })
+    },
+  },
+  created() {
+    this.id = "chart-" + util.newGUID();
+  },
+  mounted() {
+    // this.$nextTick(() => {
+      this.$el.style.width = this.width;
+      this.$el.style.height = this.height;
+      this.initChart();
+    // });
+  },
+  updated() {
+    console.log('update')
+    let myChart = echarts.init(document.getElementById(this.id));
+    myChart.dispose();
+    this.$nextTick(() => {
+      this.initChart();
+    });
+  },
+  unmounted() {
+    window.removeEventListener("resize", this.resize);
+  },
+};
+</script>
+
+<style>
+.chart {
+  width: 100%;
+  height: 100%;
+  display: inline-block;
+}
+</style>

+ 53 - 0
src/pages/dataAnalysis/hotAnalysis/components/search.vue

@@ -0,0 +1,53 @@
+<script setup name="search">
+import { reactive, ref } from 'vue'
+import SubmitBtn from '@com/SubmitBtn.vue'
+
+const queryForm = reactive({
+	maxs: 25,
+	mins: 0,
+	maxp: 2500,
+	minp: 0,
+	dimension: 10,  //拟合维度
+	mode: 0   //拟合方式
+})
+/**导出 */
+const emits = defineEmits(['submit'])
+const funSubmit = async () => {
+	emits('submit', queryForm)
+}
+/**created */
+</script>
+<template>
+	<div class="pl-[20px] flex items-center h-[80px] relative">
+		<div class="absolute top-[-7px] left-[20px] text-[#838383] text-[14px]">操作面板</div>
+		<el-form class="" :inline="true" :model="queryForm">
+			<el-form-item label="最大风速" class="!mb-0">
+				<el-input-number v-model="queryForm.maxs" size="small" :max="30"></el-input-number>
+			</el-form-item>
+			<el-form-item label="最小风速" class="!mb-0">
+				<el-input-number v-model="queryForm.mins" size="small" :min="0"></el-input-number>
+			</el-form-item>
+			<el-form-item label="最大功率" class="!mb-0">
+				<el-input-number v-model="queryForm.maxp" size="small"></el-input-number>
+			</el-form-item>
+			<el-form-item label="最小功率" class="!mb-0">
+				<el-input-number v-model="queryForm.minp" size="small" :min="0"></el-input-number>
+			</el-form-item>
+			<el-form-item label="多项式" class="!mb-0">
+				<el-select v-model="queryForm.dimension" class="w-[80px]">
+					<el-option v-for="item in 30" :key="item" :value="item" :label="item"></el-option>
+				</el-select>
+			</el-form-item>
+			<el-form-item label="拟合方式" class="!mb-0">
+				<el-select v-model="queryForm.mode" class="w-[120px]">
+					<el-option :value="0" label="单台拟合"></el-option>
+					<el-option :value="1" label="合并拟合"></el-option>
+					<el-option :value="2" label="同名拟合"></el-option>
+				</el-select>
+			</el-form-item>
+			<el-form-item class="!mb-0">
+				<submit-btn @click="funSubmit" desc="曲线拟合"></submit-btn>
+			</el-form-item>
+		</el-form>
+	</div>
+</template>

+ 52 - 0
src/pages/dataAnalysis/hotAnalysis/components/table.vue

@@ -0,0 +1,52 @@
+<script setup name="table">
+import { computed, ref } from 'vue';
+
+const props = defineProps({
+  height: {
+    type: String,
+    default: '800px'
+  },
+  data: {
+    type: Array,
+    default: () => ([]),
+  },
+  column: {
+    type: Array,
+    default: () => ([]),
+  },
+  tableName: {
+    type: String,
+    default: '',
+  },
+  tableId: {
+    type: String,
+    default: '',
+  },
+  loading: {
+    type: Boolean,
+    default: false,
+  }
+})
+const emits = defineEmits(['export'])
+const funExport = () => {
+  emits('export')
+}
+const tableRef = ref('')
+const tableHeight =  computed(() => {
+  return tableRef.value.offsetHeight? tableRef.value.offsetHeight - 46 : 739
+})
+</script>
+<template>
+  <div ref="tableRef" class=""
+    :style="{ height: typeof props.height === 'string' ? props.height : props.height + 'px' }">
+    <div class="flex justify-between items-center pb-[10px]">
+      <h3>{{ props.tableName }}</h3>
+      <!-- <el-button size="small" type="primary" @click="funExport" :disabled="!props.tableId">数据导出</el-button> -->
+    </div>
+    <el-table stripe :data="props.data" size="small" v-loading="props.loading" :max-height="tableHeight"
+      :style="{ width: '100%' }">
+      <el-table-column align="center" show-overflow-tooltip v-for="item in props.column" :prop="item.prop"
+        :label="item.label" sortable resizable :min-width="item.width ? item.width : 80" />
+    </el-table>
+  </div>
+</template>

+ 529 - 0
src/pages/dataAnalysis/hotAnalysis/index.vue

@@ -0,0 +1,529 @@
+<script setup name="prepare">
+import searchCop from './components/search.vue'
+import excelCop from '@/components/excel.vue'
+import treeCop from '@/components/tree.vue'
+import tableCop from './components/table.vue'
+import SubmitBtn from '@/components/SubmitBtn.vue'
+import { ref, nextTick, onActivated, onMounted, reactive } from 'vue'
+import request from '@/api/axios.js'
+import { ElMessage } from 'element-plus'
+import util from "@tools/util";
+import CurrentScatterChart from './components/current-scatter-chart.vue'
+// import dotRes from '@/data/dot.json'
+// import tableRes from '@/data/table.json'
+// import areaDataRes from '@/data/areaData.json'
+/**配置参数 */
+const treeHeight = ref(window.innerHeight - 150 + 'px') //tree高度
+const excelHeight = ref(window.innerHeight - 150 + 'px') //excel高度
+const tableHeight = ref(window.innerHeight - 204 + 'px')
+/**excel 开始 */
+const excelCheckboxShow = ref(false)
+const excelType = ref('')
+const excelCheckIds = ref([])
+const excelList = ref([])
+const funExcelChange = async (obj) => { //点击excel项时
+	activeTab.value = '1'
+	isChartArea.value = false
+	tableShowId.value = obj.id
+	tableName.value = obj.name
+	excelType.value = obj.type // 接收excel的type 用于控制右侧tab展示
+
+	let res = null
+	let chartRes = {
+		scatterhs: [[]],
+		scatterls: [[]],
+		sjgl: [[]],
+		llgl: [[]],
+		cpz: [[]]
+	}
+	let chartResponse = null
+	tableLoading.value = true
+	if (obj.type === 'process') {
+		res = await request.get('/power/process/show', { params: { id: obj.id } })
+	} else if (obj.type === 'fitting') {
+		activeTab.value = '2'
+		res = await request.get('/power/fitting/show', { params: { id: obj.id } })
+		// res = tableRes
+		// chartResponse = dotRes
+		chartResponse = await request.get('/temperature/curve/analysis', { params: { id: obj.id, p: 1 } })
+	}
+	if(res.code === 200){
+		tableColumn.value = res.data.title.map(o => {
+			return {
+				prop: o.key,
+				width: o.des==='时间'? 100: 80,
+				label: o.des,
+			}
+		})
+		tableData.value = res.data.data
+		tableLoading.value = false
+	}else{
+		tableLoading.value = false
+	}
+
+	if (chartResponse && chartResponse.code === 200) {
+		chartRes = chartResponse.data
+		markDot.pcl5 = chartRes.obj.pc5ratio
+		markDot.pcl10 = chartRes.obj.pc10ratio
+		markDot.pcl12 = chartRes.obj.pc12ratio
+		markDot.pcl25 = chartRes.obj.pc25ratio
+		avgObj.title = chartRes.obj.path.substring(chartRes.obj.path.indexOf(chartRes.obj.station + '_') + (chartRes.obj.station + '_').length).split('_')[0];
+		avgObj.cpavg = Number(chartRes.obj.cpavg).toFixed(2)
+		avgObj.frequency = Number(chartRes.obj.frequency).toFixed(2)
+		avgObj.pcratio = Number(chartRes.obj.pcratio).toFixed(2)
+		// dataSet.value = JSON.stringify([
+		// 	{
+		// 		source: chartRes.scatter
+		// 	},
+		// ])
+		const color = ["#1C99FF", "#FF8700", "#3D54BE", "#fa8c16", "#1DA0D7", "#DD5044"]
+		seriesData.value = [
+			{
+				name: "拟合功率",
+				type: "line",
+				symbol: "line", //设定为实心点
+				symbolSize: 0, //设定实心点的大小
+				smooth: true, //这个是把线变成曲线
+				data: chartRes.sjgl,
+				xAxisIndex: 0,
+			},
+			{
+				name: "保证功率",
+				type: "line",
+				symbol: "line", //设定为实心点
+				symbolSize: 0, //设定实心点的大小
+				smooth: true, //这个是把线变成曲线
+				data: chartRes.llgl,
+				xAxisIndex: 0,
+			},
+			{
+				type: 'effectScatter',
+				showEffectOn: "emphasis",
+				rippleEffect: {
+					scale: 1
+				},
+				name: '有用点',
+				// symbolSize: (data) => {
+				// 	return data.s ? data.s > 10 ? 10 : data.s : 4
+				// },
+				// datasetIndex: 1,
+				// encode: {
+				// 	x: 'x',
+				// 	y: 'y'
+				// },
+				data: chartRes.scatter,
+				xAxisIndex: 0,
+				yAxisIndex: 0,
+			},
+		]
+	}
+}
+const funExcelCheckChange = ({ checkArr, data }) => {   //bug 
+	excelCheckIds.value = checkArr
+}
+/**excel fitData */
+const excelFitList = ref([])
+/**prepare tree 开始 */
+const treeData = ref([])
+const actTreeNode = ref(null) //当前激活的treeNode
+const funRepeatMap = (arr, type='prepare') => {
+	return arr.map(o => {
+		if (o.children) {
+			const findIndex = o.children.findIndex(p => !!p.type)
+			if (findIndex !== -1) {
+				o.childs = o.children
+				o.children = []
+				if(!actTreeNode.value && type === 'process'){ //判断当且仅有process获取tree时 赋值
+					actTreeNode.value = o
+				}
+			}
+		}
+		return {
+			...o,
+			children: o.children ? funRepeatMap(o.children, type) : []
+		}
+	})
+}
+const funGetTree = async () => {
+	const res = await request.get("/power/process/tree")
+	treeData.value = funRepeatMap(res.data)
+	excelList.value = []
+}
+const funCurrentChange = ({ current, currentNode }) => {
+	excelCheckboxShow.value = true
+	if (current.childs) {
+		excelList.value = current.childs.map(o => {
+			return {
+				id: o.id,
+				interval: o.interval,
+				path: o.path,
+				prepareid: o.prepareid,
+				station: o.station,
+				time: o.time,
+				type: o.type,
+				windturbine: o.windturbine,
+				name: o.path.substring(o.path.indexOf(o.station + '_') + (o.station + '_').length)
+			}
+		})
+	} else {
+		excelList.value = []
+	}
+}
+const funTreeCheckChange = ({ current, checkedNodes, checkedKeys, halfCheckedNodes, halfCheckedKeys }) => {  //tree change  -> excel change
+	funCurrentChange({ current, currentNode: '' })
+	const checkIds = []
+	if (checkedNodes.length) {
+		for (const node of checkedNodes) {
+			if (node.childs && node.childs.length) {
+				for (const child of node.childs) {
+					checkIds.push(child.id)
+				}
+			}
+		}
+	}
+	excelCheckIds.value = checkIds
+}
+
+/**process tree 开始 */
+const processTreeData = ref([])
+const funGetProcessTree = async (flag = true) => { //flag控制是否获取tree的第一项 true为可获取
+	actTreeNode.value = null
+	const res = await request.get("/power/fitting/tree")
+	excelFitList.value = []
+	processTreeData.value = funRepeatMap(res.data, flag? 'process' : 'prepare') //flag控制对actTreeNode赋值
+	if(actTreeNode.value){
+		funProcessCurrentChange({current: actTreeNode.value, currentNode: null})
+		const child = actTreeNode.value.childs[0]
+		const obj = {
+			id: child.id,
+			interval: child.interval,
+			path: child.path,
+			prepareid: child.prepareid,
+			station: child.station,
+			time: child.time,
+			type: child.type,
+			windturbine: child.windturbine,
+			name: child.path.substring(child.path.indexOf(child.station + '_') + (child.station + '_').length)
+		}
+		funExcelChange(obj)
+	}
+}
+const funProcessCurrentChange = ({ current, currentNode }) => {
+	if (current.childs) {
+		excelFitList.value = current.childs.map(o => {
+			return {
+				id: o.id,
+				interval: o.interval,
+				path: o.path,
+				prepareid: o.prepareid,
+				station: o.station,
+				time: o.time,
+				type: o.type,
+				windturbine: o.windturbine,
+				name: o.path.substring(o.path.indexOf(o.station + '_') + (o.station + '_').length)
+			}
+		})
+	} else {
+		excelFitList.value = []
+	}
+}
+
+/**table 开始 */
+const tableShowId = ref('')
+const tableColumn = ref([])
+const tableLoading = ref(false)
+const tableName = ref('')
+const tableData = ref([])
+/**table 结束 */
+/**search 开始 */
+const funSubmit = async (query) => {
+	if (!excelCheckIds.value.length) {
+		ElMessage.error('请勾选要预处理的项')
+		return false
+	}
+	const params = {
+		...query,
+		ids: excelCheckIds.value.join(',')
+	}
+	const res = await request.get('/power/fitting/data', { params: params })
+	if (res.code === 200) {
+		ElMessage.success(res.msg)
+		funGetProcessTree(false) //阻止获取tree第一项数据及图表
+		const excelInfo = res.data
+
+		/**拟合完成后 显示右侧图表及数据 */
+		funExcelChange({
+			id: excelInfo.id,
+			name: excelInfo.path.substring(excelInfo.path.indexOf(excelInfo.station + '_') + (excelInfo.station + '_').length),
+			type: 'fitting'
+		})
+	}
+}
+/**chart Data */
+const avgObj = reactive({ //平均cpz等
+	title: '',
+	cpavg: '',
+	frequency: '',
+	pcratio: ''
+})
+const markDot = reactive({ //3-5 point点等
+	pcl5: null,
+	pcl10: null,
+	pcl12: null,
+	pcl25: null
+})
+const xAxisData = ref([])
+const chartRef = ref() //chart 的ref
+const seriesData = ref([])
+const isChartArea = ref(false) // 用来控制图表是否区域划分
+const dataSet = ref('')
+const funChartSelect = async (batch) => {
+	const wDataArr = []
+	const yDataArr = []
+	let scatterls = []
+	let scatterhs = []
+	let dataSetObj = []
+	wtData.value = []
+	if (batch?.length && dataSet.value) {
+		scatterls = batch[0].selected[2].dataIndex
+		scatterhs = batch[0].selected[3].dataIndex
+		if (scatterls?.length || scatterhs?.length) {
+			dataSetObj = JSON.parse(dataSet.value)
+			if (scatterls?.length) {
+				for (const scatterIndex of scatterls) {
+					wDataArr.push(dataSetObj[0].source[scatterIndex].k)
+				}
+			}
+			if (scatterhs?.length) {
+				for (const scatterIndex of scatterhs) {
+					yDataArr.push(dataSetObj[1].source[scatterIndex].k)
+				}
+			}
+			const wtRes = await request.get('/power/fitting/filter', { params: { yk: yDataArr.join(','), wk: wDataArr.join(',') } })
+			if (wtRes.code === 200) {
+				let id = 1
+				const tempArr = [] //用于以风机id 聚合dataArr
+				if (wtRes.data?.length) {
+					for (const data of wtRes.data) {
+						if (tempArr.length) {
+							const findIndex = tempArr.findIndex(o => o.wtId === data.wtId)
+							if (findIndex !== -1) {
+								if (!tempArr[findIndex].children) {
+									tempArr[findIndex].children = []
+								}
+								tempArr[findIndex].children.push({ ...data, id: id, filter: data.filter === 0 ? '是' : '否' })
+								id++
+							} else {
+								tempArr.push({ ...data, id: id, filter: data.filter === 0 ? '是' : '否' })
+								id++
+							}
+						} else {
+							tempArr.push({ ...data, id: id, filter: data.filter === 0 ? '是' : '否' })
+							id++
+						}
+					}
+					wtDialog.value = true
+					nextTick(() => {
+						wtTab.value = 'table'
+						wtData.value = tempArr
+					})
+				}
+			}
+		}
+	}
+}
+const funChartArea = () => {
+	if (seriesData.value?.length) {
+		if (!isChartArea.value) {
+			// 请求一下
+			seriesData.value[0] = {
+					...seriesData.value[0],
+					markLine: {
+						symbol: 'none',
+						label: {
+							show: false
+						},
+						lineStyle: {
+							color: 'rgba(96,174,255, 1)'
+						},
+						data: [
+							{
+								xAxis: 3,
+								valueIndex: 0,
+							},
+							{
+								xAxis: 5,
+								valueIndex: 0
+							},
+							{
+								xAxis: 10,
+								valueIndex: 0
+							},
+							{
+								xAxis: 12,
+								valueIndex: 0
+							},
+							{
+								xAxis: 25,
+								valueIndex: 0
+							},
+						]
+					},
+					markArea: {
+						label: {
+							fontSize: util.vh(12),
+						},
+						itemStyle: {
+							color: 'rgba(236,245,255, 0)'
+						},
+						emphasis: {
+							itemStyle: {
+								color: 'rgba(96,174,255, 0.5)'
+							}
+						},
+						data: [
+							[
+								{
+									name: `3~5m 偏差率: ${markDot.pcl5}%`,
+									xAxis: 3,
+								},
+								{
+									xAxis: 5,
+								}
+							],
+							[
+								{
+									name: `5~10m 偏差率: ${markDot.pcl10}%`,
+									xAxis: 5,
+								},
+								{
+									xAxis: 10,
+								}
+							],
+							[
+								{
+									name: `10~12m 偏差率: ${markDot.pcl12}%`,
+									xAxis: 10,
+								},
+								{
+									xAxis: 12,
+								}
+							],
+							[
+								{
+									name: `12~25m 偏差率: ${markDot.pcl25}%`,
+									xAxis: 12,
+								},
+								{
+									xAxis: 25,
+								}
+							],
+						]
+					},
+				}
+			isChartArea.value = true
+		} else {
+			seriesData.value[0] = {
+					...seriesData.value[0],
+					markLine: null,
+					markArea: null,
+				}
+			isChartArea.value = false
+		}
+	}
+}
+/**dialog 数据 */
+const wtDialog = ref(false)
+const wtData = ref([])
+const wtTab = ref('table')
+/**tab  */
+const activeTab = ref('1')
+/**created */
+// funGetTree()
+// funGetProcessTree()
+/**mounted */
+onMounted(() => {
+	tableHeight.value = window.innerHeight - 204 + 'px'
+	excelHeight.value =(window.innerHeight - 150) + 'px'
+	treeHeight.value = (window.innerHeight - 150) + 'px'
+	window.addEventListener('resize', () => {
+		tableHeight.value = window.innerHeight - 204 + 'px'
+		excelHeight.value = (window.innerHeight - 150) + 'px'
+		treeHeight.value = (window.innerHeight - 150)  + 'px'
+	})
+	/**test */
+	// funExcelChange({
+	// 	id: 1,
+	// 	name: 'excel',
+	// 	type: 'fitting',
+	// })
+})
+/**activated */
+onActivated(() => {
+	// funGetTree()
+	funGetProcessTree()
+})
+</script>
+<template>
+	<div class="bg-white py-[10px] px-[10px]">
+		<!-- <search-cop class="mb-[20px]  shadow rounded-[6px] shadow-blue-500" @submit="funSubmit">
+		</search-cop> -->
+		<el-dialog v-model="wtDialog" draggable title="风机功率点位">
+			<el-tabs v-model="wtTab">
+				<el-tab-pane label="数据" name="table">
+					<el-table :data="wtData" row-key="id" :max-height="550">
+						<el-table-column property="wtId" align="center" label="风机" />
+						<el-table-column property="time" sortable :width="160" align="center" label="时间" />
+						<el-table-column property="speed" sortable align="center" label="风速(m/s)" />
+						<el-table-column property="power" sortable align="center" label="功率(kW)" />
+						<el-table-column property="rr" sortable align="center" label="转速" />
+						<el-table-column property="filter" sortable align="center" label="是否有用点" />
+					</el-table>
+				</el-tab-pane>
+				<el-tab-pane label="故障" name="problem" disabled>
+
+				</el-tab-pane>
+				<el-tab-pane label="预警" name="warning" disabled>
+
+				</el-tab-pane>
+			</el-tabs>
+		</el-dialog>
+		<div class="relative shadow rounded-[6px] shadow-blue-500 px-[10px] pt-[20px] pb-[10px]">
+			<div class="text-[14px] absolute top-[-7px] text-[#838383] left-[20px]">数据展示</div>
+			<el-row :gutter="10">
+				<el-col :span="5">
+					<!-- <tree-cop :data="treeData" @checkChange="funTreeCheckChange" :show-checkbox="true" :height="treeHeight"
+						@currentChange="funCurrentChange" @refresh="funGetTree"></tree-cop> -->
+					<tree-cop :data="processTreeData" :height="treeHeight"
+						@currentChange="funProcessCurrentChange" @refresh="funGetProcessTree"></tree-cop>
+				</el-col>
+				<el-col :span="3">
+					<!-- <excel-cop :checkIds="excelCheckIds" :showCheckbox="excelCheckboxShow" :data="excelList" :height="excelHeight"
+						@excelChange="funExcelChange" @checkChange="funExcelCheckChange"></excel-cop> -->
+					<excel-cop :data="excelFitList" :height="excelHeight" @excelChange="funExcelChange">
+					</excel-cop>
+				</el-col>
+				<el-col :span="16">
+					<div class="px-[10px] shadow rounded-[6px] shadow-blue-500 ">
+						<SubmitBtn class="absolute right-[16px] top-[6px] z-10" desc="区域划分" v-if="activeTab === '2' && excelType === 'fitting'" @click="funChartArea"></SubmitBtn>
+						<el-tabs v-model="activeTab">
+							<el-tab-pane label="表格数据" name="1">
+							</el-tab-pane>
+							<el-tab-pane label="图表展示" name="2" v-if="excelType === 'fitting'">
+							</el-tab-pane>
+							<table-cop v-show="activeTab === '1'" :data="tableData" :loading="tableLoading" :column="tableColumn"
+								:height="tableHeight" :tableId="tableShowId" :tableName="tableName"></table-cop>
+							<div v-show="activeTab === '2'"
+								:style="{ height: typeof tableHeight === 'string' ? tableHeight : tableHeight + 'px' }"
+								class="p-[10px]">
+								<CurrentScatterChart ref="chartRef" width="100%" :height="`calc( ${tableHeight} - 20px )`" :chartTitle="avgObj.title+ '&nbsp;&nbsp;' +'平均Cp值:'+avgObj.cpavg+'; 静风频率:'+avgObj.frequency+'%; 曲线偏差率:'+avgObj.pcratio+'%'"
+									:xAxisData="xAxisData" :yAxisData="{ splitLine: { show: false } }" :seriesData="seriesData"
+									:showLegend="true" :brushSelected="false" :dataSet="dataSet" @getSelected="funChartSelect" />
+							</div>
+						</el-tabs>
+					</div>
+				</el-col>
+			</el-row>
+		</div>
+	</div>
+</template>

+ 21 - 0
src/pages/dataFilter/prepare/index.vue

@@ -34,6 +34,7 @@ const funExcelChange = async (obj) => { //点击excel项时
 }
 /**tree 开始 */
 const treeData = ref([])
+const actTreeNode = ref(null) //当前激活的treeNode
 const funRepeatMap = (arr) => {
 	return arr.map(o => {
 		if (o.children) {
@@ -41,6 +42,9 @@ const funRepeatMap = (arr) => {
 			if (findIndex !== -1) {
 				o.childs = o.children
 				o.children = []
+				if(!actTreeNode.value){ //判断当且仅有process获取tree时 赋值
+					actTreeNode.value = o
+				}
 			}
 		}
 		return {
@@ -50,9 +54,26 @@ const funRepeatMap = (arr) => {
 	})
 }
 const funGetTree = async () => {
+	actTreeNode.value = null
 	const res = await request.get("/power/prepare/tree")
 	treeData.value = funRepeatMap(res.data)
 	excelList.value = []
+	if(actTreeNode.value){
+		funCurrentChange({current: actTreeNode.value, currentNode: null})
+		const child = actTreeNode.value.childs[0]
+		const obj = {
+			id: child.id,
+			interval: child.interval,
+			path: child.path,
+			prepareid: child.prepareid,
+			station: child.station,
+			time: child.time,
+			type: child.type,
+			windturbine: child.windturbine,
+			name: child.path.substring(child.path.indexOf(child.station + '_') + (child.station + '_').length)
+		}
+		funExcelChange(obj)
+	}
 }
 const funCurrentChange = ({ current, currentNode }) => {
 	if (current.childs) {

+ 24 - 3
src/pages/dataFilter/process/index.vue

@@ -44,18 +44,21 @@ const funExcelCheckChange = ({ checkArr, data }) => {   //bug
 }
 /**prepare tree 开始 */
 const treeData = ref([])
-const funRepeatMap = (arr) => {
+const funRepeatMap = (arr, type = 'prepare') => {
 	return arr.map(o => {
 		if (o.children) {
 			const findIndex = o.children.findIndex(p => !!p.type)
 			if (findIndex !== -1) {
 				o.childs = o.children
 				o.children = []
+				if(!actTreeNode.value && type === 'fitting'){ //判断当且仅有process获取tree时 赋值
+					actTreeNode.value = o
+				}
 			}
 		}
 		return {
 			...o,
-			children: o.children ? funRepeatMap(o.children) : []
+			children: o.children ? funRepeatMap(o.children, type) : []
 		}
 	})
 }
@@ -101,10 +104,28 @@ const funTreeCheckChange = ({ current, checkedNodes, checkedKeys, halfCheckedNod
 
 /**process tree 开始 */
 const processTreeData = ref([])
+const actTreeNode = ref(null)
 const funGetProcessTree = async () => {
+	actTreeNode.value = null
 	const res = await request.get("/power/process/tree")
-	processTreeData.value = funRepeatMap(res.data)
+	processTreeData.value = funRepeatMap(res.data, 'fitting')
 	excelList.value = []
+	if(actTreeNode.value){
+		funProcessCurrentChange({current: actTreeNode.value, currentNode: null})
+		const child = actTreeNode.value.childs[0]
+		const obj = {
+			id: child.id,
+			interval: child.interval,
+			path: child.path,
+			prepareid: child.prepareid,
+			station: child.station,
+			time: child.time,
+			type: child.type,
+			windturbine: child.windturbine,
+			name: child.path.substring(child.path.indexOf(child.station + '_') + (child.station + '_').length)
+		}
+		funExcelChange(obj)
+	}
 }
 const funProcessCurrentChange = ({ current, currentNode }) => {
 	excelCheckboxShow.value = false

+ 13 - 1
src/router/index.js

@@ -100,10 +100,22 @@ const routes = [{
                 },
                 {
                     icon: 'el-icon-s-home',
+                    path: '/dataAnalysis/hotAnalysis',
+                    name: 'dataAnalysisthotAnalysis',
+                    meta: {
+                        title: '温度曲线分析',
+                    },
+                    component: () =>
+                        import(
+                            '../pages/dataAnalysis/hotAnalysis/index.vue'
+                        ),
+                },
+                {
+                    icon: 'el-icon-s-home',
                     path: '/dataAnalysis/tempAnalysis',
                     name: 'dataAnalysistempAnalysis',
                     meta: {
-                        title: '温度曲线分析',
+                        title: '温度与功率曲线分析',
                     },
                     component: () =>
                         import(