|
@@ -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+ ' ' +'平均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>
|