index.vue 49 KB

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