Pārlūkot izejas kodu

2023-03-09 update

1. spaceAnalysis 增加右键菜单 功率曲线拟合  和 对风偏差分析
moccus 1 gadu atpakaļ
vecāks
revīzija
e34cf762ac

+ 1 - 1
src/pages/dataAnalysis/hotAnalysis/index.vue

@@ -154,7 +154,7 @@ const funCurrentChange = ({ current, currentNode }) => {
 const processTreeData = ref([])
 const funGetProcessTree = async () => { //flag控制是否获取tree的第一项 true为可获取
 	actTreeNode.value = null
-	const res = await request.get("/power/fitting/tree")
+	const res = await request.get("/power/process/tree")
 	excelList.value = []
 	processTreeData.value = funRepeatMap(res.data) //flag控制对actTreeNode赋值
 	if(actTreeNode.value){

+ 54 - 21
src/pages/dataAnalysis/posAnalysis/components/posChart.vue

@@ -1,9 +1,10 @@
 <script setup name="posChart">
-import { onMounted, ref, shallowRef, defineProps, watch } from 'vue'
+import { ref, reactive, shallowRef, defineProps, watch, nextTick, onActivated, defineEmits } from 'vue'
 import AMapLoader from '@amap/amap-jsapi-loader';
 import { ElMessage } from 'element-plus';
 import request from '@/api/axios.js'
 // import stationPosRes from './stationPos.json'
+const emits = defineEmits(['rightClick'])
 const map = shallowRef(null);
 const aMap = ref(null)
 const container = ref()
@@ -68,7 +69,9 @@ const props = defineProps({
 		default: '100%'
 	}
 })
-
+/** 右键后对象数据的接收 */
+const rightObj = ref(null)
+/**监听windList */
 watch(() => props.windList, (val) => {
 	if(val && val.length){
 		map.value.clearMap()
@@ -80,27 +83,50 @@ watch(() => props.windList, (val) => {
 			});
 			//创建右键菜单
 			const contextMenu = new aMap.value.ContextMenu();
-
+			// {
+			// 		"id": "NG01_05",
+			// 		"code": "NG01-05",
+			// 		"windpowerstationid": "NSS_FDC",
+			// 		"longitude": 106.0223579,
+			// 		"latitude": 37.74820326,
+			// 		"modelid": "UP82",
+			// 		"status": "NG01_005",
+			// 		"projectid": "NSS01_GC",
+			// 		"lineid": "NSS01_XL",
+			// 		"firstintegratedtime": "2011-12-01 00:00:00",
+			// 		"photo": null,
+			// 		"name": "牛首山05号风机",
+			// 		"standardid": "NG01_05",
+			// 		"prepareId": null,
+			// 		"processId": "1077593559936270336",
+			// 		"fittingId": "1078321689411977217"
+			// }
+			/**右键菜单可根据props中传参定义 */
 			//右键1
 			contextMenu.addItem("功率曲线拟合",  (e) => {
-				console.log(e)
-					
+				console.log(rightObj.value)
+				// funCombineGet(rightObj.value)
+				emits('rightClick', {
+					menuIndex: 0,
+					current: rightObj.value,
+				})
 			}, 0);
 
 			//右键2
 			contextMenu.addItem("对风偏差分析", () => {
-					
+				emits('rightClick', {
+					menuIndex: 1,
+					current: rightObj.value,
+				})
 			}, 1);
 
 			//右键2
-			contextMenu.addItem("曲线偏差率分析", () => {
-					
+			contextMenu.addItem("温度与功率分析", () => {
+				emits('rightClick', {
+					menuIndex: 2,
+					current: rightObj.value
+				})
 			}, 2);
-
-			//绑定鼠标右击事件——弹出右键菜单
-			marker.on('rightclick', function (e) {
-					contextMenu.open(map, e);
-			});
 			map.value.add(marker)
 			// marker.setTitle(item.name);
 			// 设置label标签
@@ -110,12 +136,17 @@ watch(() => props.windList, (val) => {
 				offset: new aMap.value.Pixel(10, 0),  //设置文本标注偏移量
 				content: `${item.name}`, //设置文本标注内容
 			});
+			//绑定鼠标右击事件——弹出右键菜单
+			marker.on('rightclick', function (e) {
+				rightObj.value = item
+				contextMenu.open(map.value, e.lnglat);
+			});
 		})
 		map.value.setFitView()
 		setTimeout(() => {
 			let zoom = map.value.getZoom()
-			if(zoom > 15){
-				zoom = 15
+			if(zoom > 16){
+				zoom = 16
 				map.value.setZoom(zoom)
 			}
 		},1000)
@@ -124,12 +155,14 @@ watch(() => props.windList, (val) => {
 	}
 })
 //created
-funMapSet(mapStatus => {
-	if(!mapStatus){
-		ElMessage.error('地图未加载成功, 请刷新重试或检查网络!')
-		return false
-	}
-	funStationPos()
+onActivated(() => {
+	funMapSet(mapStatus => {
+		if(!mapStatus){
+			ElMessage.error('地图未加载成功, 请刷新重试或检查网络!')
+			return false
+		}
+		funStationPos()
+	})
 })
 </script>
 <template>

+ 855 - 26
src/pages/dataAnalysis/posAnalysis/index.vue

@@ -1,10 +1,18 @@
 <script setup name="prepare">
 import excelCop from '@/components/excel.vue'
 import treeCop from '@/components/tree.vue'
-import { ref, nextTick, onActivated, onMounted, reactive } from 'vue'
+import { ref, nextTick, onActivated, shallowRef, onMounted, reactive } from 'vue'
 import request from '@/api/axios.js'
 import { ElMessage } from 'element-plus'
+import tools from '@tools/htmlToPdf.js'
 import posChart from './components/posChart.vue'
+/**combine */
+import combineChart from '@/pages/dataAnalysis/combine/components/current-scatter-chart.vue'
+/**rateAnalysis */
+import chartCop from '@/pages/dataAnalysis/rateAnalysis/components/chart.vue'
+import lineChartCop from '@/pages/dataAnalysis/rateAnalysis/components/lineChart.vue'
+import SubmitBtn from '@/components/SubmitBtn.vue'
+import scatterSingleChartCop from '@/pages/dataAnalysis/rateAnalysis/components/scatterSingleChart.vue'
 /**配置参数 */
 const treeHeight = ref(window.innerHeight - 160 + 'px') //tree高度
 const excelHeight = ref(window.innerHeight - 160 + 'px') //excel高度
@@ -47,14 +55,14 @@ const funGetTree = async () => {
 	const res = await request.get("/power/fitting/tree")
 	treeData.value = funRepeatMap(res.data)
 	excelList.value = []
-	if(actTreeNode.value){
-		funCurrentChange({current: actTreeNode.value, currentNode: null})
-		if(treeCopRef.value){
-			treeCopRef.value.setCheckedKeys([actTreeNode.value.id])
-			excelCheckIds.value = actTreeNode.value.childs.map(o => o.id)
-			funSubmit()
-		}
-	}
+	// if(actTreeNode.value){
+	// 	funCurrentChange({current: actTreeNode.value, currentNode: null})
+	// 	if(treeCopRef.value){
+	// 		treeCopRef.value.setCheckedKeys([actTreeNode.value.id])
+	// 		excelCheckIds.value = actTreeNode.value.childs.map(o => o.id)
+	// 		funSubmit()
+	// 	}
+	// }
 }
 const funCurrentChange = ({ current, currentNode }) => {
 	excelCheckboxShow.value = true
@@ -72,26 +80,30 @@ const funCurrentChange = ({ current, currentNode }) => {
 				name: o.path.substring(o.path.indexOf(o.station + '_') + (o.station + '_').length)
 			}
 		})
+		excelCheckIds.value = current.childs.map(o => o.id)
+		funSubmit()
 	} else {
 		excelList.value = []
+		excelCheckIds.value = []
+		windList.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)
-				}
-			}
-		}
-	}else{
-		windList.value = []
-	}
-	excelCheckIds.value = checkIds
-	funSubmit()
+	// 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)
+	// 			}
+	// 		}
+	// 	}
+	// }else{
+	// 	windList.value = []
+	// }
+	// excelCheckIds.value = checkIds
+	// funSubmit()
 }
 
 /**search 开始 */
@@ -113,6 +125,745 @@ const funSubmit = async () => {
 
 /**posChart */
 const windList = ref([])
+const funRightClick = ({menuIndex, current}) => {
+	switch(menuIndex){
+		case 0:
+			funCombineGet(current)
+			break;
+		case 1: 
+			funRateSubmit(current)
+			queryForm.checkIds = windList.value.map(o => o.processId)
+			break;
+	}
+}
+
+/**combine-chart */
+const combineDialog = ref(false)
+const avgObj = reactive({ //平均cpz等
+	title: '',
+	cpavg: '',
+	frequency: '',
+	pcratio: ''
+})
+const markDot = reactive({ //3-5 point点等
+	pcl5: null,
+	pcl10: null,
+	pcl12: null,
+	pcl25: null
+})
+const combine = reactive({
+	xAxisData: [],
+	seriesData: [],
+	dataSet: '',
+	isChartArea: false
+})
+const wtDialog = ref(false)
+const wtData = ref([])
+const wtTab = ref('table')
+
+const funCombineChartSelect = async (batch) => {
+	const wDataArr = []
+	const yDataArr = []
+	let scatterls = []
+	let scatterhs = []
+	let dataSetObj = []
+	wtData.value = []
+	if (batch?.length && combine.dataSet) {
+		scatterls = batch[0].selected[2].dataIndex
+		scatterhs = batch[0].selected[3].dataIndex
+		if (scatterls?.length || scatterhs?.length) {
+			dataSetObj = JSON.parse(combine.dataSet)
+			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 funCombineGet = async (obj) => { //点击excel项时
+	combine.isChartArea = false
+	let res = null
+	let chartRes = {
+		scatterhs: [[]],
+		scatterls: [[]],
+		sjgl: [[]],
+		llgl: [[]],
+		cpz: [[]]
+	}
+	const chartResponse = await request.get('/power/fitting/curve', { params: { id: obj.fittingId, p: 1 } })
+	if (chartResponse && chartResponse.code === 200) {
+		combineDialog.value = true
+		nextTick(() => {
+			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)
+			combine.dataSet = JSON.stringify([
+				{
+					source: chartRes.wyd
+					// source: chartRes.scatterls
+				},
+				{
+					source: chartRes.yyd
+					// source: chartRes.scatterhs
+				}
+			])
+			const color = ["#1C99FF", "#FF8700", "#3D54BE", "#fa8c16", "#1DA0D7", "#DD5044"]
+			combine.seriesData = [
+				{
+					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: 0,
+					encode: {
+						x: 'x',
+						y: 'y'
+					},
+					xAxisIndex: 0,
+					yAxisIndex: 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'
+					},
+					xAxisIndex: 0,
+					yAxisIndex: 0,
+				},
+				{
+					name: "Cp值",
+					type: "line",
+					symbol: "line", //设定为实心点
+					symbolSize: 0, //设定实心点的大小
+					smooth: true, //这个是把线变成曲线
+					data: chartRes.cpz,
+					xAxisIndex: 0,
+					yAxisIndex: 1,
+				},
+			]
+		})
+	}
+}
+
+/**rateAnalysis chart */
+const funText = (index) => {
+	let str = ''
+	switch (index) {
+		case 0:
+			str = '0-2.5'
+			break
+		case 1:
+			str = '2.5-5'
+			break
+		case 2:
+			str = '5-7.5'
+			break
+		case 3:
+			str = '7.5-10'
+			break
+		case 4:
+			str = '10-12.5'
+			break
+		case 5:
+			str = '12.5-15'
+			break
+		case 6:
+			str = '15-17.5'
+			break
+		case 7:
+			str = '17.5-20'
+			break
+		case 8:
+			str = '20-22.5'
+			break
+		case 9:
+			str = '22.5-25'
+			break
+		case 10:
+			str = '25-inf'
+			break
+	}
+	return str
+}
+const scatterxData = ref([
+	{
+		type: 'category',
+		name: '度',
+		data:  new Array(61).fill(-30).map((o,index) => Number((o + index))),
+		boundaryGap: false,
+		splitLine: {
+			show: true
+		},
+		axisLine: {
+			show: true
+		}
+	}
+])
+const scatteryData = ref([
+	{
+		type: 'category',
+		data: [5,6,7,8,9,10],
+		axisLine: {
+			show: false
+		},
+		name: 'm/s',
+		splitLine: {
+			show: false
+		},
+	},
+])
+const scatterSeries = ref(
+	[
+				{
+					name: '对风偏航',
+					type: 'scatter',
+					symbolSize: function (val) {
+						return val[2];
+					},
+					data: [],
+					markLine: {
+							symbol: 'none',
+							label: {
+								show: false,
+							},
+							lineStyle: {
+								color: '#F72C5B',
+								width: '3',
+							},
+							data: [
+								{
+								// yAxis: powerproductionNum.value,
+								}
+							]
+					},
+					animationDelay: function (idx) {
+						return idx * 5;
+					}
+				}
+			]
+)
+const chartData = ref([]) //roses的chartList
+let chartId = 1
+/**submit */
+const funRateSubmit = async (obj) => {
+	const rosesRes = await request.get('/wind/roses', {
+		params: {
+			ids: obj.processId,
+			mode: 0
+		}
+	})
+	const lineRes = await request.get('/wind/deviation/ratio', {
+		params: {
+			ids: obj.processId,
+			mode: 0
+		}
+	})
+	if (rosesRes.code === 200) {
+		if (rosesRes.data?.length) {
+			rateDialog.value = true
+			nextTick(() => {
+				chartData.value = []
+				for (const chart of rosesRes.data) {
+					chartData.value.push({
+						id: chartId,
+						title: '',
+						subtext: '风速风向玫瑰图',
+						xAxis: {
+							type: 'category',
+							boundaryGap: false,
+							data: ['N','', 'N-E','', 'E','', 'S-E','', 'S','', 'S-W','', 'W','', 'W-N',''],
+							splitLine: {
+								show: true
+							},
+						},
+						isRadar: false,
+						series: chart.roses?.length ?chart.roses.map((o, index) => {
+							return {
+								type: 'bar',
+								data: o,
+								coordinateSystem: 'polar',
+								name: funText(index),
+								stack: 'a',
+								emphasis: {
+									focus: 'series'
+								}
+							}
+						}): []
+					})
+					chartId++
+					chartData.value.push({
+						id: chartId,
+						title: '',
+						subtext: '风速风向频次玫瑰图',
+						isRadar: true,
+						xAxis: {
+							type: 'category',
+							boundaryGap: false,
+							data: ['N','', 'N-E','', 'E','', 'S-E','', 'S','', 'S-W','', 'W','', 'W-N',''],
+							splitLine: {
+								show: true
+							}
+						},
+						series: chart.count?.length? [...chart.count.map((o,index) => {
+									return {
+										type: 'bar',
+										data: o,
+										coordinateSystem: 'polar',
+										name: funText(index),
+										stack: 'a',
+										emphasis: {
+											focus: 'series'
+										}
+									}
+								}), {
+									type: 'radar',
+									// coordinateSystem: 'polar',
+									tooltip: {
+										trigger: 'item',
+									},
+									// smooth: true,
+									// areaStyle: {},
+									name: '对风',
+									data: [{
+										value: chart.radar,
+									}],
+								}]: []
+					})
+					chartId++
+					scatterSeries.value[0].data = chart.frequency.data?.length? chart.frequency.data.map((item) => {
+							return [item[1]+'', item[0]+'', (item[2]*15).toFixed(1)];
+					}) : []
+					scatterSeries.value[0].markLine.data = [{
+						xAxis: `${chart.frequency.avg}`,
+						name: `平均偏航:${chart.frequency.avg}度`,
+					}]
+				}
+			})
+		}
+	}
+	if(lineRes.code === 200){
+		if(lineRes.data?.length){
+			lineDataSet.value[0].source = lineRes.data[0].scatter.map(o => {
+				return [o.x+'', o.y]
+			})
+			lineSeries.value = [{
+				name: "对风频次",
+				type: "line",
+				symbol: "line", //设定为实心点
+				symbolSize: 0, //设定实心点的大小
+				smooth: true, //这个是把线变成曲线
+				data: lineRes.data[0].count,
+				yAxisIndex: 1,
+			},
+			{
+				type: 'effectScatter',
+				showEffectOn: "emphasis",
+				
+				rippleEffect: {
+					scale: 1
+				},
+				legendHoverLink: false,
+				name: '数据散点',
+				symbolSize: 5,
+				datasetIndex: 0,
+				encode: {
+					x: 'x',
+					y: 'y'
+				},
+				yAxisIndex: 0,
+			}]
+		}
+	}
+}
+/**lineChart */
+const linexAxis = ref({
+	type: 'category',
+	data: new Array(101).fill(-50).map((o,index) => Number((o + index).toFixed(1))),
+	splitLine: {
+		show: false
+	},
+	axisTick: {
+		show: true
+	}
+})
+const lineyAxis = ref([
+	{
+		type: 'value',
+		name: 'm/s',
+		splitLine: {
+		show: false
+	},
+	axisTick: {
+		show: true
+	}
+	},{
+		type: 'value',
+		name: '频次',
+		splitLine: {
+		show: false
+	},
+	axisTick: {
+		show: true
+	}
+	}
+])
+const lineSeries = ref([])
+const lineDataSet = ref([
+	{
+		source: []
+	}
+])
+/** rate dialog */
+const rateDialog = ref(false)
+const dbRateDialog = 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 = windList.value.map(o => o.processId)
+	}else{
+		queryForm.checkIds = []
+	}
+}
+const funActCop = (obj, type) => {
+	switch(type){
+		case 'chartCop1':
+			actChartName.value = 'chartCop1'
+			obj.actCop = shallowRef(chartCop)
+			actDiaTitle.value = '风速风向玫瑰图'
+			break
+		case 'chartCop2':
+			actChartName.value = 'chartCop2'
+			obj.actCop = shallowRef(chartCop)
+			actDiaTitle.value = '风速风向频次玫瑰图'
+			break
+		case 'lineChartCop':
+			actChartName.value = 'lineChartCop'
+			obj.actCop = shallowRef(lineChartCop)
+			actDiaTitle.value = '对风偏差分析图'
+			break
+		case 'scatterSingleChartCop':
+			actChartName.value = 'scatterSingleChartCop'
+			obj.actCop = shallowRef(scatterSingleChartCop)
+			actDiaTitle.value = '静态偏航对风分析图'
+			break
+	}
+	obj.isBrush = type === 'lineChartCop' ? false :false
+	obj.id = chartId
+	chartId ++
+	dbRateDialog.value = true
+	actCopListBak.value = []
+	nextTick(() => {
+		actCopList.value = [obj]
+	})
+}
+const funDiaSubmit = async () => {
+	let url = ''
+	switch(actChartName.value){
+		case 'chartCop1':
+			url = '/wind/roses'
+			break
+		case 'chartCop2':
+			url = '/wind/roses'
+			break
+		case 'lineChartCop':
+			url = '/wind/deviation/ratio'
+			break
+		case 'scatterSingleChartCop':
+			url = '/wind/roses'
+			break
+	}
+	if(url){
+		const res = await request.get(url, {
+			params: {
+				ids: queryForm.checkIds.join(','),
+				mode: 0
+			}
+		})
+		if(res.code===200){
+			actCopList.value = []
+			actCopListBak.value = [] //清空备份
+			if(res.data?.length){
+				for(const chart of res.data){
+					if(actChartName.value==='chartCop1'){
+						actCopList.value.push({
+							id: chartId,
+							isBrush: false,
+							actCop: shallowRef(chartCop),
+							title: chart.wt,
+							subtext: '风速风向玫瑰图',
+							xAxis: {
+								type: 'category',
+								boundaryGap: false,
+								data: ['N','', 'N-E','', 'E','', 'S-E','', 'S','', 'S-W','', 'W','', 'W-N',''],
+								splitLine: {
+									show: true
+								},
+							},
+							isRadar: false,
+							series: chart.roses?.length ?chart.roses.map((o, index) => {
+								return {
+									type: 'bar',
+									data: o,
+									coordinateSystem: 'polar',
+									name: funText(index),
+									stack: 'a',
+									emphasis: {
+										focus: 'series'
+									}
+								}
+							}): []
+						})
+						chartId++
+					}
+					if(actChartName.value === 'chartCop2'){
+						actCopList.value.push({
+							id: chartId,
+							isBrush: false,
+							actCop: shallowRef(chartCop),
+							title: chart.wt,
+							subtext: '风速风向频次玫瑰图',
+							xAxis: {
+								type: 'category',
+								boundaryGap: false,
+								data: ['N','', 'N-E','', 'E','', 'S-E','', 'S','', 'S-W','', 'W','', 'W-N',''],
+								splitLine: {
+									show: true
+								}
+							},
+							isRadar: true,
+							series: chart.count?.length? [...chart.count.map((o,index) => {
+									return {
+										type: 'bar',
+										data: o,
+										coordinateSystem: 'polar',
+										name: funText(index),
+										stack: 'a',
+										emphasis: {
+											focus: 'series'
+										}
+									}
+								}), {
+								type: 'radar',
+								// coordinateSystem: 'polar',
+								tooltip: {
+									trigger: 'item'
+								},
+								// smooth: true,
+								// areaStyle: {},
+								name: '对风',
+								data: [{
+									value: chart.radar,
+								}],
+							}]: []
+						})
+						chartId++
+					}
+					if(actChartName.value === 'lineChartCop'){
+						actCopList.value.push({
+							id: chartId,
+							isBrush: false,
+							actCop: shallowRef(lineChartCop),
+							title: chart.wtId,
+							subtext: '对风偏差分析图',
+							xAxis: linexAxis.value,
+							yAxis: lineyAxis.value,
+							dataset: [{
+								source: chart.scatter.map(o => {
+									return [o.x+'', o.y]
+								})
+							}],
+							isRadar: false,
+							series: [{
+								name: "对风频次",
+								type: "line",
+								symbol: "line", //设定为实心点
+								symbolSize: 0, //设定实心点的大小
+								smooth: true, //这个是把线变成曲线
+								data: chart.count,
+								yAxisIndex: 1,
+							},
+							{
+								type: 'effectScatter',
+								showEffectOn: "emphasis",
+								
+								rippleEffect: {
+									scale: 1
+								},
+								legendHoverLink: false,
+								name: '数据散点',
+								symbolSize: 5,
+								datasetIndex: 0,
+								encode: {
+									x: 'x',
+									y: 'y'
+								},
+								yAxisIndex: 0,
+							}]
+
+						})
+						chartId++
+					}
+					if(actChartName.value === 'scatterSingleChartCop'){
+						actCopList.value.push({
+							id: chartId,
+							isBrush: false,
+							actCop: shallowRef(scatterSingleChartCop),
+							title: chart.wt,
+							subtext: '静态偏航对风分析图',
+							xAxis: scatterxData.value,
+							yAxis: scatteryData.value,
+							isRadar: false,
+							series: [
+								{
+									name: '对风偏航',
+									type: 'scatter',
+									symbolSize: function (val) {
+										return val[2];
+									},
+									markLine: {
+											symbol: 'none',
+											label: {
+												show: false,
+											},
+											lineStyle: {
+												color: '#F72C5B',
+												width: '3'
+											},
+											data: [
+												{
+													name: `平均偏航:${chart.frequency.avg}度`,
+													xAxis: `${chart.frequency.avg}`,
+												}
+											]
+									},
+									data: chart.frequency.data?.length? chart.frequency.data.map((item) => {
+											return [item[1]+'', item[0]+'', (item[2]*15).toFixed(1)];
+									}) : [],
+									animationDelay: function (idx) {
+										return idx * 5;
+									}
+								}
+							]
+						})
+						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]
+		}
+	}
+}
 
 /**mounted */
 onMounted(() => {
@@ -138,6 +889,84 @@ onActivated(() => {
 </script>
 <template>
   <div class="bg-white py-[10px] px-[10px] s-dialog-body">
+		<el-dialog draggable width="80%" v-model="dbRateDialog" :title="actDiaTitle">
+			<el-form class="whitespace-nowrap" :inline="true" :model="queryForm">
+				<el-form-item label="" class="!mb-0">
+					<el-select v-model="queryForm.checkIds" clearable @clear="checkAll = false" collapse-tags multiple>
+						<el-option label="全选" :class="{'selected': checkAll}" @click="funCheckAll"></el-option>
+						<el-option v-for="item in windList" :key="item.processId" :value="item.processId" :label="item.name"></el-option>
+					</el-select>
+				</el-form-item>
+				<el-form-item class="!mb-0">
+					<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" class="flex flex-wrap justify-center items-center h-[650px] overflow-y-auto overflow-x-hidden">
+					<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" :isRadar="item.isRadar" :title="item.title"
+						:series="item.series" :isDiaAlone="(actCopList.length === 1)" @dblclick="funDbClick(item)" :yAxis="item.yAxis" :dataset="item.dataset" :brush="item.isBrush"></component>
+				</div>
+			</div>
+		</el-dialog>
+		<el-dialog title="对风偏差分析" draggable width="1200px" top="100px" v-model="rateDialog">
+			<div :style="{ height: '793px' }"
+				class="flex flex-wrap justify-center items-center overflow-x-hidden overflow-y-auto ">
+				<div class="mb-[10px] w-[49%] h-[49%] flex flex-col items-end shadow rounded-[6px] shadow-blue-500"
+					v-for="(item, index) in chartData" :key="item.id" :class="{ 'mr-[10px]': index % 2 === 0 }">
+					<el-icon class="mr-[10px] mt-[10px] cursor-pointer" size="18"
+						@click="funActCop(item, 'chartCop' + (index + 1))">
+						<ZoomIn />
+					</el-icon>
+					<chart-cop class="" height="100%" width="100%" :xAxis="item.xAxis" :isRadar="item.isRadar" :subtext="item.subtext"
+						:title="item.title" :series="item.series">
+					</chart-cop>
+				</div>
+				<div class="mr-[10px] w-[49%] h-[49%] flex flex-col items-end shadow rounded-[6px] shadow-blue-500" v-if="!!lineSeries.length">
+					<el-icon class="mr-[10px] mt-[10px] cursor-pointer" size="18"
+						@click="funActCop({ xAxis: linexAxis, yAxis: lineyAxis, series: lineSeries, dataset: lineDataSet }, 'lineChartCop')">
+						<ZoomIn />
+					</el-icon>
+					<line-chart-cop class="" height="100%" width="100%" :xAxis="linexAxis" :yAxis="lineyAxis"
+						:series="lineSeries" subtext="对风偏差分析图" :dataset="lineDataSet"></line-chart-cop>
+				</div>
+				<div class="w-[49%] h-[49%] flex flex-col items-end shadow rounded-[6px] shadow-blue-500" v-if="!!lineSeries.length">
+					<el-icon class="mr-[10px] mt-[10px] cursor-pointer" size="18"
+						@click="funActCop({ xAxis: scatterxData, yAxis: scatteryData, series: scatterSeries }, 'scatterSingleChartCop')">
+						<ZoomIn />
+					</el-icon>
+					<scatter-single-chart-cop class="" height="100%" width="100%" :xAxis="scatterxData" :yAxis="scatteryData"
+						:series="scatterSeries" subtext="静态偏航对风分析图"></scatter-single-chart-cop>
+				</div>
+			</div>
+		</el-dialog>
+		<el-dialog title="功率曲线拟合" draggable width="1200px" v-model="combineDialog">
+			<combineChart width="100%" height="650px" :chartTitle="avgObj.title+ '&nbsp;&nbsp;' +'平均Cp值:'+avgObj.cpavg+'; 静风频率:'+avgObj.frequency+'%; 曲线偏差率:'+avgObj.pcratio+'%'"
+									:xAxisData="combine.xAxisData" :yAxisData="{ splitLine: { show: false } }" :seriesData="combine.seriesData"
+									:showLegend="true" :brushSelected="!combine.isChartArea" :dataSet="combine.dataSet" @getSelected="funCombineChartSelect" ></combineChart>
+		</el-dialog>
+		<!-- 功率曲线拟合的圈选功能 -->
+		<el-dialog v-model="wtDialog" draggable title="风机功率点位">
+			<el-tabs v-model="wtTab">
+				<el-tab-pane label="数据" name="table">
+					<el-table :data="wtData" default-expand-all 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
@@ -158,7 +987,7 @@ onActivated(() => {
 						ref="treeCopRef" 
             :data="treeData"
             @checkChange="funTreeCheckChange"
-            :show-checkbox="true"
+            :show-checkbox="false"
             :height="treeHeight"
             @currentChange="funCurrentChange"
             @refresh="funGetTree"
@@ -185,7 +1014,7 @@ onActivated(() => {
 								overflow: 'hidden'
               }"
             >
-							<posChart :height="typeof tableHeight === 'string' ? `calc(${tableHeight})` : tableHeight + 'px'" :windList="windList"></posChart>
+							<posChart @rightClick="funRightClick" :height="typeof tableHeight === 'string' ? `calc(${tableHeight})` : tableHeight + 'px'" :windList="windList"></posChart>
             </div>
           </div>
         </el-col>

+ 1 - 1
src/pages/dataAnalysis/spaceAnalysis/index.vue

@@ -56,7 +56,7 @@ const funRepeatMap = (arr) => {
 	})
 }
 const funGetTree = async () => {
-	const res = await request.get("/power/prepare/tree")
+	const res = await request.get("/power/process/tree")
 	actTreeNode.value = null
 	excelList.value = []
 	treeData.value = funRepeatMap(res.data)