|
|
@@ -0,0 +1,1097 @@
|
|
|
+<script setup name="hotAnalysis">
|
|
|
+import BASE from "@tools/basicTool.js";
|
|
|
+import excelCop from "@/components/excel.vue";
|
|
|
+import treeCop from "@/components/tree.vue";
|
|
|
+import barChartCop from "./components/barChart.vue";
|
|
|
+import lineChartCop from "./components/lineChart.vue";
|
|
|
+import SubmitBtn from "@/components/SubmitBtn.vue";
|
|
|
+import {
|
|
|
+ shallowRef,
|
|
|
+ ref,
|
|
|
+ nextTick,
|
|
|
+ onActivated,
|
|
|
+ onMounted,
|
|
|
+ reactive,
|
|
|
+} from "vue";
|
|
|
+import {
|
|
|
+ getWindtempCurveAnalysis,
|
|
|
+ getWindFittingTree,
|
|
|
+ getWindtempRatedPower,
|
|
|
+ getWindFittingFilter,
|
|
|
+} from "@/api/powerGenerating/index.js";
|
|
|
+import request from "@/tools/request";
|
|
|
+import tools from "@tools/htmlToPdf.js";
|
|
|
+import { ElMessage } from "element-plus";
|
|
|
+import util from "@tools/util";
|
|
|
+import CurrentScatterChart from "./components/current-scatter-chart.vue";
|
|
|
+const baseURL = process.env.VUE_APP_TEST;
|
|
|
+const currentId = ref("");
|
|
|
+/** 额定功率 */
|
|
|
+const powerproduction = ref("");
|
|
|
+/**excel 开始 */
|
|
|
+const excelCheckboxShow = ref(false);
|
|
|
+const excelCheckIds = ref([]);
|
|
|
+const excelList = ref([]);
|
|
|
+const funExcelChange = async (obj) => {
|
|
|
+ //点击excel项时
|
|
|
+ /**次代码供温度功率曲线分析使用 */
|
|
|
+ excelCheckIds.value = [obj.id]; //当为单选展示风机图表时
|
|
|
+ currentId.value = obj.id;
|
|
|
+ chartExcelList.value = excelList.value.map((o) => {
|
|
|
+ return {
|
|
|
+ ...o,
|
|
|
+ name: o.windturbine,
|
|
|
+ };
|
|
|
+ }); // 选中excel当前项时, excel列表赋值给dialog 下拉框
|
|
|
+ queryForm.checkIds = excelList.value.map((o) => o.id);
|
|
|
+ checkAll.value = true;
|
|
|
+ funSubmit();
|
|
|
+ /**---------------------------- */
|
|
|
+ // activeTab.value = '1'
|
|
|
+ isChartArea.value = false;
|
|
|
+
|
|
|
+ let chartRes = {
|
|
|
+ scatterhs: [[]],
|
|
|
+ scatterls: [[]],
|
|
|
+ sjgl: [[]],
|
|
|
+ llgl: [[]],
|
|
|
+ cpz: [[]],
|
|
|
+ };
|
|
|
+ let chartResponse = null;
|
|
|
+ if (obj.type === "fitting") {
|
|
|
+ chartResponse = await getWindtempCurveAnalysis({ id: obj.id, p: 1 });
|
|
|
+ }
|
|
|
+
|
|
|
+ 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 }) => {
|
|
|
+ excelCheckIds.value = checkArr;
|
|
|
+};
|
|
|
+/**prepare tree 开始 */
|
|
|
+const treeData = ref([]);
|
|
|
+const actTreeNode = ref(null); //当前激活的treeNode
|
|
|
+const funRepeatMap = (arr) => {
|
|
|
+ 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) {
|
|
|
+ //判断当且仅有process获取tree时 赋值
|
|
|
+ actTreeNode.value = o;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ ...o,
|
|
|
+ children: o.children ? funRepeatMap(o.children) : [],
|
|
|
+ };
|
|
|
+ });
|
|
|
+};
|
|
|
+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 = [];
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/**process tree 开始 */
|
|
|
+const processTreeData = ref([]);
|
|
|
+const funGetProcessTree = async () => {
|
|
|
+ //flag控制是否获取tree的第一项 true为可获取
|
|
|
+ actTreeNode.value = null;
|
|
|
+ const res = await getWindFittingTree();
|
|
|
+ excelList.value = [];
|
|
|
+ processTreeData.value = funRepeatMap(res.data); //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) {
|
|
|
+ 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 = [];
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/**chart */
|
|
|
+let chartId = 1;
|
|
|
+const powerproductionNum = ref(0);
|
|
|
+/**search 开始 */
|
|
|
+const funSubmit = async () => {
|
|
|
+ BASE.showLoading();
|
|
|
+ const tempRes = await getWindtempRatedPower({
|
|
|
+ ids: excelCheckIds.value.join(","),
|
|
|
+ });
|
|
|
+ if (tempRes.code === 200) {
|
|
|
+ BASE.closeLoading();
|
|
|
+ if (tempRes.data?.length) {
|
|
|
+ for (const chart of tempRes.data) {
|
|
|
+ powerproduction.value = `(额定功率=${chart.power.powerProduction}kW)`;
|
|
|
+ powerproductionNum.value = chart.power.powerProduction;
|
|
|
+ barxAxis.data = Object.keys(chart.res1);
|
|
|
+ barSeries[0].data = Object.values(chart.res1);
|
|
|
+ barSeries[0].markLine.data = [
|
|
|
+ {
|
|
|
+ yAxis: 0,
|
|
|
+ },
|
|
|
+ ];
|
|
|
+ chartId++;
|
|
|
+ lineSeries.value = [
|
|
|
+ {
|
|
|
+ type: "effectScatter",
|
|
|
+ showEffectOn: "emphasis",
|
|
|
+ rippleEffect: {
|
|
|
+ scale: 1,
|
|
|
+ },
|
|
|
+ legendHoverLink: false,
|
|
|
+ name: "",
|
|
|
+ symbolSize: 5,
|
|
|
+ data: chart.res2,
|
|
|
+ yAxisIndex: 0,
|
|
|
+ markLine: {
|
|
|
+ symbol: "none",
|
|
|
+ label: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ lineStyle: {
|
|
|
+ color: "#F72C5B",
|
|
|
+ },
|
|
|
+ data: [
|
|
|
+ {
|
|
|
+ yAxis: powerproductionNum.value,
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ];
|
|
|
+ chartId++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+/**lineChart */
|
|
|
+const linexAxis = reactive({
|
|
|
+ type: "value",
|
|
|
+ name: "°C",
|
|
|
+ splitLine: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ axisTick: {
|
|
|
+ show: true,
|
|
|
+ },
|
|
|
+ axisLine: {
|
|
|
+ onZero: false,
|
|
|
+ },
|
|
|
+});
|
|
|
+const lineyAxis = reactive([
|
|
|
+ {
|
|
|
+ type: "value",
|
|
|
+ name: "kW",
|
|
|
+ splitLine: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ axisTick: {
|
|
|
+ show: true,
|
|
|
+ },
|
|
|
+ axisLine: {
|
|
|
+ onZero: false,
|
|
|
+ },
|
|
|
+ },
|
|
|
+]);
|
|
|
+const lineSeries = ref([]);
|
|
|
+const lineDataSet = reactive([
|
|
|
+ {
|
|
|
+ source: [],
|
|
|
+ },
|
|
|
+]);
|
|
|
+// 圈选散点触发函数
|
|
|
+const funChartSelect = async (batch) => {
|
|
|
+ const wDataArr = [];
|
|
|
+ const yDataArr = [];
|
|
|
+ let scatterls = [];
|
|
|
+ let dataSetObj = [];
|
|
|
+ wtData.value = [];
|
|
|
+ if (batch?.length && actCopList.value[0]?.dataset) {
|
|
|
+ scatterls = batch[0].selected[1].dataIndex;
|
|
|
+ if (scatterls?.length) {
|
|
|
+ dataSetObj = JSON.parse(actCopList.value[0].dataset);
|
|
|
+ if (scatterls?.length) {
|
|
|
+ for (const scatterIndex of scatterls) {
|
|
|
+ wDataArr.push(dataSetObj[0].source[scatterIndex].k);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const wtRes = await getWindFittingFilter({
|
|
|
+ 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;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+/**barChart */
|
|
|
+const barxAxis = reactive({
|
|
|
+ type: "category",
|
|
|
+ name: "℃",
|
|
|
+ data: [],
|
|
|
+ splitLine: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ axisTick: {
|
|
|
+ show: true,
|
|
|
+ },
|
|
|
+ axisLine: {
|
|
|
+ onZero: false,
|
|
|
+ },
|
|
|
+});
|
|
|
+const baryAxis = reactive({
|
|
|
+ type: "value",
|
|
|
+ name: "kW",
|
|
|
+ splitLine: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ axisTick: {
|
|
|
+ show: true,
|
|
|
+ },
|
|
|
+ axisLine: {
|
|
|
+ onZero: false,
|
|
|
+ },
|
|
|
+});
|
|
|
+const barSeries = reactive([
|
|
|
+ {
|
|
|
+ name: "",
|
|
|
+ type: "bar",
|
|
|
+ data: [],
|
|
|
+ markLine: {
|
|
|
+ symbol: "none",
|
|
|
+ label: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ lineStyle: {
|
|
|
+ color: "#F72C5B",
|
|
|
+ },
|
|
|
+ data: [],
|
|
|
+ },
|
|
|
+ },
|
|
|
+]);
|
|
|
+/**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 funhotChartSelect = 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 getWindFittingFilter({
|
|
|
+ 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");
|
|
|
+/**dialog */
|
|
|
+const dialog = ref(false);
|
|
|
+const actChartName = ref("");
|
|
|
+const actDiaTitle = ref("");
|
|
|
+const diaPanelRef = ref();
|
|
|
+const exportLoading = ref(false);
|
|
|
+const actCopList = ref([
|
|
|
+ // {
|
|
|
+ // xAxis: [],
|
|
|
+ // subtext: '',
|
|
|
+ // title: '',
|
|
|
+ // isRadar: false,
|
|
|
+ // series: [],
|
|
|
+ // yAxis: [],
|
|
|
+ // dataset: []
|
|
|
+ // }
|
|
|
+]);
|
|
|
+// 作为actCopList的备份 在actCopList赋值多个时 同时赋值, 在dialog弹出时清空. 作用: 在actCopList变化时, 重新赋值原始数据
|
|
|
+const actCopListBak = ref([]);
|
|
|
+const checkAll = ref(true);
|
|
|
+const queryForm = reactive({
|
|
|
+ checkIds: [],
|
|
|
+});
|
|
|
+const funCheckAll = () => {
|
|
|
+ checkAll.value = !checkAll.value;
|
|
|
+ if (checkAll.value) {
|
|
|
+ queryForm.checkIds = chartExcelList.value.map((o) => o.id);
|
|
|
+ } else {
|
|
|
+ queryForm.checkIds = [];
|
|
|
+ }
|
|
|
+};
|
|
|
+const chartExcelList = ref([]); //dialog 下拉项
|
|
|
+const funActCop = (obj, type) => {
|
|
|
+ switch (type) {
|
|
|
+ case "barChartCop":
|
|
|
+ actChartName.value = "barChartCop";
|
|
|
+ obj.actCop = shallowRef(barChartCop);
|
|
|
+ actDiaTitle.value = "平均功率-额定功率";
|
|
|
+ break;
|
|
|
+ case "lineChartCop":
|
|
|
+ actChartName.value = "lineChartCop";
|
|
|
+ obj.actCop = shallowRef(lineChartCop);
|
|
|
+ actDiaTitle.value = "额定功率温度分析";
|
|
|
+ break;
|
|
|
+ // case 'CurrentScatterChartCop':
|
|
|
+ // actChartName.value = 'CurrentScatterChartCop'
|
|
|
+ // obj.actCop = shallowRef(CurrentScatte // console.log(res)rChartCop)
|
|
|
+ // actDiaTitle.value = '静态偏航对风分析图'
|
|
|
+ // break
|
|
|
+ }
|
|
|
+ obj.isBrush = false;
|
|
|
+ obj.id = chartId;
|
|
|
+ chartId++;
|
|
|
+ dialog.value = true;
|
|
|
+ actCopListBak.value = [];
|
|
|
+ nextTick(() => {
|
|
|
+ actCopList.value = [obj];
|
|
|
+ });
|
|
|
+};
|
|
|
+const funDiaSubmit = async () => {
|
|
|
+ let url = "";
|
|
|
+ switch (actChartName.value) {
|
|
|
+ case "barChartCop":
|
|
|
+ url = "/temperature/rated/power";
|
|
|
+ break;
|
|
|
+ case "lineChartCop":
|
|
|
+ url = "/temperature/rated/power";
|
|
|
+ break;
|
|
|
+ // case 'CurrentScatterChartCop':
|
|
|
+ // url = '' //暂无接口
|
|
|
+ // break
|
|
|
+ }
|
|
|
+ if (url) {
|
|
|
+ const res = await request({
|
|
|
+ baseURL,
|
|
|
+ url,
|
|
|
+ params: {
|
|
|
+ ids: queryForm.checkIds.join(","),
|
|
|
+ mode: 0,
|
|
|
+ },
|
|
|
+ method: "get",
|
|
|
+ headers: {
|
|
|
+ isPower: true,
|
|
|
+ },
|
|
|
+ timeout: 15000,
|
|
|
+ });
|
|
|
+ if (res.code === 200) {
|
|
|
+ actCopList.value = [];
|
|
|
+ actCopListBak.value = []; //清空备份
|
|
|
+ if (res.data?.length) {
|
|
|
+ for (const chart of res.data) {
|
|
|
+ if (actChartName.value === "barChartCop") {
|
|
|
+ actCopList.value.push({
|
|
|
+ id: chartId,
|
|
|
+ isBrush: false,
|
|
|
+ actCop: shallowRef(barChartCop),
|
|
|
+ title: chart.wt,
|
|
|
+ subtext: `平均功率-额定功率(额定功率=${chart.power.powerProduction}kW)`,
|
|
|
+ xAxis: {
|
|
|
+ ...barxAxis,
|
|
|
+ data: Object.keys(chart.res1),
|
|
|
+ },
|
|
|
+ yAxis: baryAxis,
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: "",
|
|
|
+ type: "bar",
|
|
|
+ data: Object.values(chart.res1),
|
|
|
+ markLine: {
|
|
|
+ symbol: "none",
|
|
|
+ label: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ lineStyle: {
|
|
|
+ color: "#F72C5B",
|
|
|
+ },
|
|
|
+ data: [
|
|
|
+ {
|
|
|
+ yAxis: 0,
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ });
|
|
|
+ chartId++;
|
|
|
+ }
|
|
|
+ if (actChartName.value === "lineChartCop") {
|
|
|
+ actCopList.value.push({
|
|
|
+ id: chartId,
|
|
|
+ isBrush: false,
|
|
|
+ actCop: shallowRef(lineChartCop),
|
|
|
+ title: chart.wt,
|
|
|
+ subtext: `额定功率温度分析(额定功率=${chart.power.powerProduction}kW)`,
|
|
|
+ xAxis: linexAxis,
|
|
|
+ yAxis: lineyAxis,
|
|
|
+ dataset: lineDataSet,
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ type: "effectScatter",
|
|
|
+ showEffectOn: "emphasis",
|
|
|
+ rippleEffect: {
|
|
|
+ scale: 1,
|
|
|
+ },
|
|
|
+ legendHoverLink: false,
|
|
|
+ name: "",
|
|
|
+ symbolSize: 5,
|
|
|
+ data: chart.res2,
|
|
|
+ yAxisIndex: 0,
|
|
|
+ markLine: {
|
|
|
+ symbol: "none",
|
|
|
+ label: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ lineStyle: {
|
|
|
+ color: "#F72C5B",
|
|
|
+ },
|
|
|
+ data: [
|
|
|
+ {
|
|
|
+ yAxis: chart.power.powerProduction,
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ });
|
|
|
+ chartId++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ actCopListBak.value = actCopList.value;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+const funDiaExport = () => {
|
|
|
+ exportLoading.value = true;
|
|
|
+ tools.scrollToPDF(diaPanelRef.value, actDiaTitle.value, () => {
|
|
|
+ exportLoading.value = false;
|
|
|
+ });
|
|
|
+};
|
|
|
+const funDbClick = (obj) => {
|
|
|
+ if (actCopListBak.value.length > 1) {
|
|
|
+ //判断大于1时, 才有双击放大功能
|
|
|
+ if (actCopList.value.length === 1) {
|
|
|
+ actCopList.value = actCopListBak.value;
|
|
|
+ } else {
|
|
|
+ actCopList.value = [obj];
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+/**tab */
|
|
|
+const activeTab = ref("1");
|
|
|
+/**created */
|
|
|
+funGetProcessTree();
|
|
|
+/**mounted */
|
|
|
+
|
|
|
+/**activated */
|
|
|
+onActivated(() => {
|
|
|
+ funGetProcessTree();
|
|
|
+});
|
|
|
+</script>
|
|
|
+<template>
|
|
|
+ <div class="container-wrapper">
|
|
|
+ <el-dialog draggable width="80%" v-model="dialog">
|
|
|
+ <template #title>
|
|
|
+ <div class="dialog-title">
|
|
|
+ <div class="title">{{ actDiaTitle }}</div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <el-form class="whitespace-nowrap" :inline="true" :model="queryForm">
|
|
|
+ <el-form-item label="">
|
|
|
+ <el-select
|
|
|
+ v-model="queryForm.checkIds"
|
|
|
+ popper-class="select"
|
|
|
+ clearable
|
|
|
+ @clear="checkAll = false"
|
|
|
+ collapse-tags
|
|
|
+ multiple
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ label="全选"
|
|
|
+ :class="{ selected: checkAll }"
|
|
|
+ @click="funCheckAll"
|
|
|
+ ></el-option>
|
|
|
+ <el-option
|
|
|
+ v-for="item in chartExcelList"
|
|
|
+ :key="item.id"
|
|
|
+ :value="item.id"
|
|
|
+ :label="item.name"
|
|
|
+ ></el-option>
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <submit-btn desc="查询" @click="funDiaSubmit"></submit-btn>
|
|
|
+ <submit-btn desc="导出" @click="funDiaExport"></submit-btn>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <div v-loading="exportLoading">
|
|
|
+ <div
|
|
|
+ ref="diaPanelRef"
|
|
|
+ style="
|
|
|
+ height: 700px;
|
|
|
+ overflow-y: auto;
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <component
|
|
|
+ :is="item.actCop"
|
|
|
+ :width="actCopList.length > 1 ? '50%' : '100%'"
|
|
|
+ height="100%"
|
|
|
+ v-for="item in actCopList"
|
|
|
+ :key="item.id"
|
|
|
+ :xAxis="item.xAxis"
|
|
|
+ :subtext="item.subtext"
|
|
|
+ :title="item.title"
|
|
|
+ :series="item.series"
|
|
|
+ :isDiaAlone="actCopList.length === 1"
|
|
|
+ @dblclick="funDbClick(item)"
|
|
|
+ :yAxis="item.yAxis"
|
|
|
+ :dataset="item.dataset"
|
|
|
+ :brush="item.isBrush"
|
|
|
+ @getSelected="funChartSelect"
|
|
|
+ ></component>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+ <el-dialog v-model="wtDialog" draggable>
|
|
|
+ <template #title>
|
|
|
+ <div class="dialog-title">
|
|
|
+ <div class="title">风机功率点位</div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <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="power-data-wrapper card-shadow wrapper">
|
|
|
+ <div class="card-title">数据展示</div>
|
|
|
+ <div class="data-wrapper">
|
|
|
+ <tree-cop
|
|
|
+ :data="processTreeData"
|
|
|
+ @currentChange="funProcessCurrentChange"
|
|
|
+ @refresh="funGetProcessTree"
|
|
|
+ ></tree-cop>
|
|
|
+ <excel-cop
|
|
|
+ :data="excelList"
|
|
|
+ :currentIds="currentId"
|
|
|
+ @excelChange="funExcelChange"
|
|
|
+ >
|
|
|
+ </excel-cop>
|
|
|
+ <div class="data-table-wrapper card-shadow">
|
|
|
+ <el-tabs v-model="activeTab" class="data-table-tabs">
|
|
|
+ <el-tab-pane label="温度与功率" name="1"> </el-tab-pane>
|
|
|
+ <el-tab-pane label="温度曲线" name="2"> </el-tab-pane>
|
|
|
+ <div
|
|
|
+ v-show="activeTab === '1'"
|
|
|
+ :style="{ height: tableHeight }"
|
|
|
+ class="data-chart-wrapper"
|
|
|
+ >
|
|
|
+ <div class="data-chart-item card-shadow">
|
|
|
+ <el-icon
|
|
|
+ class="zoom-icon"
|
|
|
+ size="18"
|
|
|
+ @click="
|
|
|
+ funActCop(
|
|
|
+ { xAxis: barxAxis, yAxis: baryAxis, series: barSeries },
|
|
|
+ 'barChartCop'
|
|
|
+ )
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <ZoomIn />
|
|
|
+ </el-icon>
|
|
|
+ <bar-chart-cop
|
|
|
+ width="calc(100% - 20px)"
|
|
|
+ height="100%"
|
|
|
+ :subtext="`平均功率-额定功率 ${powerproduction}`"
|
|
|
+ :xAxis="barxAxis"
|
|
|
+ :yAxis="baryAxis"
|
|
|
+ :series="barSeries"
|
|
|
+ ></bar-chart-cop>
|
|
|
+ </div>
|
|
|
+ <div class="data-chart-item card-shadow">
|
|
|
+ <el-icon
|
|
|
+ class="zoom-icon"
|
|
|
+ size="18"
|
|
|
+ @click="
|
|
|
+ funActCop(
|
|
|
+ {
|
|
|
+ xAxis: linexAxis,
|
|
|
+ yAxis: lineyAxis,
|
|
|
+ series: lineSeries,
|
|
|
+ },
|
|
|
+ 'lineChartCop'
|
|
|
+ )
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <ZoomIn />
|
|
|
+ </el-icon>
|
|
|
+ <line-chart-cop
|
|
|
+ class=""
|
|
|
+ height="100%"
|
|
|
+ width="calc(100% - 20px)"
|
|
|
+ :xAxis="linexAxis"
|
|
|
+ :yAxis="lineyAxis"
|
|
|
+ :series="lineSeries"
|
|
|
+ :subtext="`额定功率温度分析 ${powerproduction}`"
|
|
|
+ :dataset="lineDataSet"
|
|
|
+ ></line-chart-cop>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-if="activeTab === '2'" class="data-chart-wrapper">
|
|
|
+ <CurrentScatterChart
|
|
|
+ ref="chartRef"
|
|
|
+ width="100%"
|
|
|
+ height="100%"
|
|
|
+ :chartTitle="
|
|
|
+ avgObj.title +
|
|
|
+ ' ' +
|
|
|
+ '平均Cp值:' +
|
|
|
+ avgObj.cpavg +
|
|
|
+ '; 静风频率:' +
|
|
|
+ avgObj.frequency +
|
|
|
+ '%; 曲线偏差率:' +
|
|
|
+ avgObj.pcratio +
|
|
|
+ '%'
|
|
|
+ "
|
|
|
+ :xAxisData="xAxisData"
|
|
|
+ :yAxisData="{ splitLine: { show: false } }"
|
|
|
+ :seriesData="seriesData"
|
|
|
+ :showLegend="true"
|
|
|
+ :brushSelected="false"
|
|
|
+ :dataSet="dataSet"
|
|
|
+ @getSelected="funhotChartSelect"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </el-tabs>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<style lang="less" scoped>
|
|
|
+.power-data-wrapper {
|
|
|
+ height: 100%;
|
|
|
+ margin-top: 0;
|
|
|
+}
|
|
|
+.data-table-wrapper {
|
|
|
+ width: calc(62% - 40px) !important;
|
|
|
+}
|
|
|
+.el-tabs ::v-deep {
|
|
|
+ height: calc(100% - 22px);
|
|
|
+ .el-tabs__item {
|
|
|
+ color: #b3b3b3;
|
|
|
+ padding: 0 12px;
|
|
|
+ }
|
|
|
+ .el-tabs__nav-wrap::after {
|
|
|
+ background-color: #14221f;
|
|
|
+ }
|
|
|
+ .el-tabs__active-bar {
|
|
|
+ background-color: #05bb4c;
|
|
|
+ }
|
|
|
+ .el-tabs__item.is-active,
|
|
|
+ .el-tabs__item:hover {
|
|
|
+ color: #05bb4c;
|
|
|
+ }
|
|
|
+ .el-tabs__content {
|
|
|
+ height: calc(100% - 45px);
|
|
|
+ // .table-wrapper {
|
|
|
+ // width: 100%;
|
|
|
+ // }
|
|
|
+ .data-chart-wrapper {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ .data-chart-item {
|
|
|
+ height: calc(50% - 10px);
|
|
|
+ width: 100%;
|
|
|
+ padding: 10px;
|
|
|
+ position: relative;
|
|
|
+ .zoom-icon {
|
|
|
+ position: absolute;
|
|
|
+ top: 10px;
|
|
|
+ right: 10px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.el-select ::v-deep {
|
|
|
+ .el-select__tags {
|
|
|
+ max-width: unset !important;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|