index.vue 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405
  1. <template>
  2. <div class="dataAnalysisPosAnal" :class="!theme ? 'themeDark' : 'themeLight'">
  3. <div class="dataAnalysisPosAnalMain">
  4. <div class="main_top">
  5. <p class="topPsty">微观选址分析</p>
  6. </div>
  7. <div class="main">
  8. <div class="treeDataMain">
  9. <tree-cop ref="treeCopRef" :data="treeData" @checkChange="funTreeCheckChange" :show-checkbox="true"
  10. :height="treeHeight" @currentChange="funCurrentChange" @refresh="funGetTree"></tree-cop>
  11. </div>
  12. <div class="excelDataMain">
  13. <excel-cop :checkIds="excelCheckIds" :showCheckbox="excelCheckboxShow" :data="excelList"
  14. :theme="theme" :height="excelHeight" @excelChange="funExcelChange"
  15. @checkChange="funExcelCheckChange">
  16. </excel-cop>
  17. </div>
  18. <div class="tableDataMain">
  19. <div class="shadow rounded-[6px] shadow-blue-500 overflow-hidden">
  20. <div :style="{
  21. height:
  22. typeof tableHeight === 'string'
  23. ? tableHeight
  24. : tableHeight + 'px',
  25. overflow: 'hidden',
  26. }">
  27. <!-- <posChart @mapDone="funMapDone" @rightClick="funRightClick" :height="tableHeight"
  28. :windList="windList" :ids="excelCheckIds" v-if="showOnlineMap" /> -->
  29. <!-- v-if="showOnlineMap" -->
  30. <!-- <kMap :parentId="treeId" :ids="excelCheckIds" @mapDone="funMapDone"
  31. @rightClick="funRightClick" v-else /> -->
  32. <leafletMap :windList="windList" :ids="excelCheckIds" @mapDone="funMapDone"
  33. @rightClick="funRightClick" />
  34. </div>
  35. </div>
  36. </div>
  37. </div>
  38. </div>
  39. <el-dialog draggable width="80%" top="10px" v-model="dbRateDialog" :title="actDiaTitle"
  40. modal-class="rightMenuDialog">
  41. <el-form class="whitespace-nowrap" :inline="true" :model="queryForm">
  42. <el-form-item label="" class="!mb-0">
  43. <el-select v-model="queryForm.checkIds" clearable @clear="checkAll = false" collapse-tags multiple>
  44. <el-option label="全选" :class="{ selected: checkAll }" @click="funCheckAll"></el-option>
  45. <el-option v-for="item in windList" :key="item.processId" :value="item.processId"
  46. :label="item.name"></el-option>
  47. </el-select>
  48. </el-form-item>
  49. <el-form-item class="!mb-0">
  50. <submit-btn desc="查询" @click="funDiaSubmit"></submit-btn>
  51. <submit-btn desc="导出" @click="funDiaExport"></submit-btn>
  52. </el-form-item>
  53. </el-form>
  54. <div v-loading="exportLoading">
  55. <div style="height: 600px"
  56. class="flex flex-wrap justify-center items-center overflow-y-auto overflow-x-hidden"
  57. ref="diaPanelRef">
  58. <component :is="item.actCop" :width="`${100 / (actCopList.length || 1)}%`" height="100%"
  59. v-for="item in actCopList" :key="item.id" :xAxis="item.xAxis" :subtext="item.subtext"
  60. :isRadar="item.isRadar" :title="item.title" :series="item.series"
  61. :isDiaAlone="actCopList.length === 1" @dblclick="funDbClick(item)" :yAxis="item.yAxis"
  62. :dataset="item.dataset" :brush="item.isBrush"></component>
  63. </div>
  64. </div>
  65. </el-dialog>
  66. <el-dialog custom-class="windLifeDialog" title="对风偏差分析" draggable width="90%" top="25px" v-model="rateDialog">
  67. <el-row :style="{ height: '793px' }">
  68. <el-col :span="12" v-for="(item, index) in chartData" :key="item.id" style="height: 45%">
  69. <el-icon :style="!theme ? 'color: #fff' : ''" size="18"
  70. @click="funActCop(item, 'chartCop' + (index + 1))">
  71. <ZoomIn />
  72. </el-icon>
  73. <chart-cop class="" height="100%" width="100%" :xAxis="item.xAxis" :isRadar="item.isRadar"
  74. :theme="theme" :echartsTheme="echartsTheme" :subtext="item.subtext" :title="item.title"
  75. :series="item.series">
  76. </chart-cop>
  77. </el-col>
  78. <el-col :span="12" v-if="!!lineSeries.length" style="height: 50%">
  79. <el-icon :style="!theme ? 'color: #fff' : ''" size="18"
  80. @click="funActCop({ xAxis: linexAxis, yAxis: lineyAxis, series: lineSeries, dataset: lineDataSet }, 'lineChartCop')">
  81. <ZoomIn />
  82. </el-icon>
  83. <line-chart-cop class="" height="100%" width="100%" :xAxis="linexAxis" :yAxis="lineyAxis"
  84. :theme="theme" :echartsTheme="echartsTheme" :series="lineSeries" subtext="对风偏差分析图"
  85. :dataset="lineDataSet"></line-chart-cop>
  86. </el-col>
  87. <el-col :span="12" v-if="!!lineSeries.length" style="height: 50%">
  88. <el-icon :style="!theme ? 'color: #fff' : ''" size="18"
  89. @click="funActCop({ xAxis: scatterxData, yAxis: scatteryData, series: scatterSeries }, 'scatterSingleChartCop')">
  90. <ZoomIn />
  91. </el-icon>
  92. <scatter-single-chart-cop class="" height="95%" width="100%" :xAxis="scatterxData" :theme="theme"
  93. :echartsTheme="echartsTheme" :yAxis="scatteryData" :series="scatterSeries" subtext="静态偏航对风分析图">
  94. </scatter-single-chart-cop>
  95. </el-col>
  96. </el-row>
  97. </el-dialog>
  98. <el-dialog custom-class="windLifeDialog" title="功率曲线拟合" draggable width="90%" top="25px"
  99. modal-class="rightMenuDialog" v-model="combineDialog">
  100. <combineChart width="100%" height="600px" :chartTitle="
  101. avgObj.title +
  102. '&nbsp;&nbsp;' +
  103. '平均Cp值:' +
  104. avgObj.cpavg +
  105. '; 静风频率:' +
  106. avgObj.frequency +
  107. '%; 曲线偏差率:' +
  108. avgObj.pcratio +
  109. '%'
  110. " :xAxisData="combine.xAxisData" :yAxisData="{ splitLine: { show: false } }" :seriesData="combine.seriesData"
  111. :theme="theme" :echartsTheme="echartsTheme" :showLegend="true" :brushSelected="!combine.isChartArea"
  112. :dataSet="combine.dataSet" @getSelected="funCombineChartSelect"></combineChart>
  113. </el-dialog>
  114. <!-- 功率曲线拟合的圈选功能 -->
  115. <el-dialog v-model="wtDialog" draggable title="风机功率点位">
  116. <el-tabs v-model="wtTab">
  117. <el-tab-pane label="数据" name="table">
  118. <el-table :data="wtData" default-expand-all row-key="id" :max-height="550">
  119. <el-table-column property="wtId" align="center" label="风机" />
  120. <el-table-column property="time" sortable :width="160" align="center" label="时间" />
  121. <el-table-column property="speed" sortable align="center" label="风速(m/s)" />
  122. <el-table-column property="power" sortable align="center" label="功率(kW)" />
  123. <el-table-column property="rr" sortable align="center" label="转速" />
  124. <el-table-column property="filter" sortable align="center" label="是否有用点" />
  125. </el-table>
  126. </el-tab-pane>
  127. <el-tab-pane label="故障" name="problem" disabled> </el-tab-pane>
  128. <el-tab-pane label="预警" name="warning" disabled> </el-tab-pane>
  129. </el-tabs>
  130. </el-dialog>
  131. </div>
  132. </template>
  133. <script setup name="prepare">
  134. import excelCop from '@/components/generatingCapacityComponent/excel.vue'
  135. import treeCop from '@/components/generatingCapacityComponent/tree.vue'
  136. import {
  137. ref,
  138. nextTick,
  139. onActivated,
  140. shallowRef,
  141. onMounted,
  142. reactive,
  143. watch,
  144. } from "vue";
  145. import axios from "axios";
  146. import {
  147. useRouter
  148. } from "vue-router";
  149. import {
  150. useStore
  151. } from "vuex";
  152. import {
  153. ElMessage
  154. } from "element-plus";
  155. import tools from "@tools/htmlToPdf.js";
  156. import posChart from "./components/posChart.vue";
  157. import leafletMap from "./components/leafletMap.vue";
  158. /**combine */
  159. import combineChart from "../combine/components/current-scatter-chart.vue";
  160. /**rateAnalysis */
  161. import chartCop from "../rateAnalysis/components/chart.vue";
  162. import lineChartCop from "../rateAnalysis/components/lineChart.vue";
  163. import scatterSingleChartCop from "../rateAnalysis/components/scatterSingleChart.vue";
  164. import kMap from "@/components/generatingCapacityComponent/kMap/index.vue";
  165. import httpRequest from '@/utils/request.js'
  166. const router = useRouter();
  167. /**配置参数 */
  168. const treeHeight = ref(window.innerHeight - 115 + "px"); //tree高度
  169. const excelHeight = ref(window.innerHeight - 115 + "px"); //excel高度
  170. const tableHeight = ref(window.innerHeight - 115 + "px");
  171. /**excel 开始 */
  172. const excelCheckboxShow = ref(false);
  173. const excelCheckIds = ref([]);
  174. const excelList = ref([]);
  175. const store = useStore();
  176. const showOnlineMap = ref(false);
  177. watch(
  178. () => router.currentRoute.value,
  179. (newValue, oldValue) => {
  180. // if (newValue.path === "/dataAnalysis/posAnalysis") {
  181. if (newValue.path.indexOf("/dataAnalysis/posAnalysis") > -1) {
  182. if (newValue.query.onlineMap) {
  183. showOnlineMap.value = newValue.query.onlineMap === "1" ? false : true;
  184. }
  185. }
  186. }, {
  187. immediate: true
  188. }
  189. );
  190. const funExcelChange = async (obj) => {
  191. //点击excel项时
  192. return false;
  193. };
  194. const funExcelCheckChange = ({
  195. checkArr,
  196. data
  197. }) => {
  198. //bug
  199. excelCheckIds.value = checkArr;
  200. funSubmit();
  201. };
  202. /**prepare tree 开始 */
  203. const treeData = ref([]);
  204. const treeCopRef = ref(); //treeCop ref
  205. const actTreeNode = ref(null); //当前激活的treeNode
  206. const funRepeatMap = (arr, type = "fitting") => {
  207. return arr.map((o) => {
  208. if (o.children) {
  209. const findIndex = o.children.findIndex((p) => !!p.type);
  210. if (findIndex !== -1) {
  211. o.childs = o.children;
  212. o.children = [];
  213. if (!actTreeNode.value && type === "fitting") {
  214. //判断当且仅有process获取tree时 赋值
  215. actTreeNode.value = o;
  216. }
  217. }
  218. }
  219. return {
  220. ...o,
  221. children: o.children ? funRepeatMap(o.children, type) : [],
  222. };
  223. });
  224. };
  225. const funGetTree = async () => {
  226. actTreeNode.value = null;
  227. const res = await httpRequest.get("/power/fitting/tree");
  228. treeData.value = funRepeatMap(res.data);
  229. excelList.value = [];
  230. if (actTreeNode.value) {
  231. funCurrentChange({
  232. current: actTreeNode.value,
  233. currentNode: null
  234. });
  235. if (treeCopRef.value) {
  236. treeCopRef.value.$refs.tree.setCheckedKeys([actTreeNode.value.id]);
  237. excelCheckIds.value = actTreeNode.value.childs.map((o) => o.id);
  238. funSubmit();
  239. }
  240. }
  241. };
  242. const treeId = ref("");
  243. const funCurrentChange = ({
  244. current,
  245. currentNode
  246. }) => {
  247. excelCheckboxShow.value = true;
  248. if (current.childs) {
  249. excelList.value = current.childs.map((o) => {
  250. return {
  251. id: o.id,
  252. interval: o.interval,
  253. path: o.path,
  254. prepareid: o.prepareid,
  255. station: o.station,
  256. time: o.time,
  257. type: o.type,
  258. windturbine: o.windturbine,
  259. name: o.path.substring(
  260. o.path.indexOf(o.station + "_") + (o.station + "_").length
  261. ),
  262. };
  263. });
  264. // excelCheckIds.value = current.childs.map((o) => o.id);
  265. // treeId.value = current.id || "";
  266. funSubmit();
  267. } else {
  268. excelList.value = [];
  269. excelCheckIds.value = [];
  270. windList.value = [];
  271. }
  272. };
  273. const funTreeCheckChange = ({
  274. current,
  275. checkedNodes,
  276. checkedKeys,
  277. halfCheckedNodes,
  278. halfCheckedKeys,
  279. }) => {
  280. funCurrentChange({
  281. current,
  282. currentNode: ''
  283. })
  284. const checkIds = []
  285. if (checkedNodes.checkedNodes.length) {
  286. let checkArr = checkedNodes.checkedNodes
  287. checkArr.forEach(it => {
  288. if (it.childs && it.childs.length) {
  289. it.childs.forEach(iv => {
  290. checkIds.push(iv.id)
  291. })
  292. }
  293. })
  294. }
  295. excelCheckIds.value = checkIds
  296. //tree change -> excel change
  297. // funCurrentChange({ current, currentNode: '' })
  298. // const checkIds = []
  299. // if (checkedNodes.length) {
  300. // for (const node of checkedNodes) {
  301. // if (node.childs && node.childs.length) {
  302. // for (const child of node.childs) {
  303. // checkIds.push(child.id)
  304. // }
  305. // }
  306. // }
  307. // }else{
  308. // windList.value = []
  309. // }
  310. // excelCheckIds.value = checkIds
  311. // funSubmit()
  312. };
  313. /**search 开始 */
  314. const funSubmit = async () => {
  315. // if (!excelCheckIds.value.length) {
  316. // ElMessage.error('请勾选要执行的项')
  317. // return false
  318. // }
  319. const params = {
  320. ids: excelCheckIds.value.join(","),
  321. };
  322. const res = await httpRequest.get("/base/location", {
  323. params: params
  324. });
  325. let windList = [];
  326. res.data.forEach((ele) => {
  327. if (ele.longitude && ele.latitude) {
  328. windList.push(ele);
  329. }
  330. });
  331. windList.value = windList;
  332. };
  333. /**posChart */
  334. const windList = ref([]);
  335. const funRightClick = ({
  336. menuIndex,
  337. current
  338. }) => {
  339. console.log({
  340. menuIndex,
  341. current
  342. });
  343. switch (menuIndex) {
  344. case 0:
  345. funCombineGet(current);
  346. break;
  347. case 1:
  348. funRateSubmit(current);
  349. queryForm.checkIds = windList.value.map((o) => o.processId);
  350. break;
  351. }
  352. };
  353. /**combine-chart */
  354. const combineDialog = ref(false);
  355. const avgObj = reactive({
  356. //平均cpz等
  357. title: "",
  358. cpavg: "",
  359. frequency: "",
  360. pcratio: "",
  361. });
  362. const markDot = reactive({
  363. //3-5 point点等
  364. pcl5: null,
  365. pcl10: null,
  366. pcl12: null,
  367. pcl25: null,
  368. });
  369. const combine = reactive({
  370. xAxisData: [],
  371. seriesData: [],
  372. dataSet: "",
  373. isChartArea: false,
  374. });
  375. const wtDialog = ref(false);
  376. const wtData = ref([]);
  377. const wtTab = ref("table");
  378. const funCombineChartSelect = async (batch) => {
  379. const wDataArr = [];
  380. const yDataArr = [];
  381. let scatterls = [];
  382. let scatterhs = [];
  383. let dataSetObj = [];
  384. wtData.value = [];
  385. if (batch.length && combine.dataSet) {
  386. scatterls = batch[0].selected[2].dataIndex;
  387. scatterhs = batch[0].selected[3].dataIndex;
  388. if (scatterls.length || scatterhs.length) {
  389. dataSetObj = JSON.parse(combine.dataSet);
  390. if (scatterls.length) {
  391. for (const scatterIndex of scatterls) {
  392. wDataArr.push(dataSetObj[0].source[scatterIndex].k);
  393. }
  394. }
  395. if (scatterhs.length) {
  396. for (const scatterIndex of scatterhs) {
  397. yDataArr.push(dataSetObj[1].source[scatterIndex].k);
  398. }
  399. }
  400. const wtRes = await httpRequest.get("/power/fitting/filter", {
  401. params: {
  402. yk: yDataArr.join(","),
  403. wk: wDataArr.join(",")
  404. },
  405. });
  406. if (wtRes.code === 200) {
  407. let id = 1;
  408. const tempArr = []; //用于以风机id 聚合dataArr
  409. if (wtRes.data.length) {
  410. for (const data of wtRes.data) {
  411. if (tempArr.length) {
  412. const findIndex = tempArr.findIndex((o) => o.wtId === data.wtId);
  413. if (findIndex !== -1) {
  414. if (!tempArr[findIndex].children) {
  415. tempArr[findIndex].children = [];
  416. }
  417. tempArr[findIndex].children.push({
  418. ...data,
  419. id: id,
  420. filter: data.filter === 0 ? "是" : "否",
  421. });
  422. id++;
  423. } else {
  424. tempArr.push({
  425. ...data,
  426. id: id,
  427. filter: data.filter === 0 ? "是" : "否",
  428. });
  429. id++;
  430. }
  431. } else {
  432. tempArr.push({
  433. ...data,
  434. id: id,
  435. filter: data.filter === 0 ? "是" : "否",
  436. });
  437. id++;
  438. }
  439. }
  440. wtDialog.value = true;
  441. nextTick(() => {
  442. wtTab.value = "table";
  443. wtData.value = tempArr;
  444. });
  445. }
  446. }
  447. }
  448. }
  449. };
  450. const funCombineGet = async (obj) => {
  451. //点击excel项时
  452. combine.isChartArea = false;
  453. let res = null;
  454. let chartRes = {
  455. scatterhs: [
  456. []
  457. ],
  458. scatterls: [
  459. []
  460. ],
  461. sjgl: [
  462. []
  463. ],
  464. llgl: [
  465. []
  466. ],
  467. cpz: [
  468. []
  469. ],
  470. };
  471. const chartResponse = await httpRequest.get("/power/fitting/curve", {
  472. params: {
  473. id: obj.fittingId,
  474. p: 1
  475. },
  476. });
  477. if (chartResponse && chartResponse.code === 200) {
  478. combineDialog.value = true;
  479. nextTick(() => {
  480. chartRes = chartResponse.data;
  481. markDot.pcl5 = chartRes.obj.pc5ratio;
  482. markDot.pcl10 = chartRes.obj.pc10ratio;
  483. markDot.pcl12 = chartRes.obj.pc12ratio;
  484. markDot.pcl25 = chartRes.obj.pc25ratio;
  485. avgObj.title = chartRes.obj.path
  486. .substring(
  487. chartRes.obj.path.indexOf(chartRes.obj.station + "_") +
  488. (chartRes.obj.station + "_").length
  489. )
  490. .split("_")[0];
  491. avgObj.cpavg = Number(chartRes.obj.cpavg).toFixed(2);
  492. avgObj.frequency = Number(chartRes.obj.frequency).toFixed(2);
  493. avgObj.pcratio = Number(chartRes.obj.pcratio).toFixed(2);
  494. combine.dataSet = JSON.stringify([{
  495. source: chartRes.wyd,
  496. // source: chartRes.scatterls
  497. },
  498. {
  499. source: chartRes.yyd,
  500. // source: chartRes.scatterhs
  501. },
  502. ]);
  503. const color = [
  504. "#1C99FF",
  505. "#FF8700",
  506. "#3D54BE",
  507. "#fa8c16",
  508. "#1DA0D7",
  509. "#DD5044",
  510. ];
  511. combine.seriesData = [{
  512. name: "拟合功率",
  513. type: "line",
  514. symbol: "line", //设定为实心点
  515. symbolSize: 0, //设定实心点的大小
  516. smooth: true, //这个是把线变成曲线
  517. data: chartRes.sjgl,
  518. xAxisIndex: 0,
  519. },
  520. {
  521. name: "保证功率",
  522. type: "line",
  523. symbol: "line", //设定为实心点
  524. symbolSize: 0, //设定实心点的大小
  525. smooth: true, //这个是把线变成曲线
  526. data: chartRes.llgl,
  527. xAxisIndex: 0,
  528. },
  529. {
  530. type: "effectScatter",
  531. showEffectOn: "emphasis",
  532. rippleEffect: {
  533. scale: 1,
  534. },
  535. name: "无用点",
  536. symbolSize: (data) => {
  537. return data.s ? (data.s > 10 ? 10 : data.s) : 4;
  538. },
  539. datasetIndex: 0,
  540. encode: {
  541. x: "x",
  542. y: "y",
  543. },
  544. xAxisIndex: 0,
  545. yAxisIndex: 0,
  546. },
  547. {
  548. type: "effectScatter",
  549. showEffectOn: "emphasis",
  550. rippleEffect: {
  551. scale: 1,
  552. },
  553. name: "有用点",
  554. symbolSize: (data) => {
  555. return data.s ? (data.s > 10 ? 10 : data.s) : 4;
  556. },
  557. datasetIndex: 1,
  558. encode: {
  559. x: "x",
  560. y: "y",
  561. },
  562. xAxisIndex: 0,
  563. yAxisIndex: 0,
  564. },
  565. {
  566. name: "Cp值",
  567. type: "line",
  568. symbol: "line", //设定为实心点
  569. symbolSize: 0, //设定实心点的大小
  570. smooth: true, //这个是把线变成曲线
  571. data: chartRes.cpz,
  572. xAxisIndex: 0,
  573. yAxisIndex: 1,
  574. },
  575. ];
  576. });
  577. }
  578. };
  579. /**rateAnalysis chart */
  580. const funText = (index) => {
  581. let str = "";
  582. switch (index) {
  583. case 0:
  584. str = "0-2.5";
  585. break;
  586. case 1:
  587. str = "2.5-5";
  588. break;
  589. case 2:
  590. str = "5-7.5";
  591. break;
  592. case 3:
  593. str = "7.5-10";
  594. break;
  595. case 4:
  596. str = "10-12.5";
  597. break;
  598. case 5:
  599. str = "12.5-15";
  600. break;
  601. case 6:
  602. str = "15-17.5";
  603. break;
  604. case 7:
  605. str = "17.5-20";
  606. break;
  607. case 8:
  608. str = "20-22.5";
  609. break;
  610. case 9:
  611. str = "22.5-25";
  612. break;
  613. case 10:
  614. str = "25-inf";
  615. break;
  616. }
  617. return str;
  618. };
  619. const scatterxData = ref([{
  620. type: "category",
  621. name: "度",
  622. data: new Array(61).fill(-30).map((o, index) => Number(o + index)),
  623. boundaryGap: false,
  624. splitLine: {
  625. show: true,
  626. },
  627. axisLine: {
  628. show: true,
  629. },
  630. }, ]);
  631. const scatteryData = ref([{
  632. type: "category",
  633. data: [5, 6, 7, 8, 9, 10],
  634. axisLine: {
  635. show: false,
  636. },
  637. name: "m/s",
  638. splitLine: {
  639. show: false,
  640. },
  641. }, ]);
  642. const scatterSeries = ref([{
  643. name: "对风偏航",
  644. type: "scatter",
  645. symbolSize: function (val) {
  646. return val[2];
  647. },
  648. data: [],
  649. markLine: {
  650. symbol: "none",
  651. label: {
  652. show: false,
  653. },
  654. lineStyle: {
  655. color: "#F72C5B",
  656. width: "3",
  657. },
  658. data: [{
  659. // yAxis: powerproductionNum.value,
  660. }, ],
  661. },
  662. animationDelay: function (idx) {
  663. return idx * 5;
  664. },
  665. }, ]);
  666. const chartData = ref([]); //roses的chartList
  667. let chartId = 1;
  668. /**submit */
  669. const funRateSubmit = async (obj) => {
  670. const rosesRes = await httpRequest.get("/wind/roses", {
  671. params: {
  672. ids: obj.processId,
  673. mode: 0,
  674. },
  675. });
  676. const lineRes = await httpRequest.get("/wind/deviation/ratio", {
  677. params: {
  678. ids: obj.processId,
  679. mode: 0,
  680. },
  681. });
  682. if (rosesRes.code === 200) {
  683. if (rosesRes.data.length) {
  684. rateDialog.value = true;
  685. nextTick(() => {
  686. chartData.value = [];
  687. for (const chart of rosesRes.data) {
  688. chartData.value.push({
  689. id: chartId,
  690. title: "",
  691. subtext: "风速风向玫瑰图",
  692. xAxis: {
  693. type: "category",
  694. boundaryGap: false,
  695. data: [
  696. "N",
  697. "",
  698. "N-E",
  699. "",
  700. "E",
  701. "",
  702. "S-E",
  703. "",
  704. "S",
  705. "",
  706. "S-W",
  707. "",
  708. "W",
  709. "",
  710. "W-N",
  711. "",
  712. ],
  713. splitLine: {
  714. show: true,
  715. },
  716. },
  717. isRadar: false,
  718. series: chart.roses.length ?
  719. chart.roses.map((o, index) => {
  720. return {
  721. type: "bar",
  722. data: o,
  723. coordinateSystem: "polar",
  724. name: funText(index),
  725. stack: "a",
  726. emphasis: {
  727. focus: "series",
  728. },
  729. };
  730. }) : [],
  731. });
  732. chartId++;
  733. chartData.value.push({
  734. id: chartId,
  735. title: "",
  736. subtext: "风速风向频次玫瑰图",
  737. isRadar: true,
  738. xAxis: {
  739. type: "category",
  740. boundaryGap: false,
  741. data: [
  742. "N",
  743. "",
  744. "N-E",
  745. "",
  746. "E",
  747. "",
  748. "S-E",
  749. "",
  750. "S",
  751. "",
  752. "S-W",
  753. "",
  754. "W",
  755. "",
  756. "W-N",
  757. "",
  758. ],
  759. splitLine: {
  760. show: true,
  761. },
  762. },
  763. series: chart.count.length ? [
  764. ...chart.count.map((o, index) => {
  765. return {
  766. type: "bar",
  767. data: o,
  768. coordinateSystem: "polar",
  769. name: funText(index),
  770. stack: "a",
  771. emphasis: {
  772. focus: "series",
  773. },
  774. };
  775. }),
  776. {
  777. type: "radar",
  778. // coordinateSystem: 'polar',
  779. tooltip: {
  780. trigger: "item",
  781. },
  782. // smooth: true,
  783. // areaStyle: {},
  784. name: "对风",
  785. data: [{
  786. value: chart.radar,
  787. }, ],
  788. },
  789. ] : [],
  790. });
  791. chartId++;
  792. scatterSeries.value[0].data = chart.frequency.data.length ?
  793. chart.frequency.data.map((item) => {
  794. return [item[1] + "", item[0] + "", (item[2] * 15).toFixed(1)];
  795. }) : [];
  796. scatterSeries.value[0].markLine.data = [{
  797. xAxis: `${chart.frequency.avg}`,
  798. name: `平均偏航:${chart.frequency.avg}度`,
  799. }, ];
  800. }
  801. });
  802. }
  803. }
  804. if (lineRes.code === 200) {
  805. if (lineRes.data.length) {
  806. lineDataSet.value[0].source = lineRes.data[0].scatter.map((o) => {
  807. return [o.x + "", o.y];
  808. });
  809. lineSeries.value = [{
  810. name: "对风频次",
  811. type: "line",
  812. symbol: "line", //设定为实心点
  813. symbolSize: 0, //设定实心点的大小
  814. smooth: true, //这个是把线变成曲线
  815. data: lineRes.data[0].count,
  816. yAxisIndex: 1,
  817. },
  818. {
  819. type: "effectScatter",
  820. showEffectOn: "emphasis",
  821. rippleEffect: {
  822. scale: 1,
  823. },
  824. legendHoverLink: false,
  825. name: "数据散点",
  826. symbolSize: 5,
  827. datasetIndex: 0,
  828. encode: {
  829. x: "x",
  830. y: "y",
  831. },
  832. yAxisIndex: 0,
  833. },
  834. ];
  835. }
  836. }
  837. };
  838. /**lineChart */
  839. const linexAxis = ref({
  840. type: "category",
  841. data: new Array(101)
  842. .fill(-50)
  843. .map((o, index) => Number((o + index).toFixed(1))),
  844. splitLine: {
  845. show: false,
  846. },
  847. axisTick: {
  848. show: true,
  849. },
  850. });
  851. const lineyAxis = ref([{
  852. type: "value",
  853. name: "m/s",
  854. splitLine: {
  855. show: false,
  856. },
  857. axisTick: {
  858. show: true,
  859. },
  860. },
  861. {
  862. type: "value",
  863. name: "频次",
  864. splitLine: {
  865. show: false,
  866. },
  867. axisTick: {
  868. show: true,
  869. },
  870. },
  871. ]);
  872. const lineSeries = ref([]);
  873. const lineDataSet = ref([{
  874. source: [],
  875. }, ]);
  876. /** rate dialog */
  877. const rateDialog = ref(false);
  878. const dbRateDialog = ref(false);
  879. const actChartName = ref("");
  880. const actDiaTitle = ref("");
  881. const diaPanelRef = ref();
  882. const exportLoading = ref(false);
  883. const actCopList = ref([
  884. // {
  885. // xAxis: [],
  886. // subtext: '',
  887. // title: '',
  888. // isRadar: false,
  889. // series: [],
  890. // yAxis: [],
  891. // dataset: []
  892. // }
  893. ]);
  894. // 作为actCopList的备份 在actCopList赋值多个时 同时赋值, 在dialog弹出时清空. 作用: 在actCopList变化时, 重新赋值原始数据
  895. const actCopListBak = ref([]);
  896. const checkAll = ref(true);
  897. const queryForm = reactive({
  898. checkIds: [],
  899. });
  900. const funCheckAll = () => {
  901. checkAll.value = !checkAll.value;
  902. if (checkAll.value) {
  903. queryForm.checkIds = windList.value.map((o) => o.processId);
  904. } else {
  905. queryForm.checkIds = [];
  906. }
  907. };
  908. const funActCop = (obj, type) => {
  909. switch (type) {
  910. case "chartCop1":
  911. actChartName.value = "chartCop1";
  912. obj.actCop = shallowRef(chartCop);
  913. actDiaTitle.value = "风速风向玫瑰图";
  914. break;
  915. case "chartCop2":
  916. actChartName.value = "chartCop2";
  917. obj.actCop = shallowRef(chartCop);
  918. actDiaTitle.value = "风速风向频次玫瑰图";
  919. break;
  920. case "lineChartCop":
  921. actChartName.value = "lineChartCop";
  922. obj.actCop = shallowRef(lineChartCop);
  923. actDiaTitle.value = "对风偏差分析图";
  924. break;
  925. case "scatterSingleChartCop":
  926. actChartName.value = "scatterSingleChartCop";
  927. obj.actCop = shallowRef(scatterSingleChartCop);
  928. actDiaTitle.value = "静态偏航对风分析图";
  929. break;
  930. }
  931. obj.isBrush = type === "lineChartCop" ? false : false;
  932. obj.id = chartId;
  933. chartId++;
  934. dbRateDialog.value = true;
  935. actCopListBak.value = [];
  936. nextTick(() => {
  937. actCopList.value = [obj];
  938. });
  939. };
  940. const funDiaSubmit = async () => {
  941. let url = "";
  942. switch (actChartName.value) {
  943. case "chartCop1":
  944. url = "/wind/roses";
  945. break;
  946. case "chartCop2":
  947. url = "/wind/roses";
  948. break;
  949. case "lineChartCop":
  950. url = "/wind/deviation/ratio";
  951. break;
  952. case "scatterSingleChartCop":
  953. url = "/wind/roses";
  954. break;
  955. }
  956. if (url) {
  957. const res = await httpRequest.get(url, {
  958. params: {
  959. ids: queryForm.checkIds.join(","),
  960. mode: 0,
  961. },
  962. });
  963. if (res.code === 200) {
  964. actCopList.value = [];
  965. actCopListBak.value = []; //清空备份
  966. if (res.data.length) {
  967. for (const chart of res.data) {
  968. if (actChartName.value === "chartCop1") {
  969. actCopList.value.push({
  970. id: chartId,
  971. isBrush: false,
  972. actCop: shallowRef(chartCop),
  973. title: chart.wt,
  974. subtext: "风速风向玫瑰图",
  975. xAxis: {
  976. type: "category",
  977. boundaryGap: false,
  978. data: [
  979. "N",
  980. "",
  981. "N-E",
  982. "",
  983. "E",
  984. "",
  985. "S-E",
  986. "",
  987. "S",
  988. "",
  989. "S-W",
  990. "",
  991. "W",
  992. "",
  993. "W-N",
  994. "",
  995. ],
  996. splitLine: {
  997. show: true,
  998. },
  999. },
  1000. isRadar: false,
  1001. series: chart.roses.length ?
  1002. chart.roses.map((o, index) => {
  1003. return {
  1004. type: "bar",
  1005. data: o,
  1006. coordinateSystem: "polar",
  1007. name: funText(index),
  1008. stack: "a",
  1009. emphasis: {
  1010. focus: "series",
  1011. },
  1012. };
  1013. }) : [],
  1014. });
  1015. chartId++;
  1016. }
  1017. if (actChartName.value === "chartCop2") {
  1018. actCopList.value.push({
  1019. id: chartId,
  1020. isBrush: false,
  1021. actCop: shallowRef(chartCop),
  1022. title: chart.wt,
  1023. subtext: "风速风向频次玫瑰图",
  1024. xAxis: {
  1025. type: "category",
  1026. boundaryGap: false,
  1027. data: [
  1028. "N",
  1029. "",
  1030. "N-E",
  1031. "",
  1032. "E",
  1033. "",
  1034. "S-E",
  1035. "",
  1036. "S",
  1037. "",
  1038. "S-W",
  1039. "",
  1040. "W",
  1041. "",
  1042. "W-N",
  1043. "",
  1044. ],
  1045. splitLine: {
  1046. show: true,
  1047. },
  1048. },
  1049. isRadar: true,
  1050. series: chart.count.length ? [
  1051. ...chart.count.map((o, index) => {
  1052. return {
  1053. type: "bar",
  1054. data: o,
  1055. coordinateSystem: "polar",
  1056. name: funText(index),
  1057. stack: "a",
  1058. emphasis: {
  1059. focus: "series",
  1060. },
  1061. };
  1062. }),
  1063. {
  1064. type: "radar",
  1065. // coordinateSystem: 'polar',
  1066. tooltip: {
  1067. trigger: "item",
  1068. },
  1069. // smooth: true,
  1070. // areaStyle: {},
  1071. name: "对风",
  1072. data: [{
  1073. value: chart.radar,
  1074. }, ],
  1075. },
  1076. ] : [],
  1077. });
  1078. chartId++;
  1079. }
  1080. if (actChartName.value === "lineChartCop") {
  1081. actCopList.value.push({
  1082. id: chartId,
  1083. isBrush: false,
  1084. actCop: shallowRef(lineChartCop),
  1085. title: chart.wtId,
  1086. subtext: "对风偏差分析图",
  1087. xAxis: linexAxis.value,
  1088. yAxis: lineyAxis.value,
  1089. dataset: [{
  1090. source: chart.scatter.map((o) => {
  1091. return [o.x + "", o.y];
  1092. }),
  1093. }, ],
  1094. isRadar: false,
  1095. series: [{
  1096. name: "对风频次",
  1097. type: "line",
  1098. symbol: "line", //设定为实心点
  1099. symbolSize: 0, //设定实心点的大小
  1100. smooth: true, //这个是把线变成曲线
  1101. data: chart.count,
  1102. yAxisIndex: 1,
  1103. },
  1104. {
  1105. type: "effectScatter",
  1106. showEffectOn: "emphasis",
  1107. rippleEffect: {
  1108. scale: 1,
  1109. },
  1110. legendHoverLink: false,
  1111. name: "数据散点",
  1112. symbolSize: 5,
  1113. datasetIndex: 0,
  1114. encode: {
  1115. x: "x",
  1116. y: "y",
  1117. },
  1118. yAxisIndex: 0,
  1119. },
  1120. ],
  1121. });
  1122. chartId++;
  1123. }
  1124. if (actChartName.value === "scatterSingleChartCop") {
  1125. actCopList.value.push({
  1126. id: chartId,
  1127. isBrush: false,
  1128. actCop: shallowRef(scatterSingleChartCop),
  1129. title: chart.wt,
  1130. subtext: "静态偏航对风分析图",
  1131. xAxis: scatterxData.value,
  1132. yAxis: scatteryData.value,
  1133. isRadar: false,
  1134. series: [{
  1135. name: "对风偏航",
  1136. type: "scatter",
  1137. symbolSize: function (val) {
  1138. return val[2];
  1139. },
  1140. markLine: {
  1141. symbol: "none",
  1142. label: {
  1143. show: false,
  1144. },
  1145. lineStyle: {
  1146. color: "#F72C5B",
  1147. width: "3",
  1148. },
  1149. data: [{
  1150. name: `平均偏航:${chart.frequency.avg}度`,
  1151. xAxis: `${chart.frequency.avg}`,
  1152. }, ],
  1153. },
  1154. data: chart.frequency.data.length ?
  1155. chart.frequency.data.map((item) => {
  1156. return [
  1157. item[1] + "",
  1158. item[0] + "",
  1159. (item[2] * 15).toFixed(1),
  1160. ];
  1161. }) : [],
  1162. animationDelay: function (idx) {
  1163. return idx * 5;
  1164. },
  1165. }, ],
  1166. });
  1167. chartId++;
  1168. }
  1169. }
  1170. actCopListBak.value = actCopList.value;
  1171. }
  1172. }
  1173. }
  1174. };
  1175. const funDiaExport = () => {
  1176. exportLoading.value = true;
  1177. tools.scrollToPDF(diaPanelRef.value, actDiaTitle.value, () => {
  1178. exportLoading.value = false;
  1179. });
  1180. };
  1181. const funDbClick = (obj) => {
  1182. if (actCopListBak.value.length > 1) {
  1183. //判断大于1时, 才有双击放大功能
  1184. if (actCopList.value.length === 1) {
  1185. actCopList.value = actCopListBak.value;
  1186. } else {
  1187. actCopList.value = [obj];
  1188. }
  1189. }
  1190. };
  1191. const theme = ref(null)
  1192. const echartsTheme = ref('')
  1193. watch(() => store.state.theme, (newVal, oldVal) => {
  1194. theme.value = newVal
  1195. echartsTheme.value = !newVal ? 'dark' : ''
  1196. funGetTree()
  1197. }, {
  1198. deep: true
  1199. })
  1200. const getOnline = () => {
  1201. axios({
  1202. method: "get",
  1203. baseURL: 'ping',
  1204. url: "",
  1205. }).then(res => {
  1206. showOnlineMap.value = true
  1207. }).catch(e => {
  1208. showOnlineMap.value = false
  1209. })
  1210. };
  1211. /**mounted */
  1212. onMounted(() => {
  1213. // getOnline();
  1214. funGetTree();
  1215. theme.value = store.state.theme
  1216. echartsTheme.value = !theme.value ? 'dark' : ''
  1217. tableHeight.value = window.innerHeight - 115 + "px";
  1218. excelHeight.value = window.innerHeight - 115 + "px";
  1219. treeHeight.value = window.innerHeight - 115 + "px";
  1220. window.addEventListener("resize", () => {
  1221. tableHeight.value = window.innerHeight - 115 + "px";
  1222. excelHeight.value = window.innerHeight - 115 + "px";
  1223. treeHeight.value = window.innerHeight - 115 + "px";
  1224. });
  1225. /**test */
  1226. // funExcelChange({
  1227. // id: 1,
  1228. // name: 'excel',
  1229. // type: 'fitting',
  1230. // })
  1231. });
  1232. /**activated */
  1233. // onActivated(() => {
  1234. // funGetTree()
  1235. // })
  1236. const funMapDone = (mapStatus) => {
  1237. if (mapStatus) {
  1238. funGetTree();
  1239. }
  1240. };
  1241. </script>
  1242. <style lang="less" scoped>
  1243. .dataAnalysisPosAnal {
  1244. height: 100%;
  1245. .dataAnalysisPosAnalMain {
  1246. height: 100%;
  1247. .main_top {
  1248. height: 40px;
  1249. display: flex;
  1250. align-items: center;
  1251. .topPsty {
  1252. position: relative;
  1253. top: 5px;
  1254. padding: 7px 20px;
  1255. font-size: 12px;
  1256. font-weight: 600;
  1257. margin-left: 10px;
  1258. border-radius: 3px;
  1259. }
  1260. }
  1261. .main {
  1262. display: flex;
  1263. width: 100%;
  1264. .treeDataMain,
  1265. .excelDataMain,
  1266. .tableDataMain {
  1267. border-radius: 10px;
  1268. }
  1269. .treeDataMain {
  1270. margin-right: 10px;
  1271. padding: 10px 0 10px 10px;
  1272. width: calc(19% - 20px);
  1273. }
  1274. .excelDataMain {
  1275. margin-right: 10px;
  1276. padding: 10px 0 10px 10px;
  1277. width: calc(15% - 20px);
  1278. .excelDataMain_top {
  1279. height: 49%;
  1280. padding: 5px 0;
  1281. }
  1282. .excelDataMain_bot {
  1283. padding: 5px 0;
  1284. }
  1285. }
  1286. .tableDataMain {
  1287. padding: 10px;
  1288. width: calc(66% - 20px);
  1289. position: relative;
  1290. .butten_com {
  1291. position: absolute;
  1292. right: 20px;
  1293. z-index: 111111;
  1294. }
  1295. }
  1296. }
  1297. }
  1298. }
  1299. .rightMenuDialog {
  1300. .el-overlay-dialog {
  1301. overflow: hidden;
  1302. }
  1303. }
  1304. .themeDark {
  1305. .dataAnalysisPosAnalMain {
  1306. .main_top {
  1307. .topPsty {
  1308. color: #1C99FF;
  1309. background: #1E2126;
  1310. }
  1311. }
  1312. .main {
  1313. background: #13171e;
  1314. .treeDataMain {
  1315. background: transparent;
  1316. }
  1317. .excelDataMain {
  1318. background: #313233;
  1319. }
  1320. .tableDataMain {
  1321. margin-top: 5px;
  1322. background: #212223;
  1323. }
  1324. }
  1325. }
  1326. }
  1327. .themeLight {
  1328. padding: 0;
  1329. .dataAnalysisPosAnalMain {
  1330. .main_top {
  1331. .topPsty {
  1332. color: #2778FF;
  1333. background: #FFFFFF;
  1334. }
  1335. }
  1336. .main {
  1337. background: #E6E8F2;
  1338. .treeDataMain {
  1339. background: transparent;
  1340. }
  1341. .excelDataMain {
  1342. background: #F4F6FB;
  1343. }
  1344. .tableDataMain {
  1345. background: #fff;
  1346. margin-top: 5px;
  1347. }
  1348. }
  1349. }
  1350. }
  1351. </style>