panoramaPowerDialogPage.vue 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. <template>
  2. <el-dialog class="windLifeDialog" :title="title" v-model="dialogVisible" :fullscreen="true"
  3. :close-on-click-modal="false">
  4. <div class="globalDiaMain" :class="!theme ? 'themeDa' : 'themeLi'">
  5. <div class="main_top">
  6. <div class="main_top_left" >
  7. <div class="exceed">
  8. <span style="margin-top: 3px">时间:</span>
  9. <el-date-picker v-model="pickerTime" @change="changeTime" type="datetimerange"
  10. :clearable="false" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期">
  11. </el-date-picker>
  12. </div>
  13. <div class="exceed">
  14. <span style="margin-top: 3px">超前:</span>
  15. <el-select style="width: 130px" class="exTime" v-model="chooseExceedTimeFv" placeholder="请选择">
  16. <el-option v-for="item in ExceedTimeList" :key="item.value" :label="item.label"
  17. :disabled="item.disabled" :value="item.value">
  18. </el-option>
  19. </el-select>
  20. </div>
  21. <el-button type="primary" @click="seachData">查 询</el-button>
  22. <el-button @click="exportExcel">导出查询结果</el-button>
  23. </div>
  24. </div>
  25. <div v-loading="loading">
  26. <el-row class="main_charts">
  27. <el-col :span="12">
  28. <div id="centerCharts" class="chartsStyle"></div>
  29. </el-col>
  30. <el-col :span="12">
  31. <div id="windCharts" class="chartsStyle"></div>
  32. </el-col>
  33. </el-row>
  34. <div class="main_table warn-table" style="margin-top: 20px">
  35. <el-table :data="tableData" ref="report-table" border show-summary :summary-method="getSummaries" max-height="45vh" style="width: 100%"
  36. :header-cell-style="{
  37. padding: '4px',
  38. fontSize: '16px',
  39. fontWeight: bold,
  40. border: '0.5px solid rgba(0,0,0,.5) !important',
  41. }">
  42. <el-table-column prop="dataTime" label="时间" align="center" width="160"></el-table-column>
  43. <el-table-column prop="actualWindSpeedDq" label="实际风速" align="center"></el-table-column>
  44. <el-table-column prop="forecastWindSpeedDq" label="预测风速" align="center"></el-table-column>
  45. <el-table-column prop="theoreticalPower" label="理论功率" align="center"></el-table-column>
  46. <el-table-column prop="availablePower" label="可用功率" align="center"></el-table-column>
  47. <el-table-column label="当期数据" align="center">
  48. <el-table-column prop="actualPowerDq" label="实际功率" align="center"></el-table-column>
  49. <el-table-column prop="veryShortTermForecastDq" label="超短期预测" align="center">
  50. </el-table-column>
  51. <el-table-column prop="shortTermForecastDq" label="短期预测" align="center"></el-table-column>
  52. </el-table-column>
  53. <el-table-column label="同期数据" align="center">
  54. <el-table-column prop="actualPowerTq" label="实际功率" align="center"></el-table-column>
  55. <el-table-column prop="veryShortTermForecastTq" label="超短期预测" align="center">
  56. </el-table-column>
  57. <el-table-column prop="shortTermForecastTq" label="短期预测" align="center"></el-table-column>
  58. </el-table-column>
  59. <el-table-column label="同期比率" align="center">
  60. <el-table-column prop="tqActualRatio" label="实际功率" align="center"></el-table-column>
  61. <el-table-column prop="tqUltraRatio" label="超短期预测" align="center"></el-table-column>
  62. <el-table-column prop="tqShortRatio" label="短期预测" align="center"></el-table-column>
  63. </el-table-column>
  64. <el-table-column label="环比数据" align="center" v-if="dateType === 3">
  65. <el-table-column prop="actualPowerSy" label="实际功率" align="center"></el-table-column>
  66. <el-table-column prop="veryShortTermForecastSy" label="超短期预测" align="center">
  67. </el-table-column>
  68. <el-table-column prop="shortTermForecastSy" label="短期预测" align="center"></el-table-column>
  69. </el-table-column>
  70. <el-table-column label="环比比率" align="center" v-if="dateType === 3">
  71. <el-table-column prop="hbActualRatio" label="实际功率" align="center"></el-table-column>
  72. <el-table-column prop="hbUltraRatio" label="超短期预测" align="center"></el-table-column>
  73. <el-table-column prop="hbShortRatio" label="短期预测" align="center"></el-table-column>
  74. </el-table-column>
  75. </el-table>
  76. </div>
  77. </div>
  78. </div>
  79. <!-- <span slot="footer" class="dialog-footer">
  80. <el-button type="primary">确 定</el-button>
  81. <el-button @click="dialogVisible = false">取 消</el-button>
  82. </span> -->
  83. </el-dialog>
  84. </template>
  85. <script>
  86. import * as XLSX from "xlsx";
  87. import {
  88. saveAs
  89. } from "file-saver";
  90. import * as XLSXD from "xlsx-js-style";
  91. import {
  92. apiGetglobalPowerCharts,
  93. apiGetglobalPowerTable,
  94. apiGetglobalWindSpeedCharts,
  95. apiGetglobalIrradianceCharts,
  96. } from "../../../api/api";
  97. export default {
  98. props: {
  99. from: {
  100. type: String,
  101. default: () => {
  102. return "";
  103. },
  104. },
  105. ExceedTimeList: {
  106. type: Array,
  107. default: () => {
  108. return [];
  109. },
  110. },
  111. echartsTheme: {
  112. type: String,
  113. default: () => {
  114. return "";
  115. },
  116. },
  117. theme: {
  118. type: Boolean,
  119. default: () => {
  120. return false;
  121. },
  122. },
  123. },
  124. data() {
  125. return {
  126. title: "",
  127. dialogVisible: false,
  128. windTurbines: null,
  129. windTurbinesVal: null,
  130. tableData: [],
  131. chooseExceedTimeFv: 0,
  132. pickerTime: [],
  133. dateType: 1,
  134. stationData: {},
  135. loading: false,
  136. global: false, //全域数据标识
  137. };
  138. },
  139. created() {},
  140. methods: {
  141. seachData() {
  142. this.global = false;
  143. this.getChartsData();
  144. this.getTableData();
  145. },
  146. getSummaries(datas) {
  147. const {columns, data} = datas
  148. const sums = [];
  149. columns.forEach((column, index) => {
  150. if (index === 0) {
  151. sums[index] = '合计';
  152. return;
  153. }
  154. const values = data.map(item => Number(item[column.property]));
  155. if (!values.every(value => isNaN(value))) {
  156. if (index === 1 || index === 2) {
  157. sums[index] = values.reduce((prev, curr) => {
  158. const value = Number(curr);
  159. if (!isNaN(value)) {
  160. return prev + curr;
  161. } else {
  162. return prev;
  163. }
  164. }, 0) / values.length;
  165. sums[index] = sums[index].toFixed(2) + ' (平均值)';
  166. } else {
  167. sums[index] = values.reduce((prev, curr) => {
  168. const value = Number(curr);
  169. if (!isNaN(value)) {
  170. return prev + curr;
  171. } else {
  172. return prev;
  173. }
  174. }, 0);
  175. sums[index] = sums[index].toFixed(2)
  176. }
  177. } else {
  178. sums[index] = '-';
  179. }
  180. });
  181. return sums;
  182. },
  183. changeTime(val) {
  184. if (val) {
  185. let timeC = new Date(val[1]).getTime() - new Date(val[0]).getTime();
  186. if (timeC <= 10 * 86400000) {
  187. //十天内
  188. this.dateType = 1;
  189. } else if (timeC > 10 * 86400000 && timeC <= 2592000000) {
  190. // 大于十天小于30天
  191. this.dateType = 2;
  192. } else {
  193. this.dateType = 3;
  194. }
  195. console.log(timeC);
  196. console.log(this.dateType);
  197. }
  198. },
  199. //转换时间
  200. getPowerTime(date) {
  201. var y = date.getFullYear();
  202. var m = date.getMonth() + 1;
  203. m = m < 10 ? "0" + m : m;
  204. var d = date.getDate();
  205. d = d < 10 ? "0" + d : d;
  206. var h = date.getHours();
  207. h = h < 10 ? "0" + h : h;
  208. var minute = date.getMinutes();
  209. minute = minute < 10 ? "0" + minute : minute;
  210. let timeF = "";
  211. timeF = y + "-" + m + "-" + d + " " + h + ":" + minute;
  212. return this.$utils.changePowerPickDate(timeF);
  213. },
  214. getChartsData() {
  215. let pickStartTime = this.getPowerTime(this.pickerTime[0]);
  216. let pickEndTime = this.getPowerTime(this.pickerTime[1]);
  217. let type;
  218. if (
  219. new Date(pickEndTime).getTime() - new Date(pickStartTime).getTime() <=
  220. 10 * 86400000
  221. ) {
  222. type = 1;
  223. } else {
  224. type = 2;
  225. }
  226. let that = this;
  227. that.loading = true;
  228. // 功率
  229. let params = {
  230. beginDataTime: pickStartTime,
  231. endDataTime: pickEndTime,
  232. leadTime: that.chooseExceedTimeFv,
  233. stationNumber: that.stationData.stationNumber,
  234. // itemVal: that.stationData.itemVal,
  235. itemVal: 0,
  236. timeType: type,
  237. };
  238. //风速
  239. //光伏
  240. let params1 = {
  241. beginDataTime: pickStartTime,
  242. endDataTime: pickEndTime,
  243. stationNumber: that.stationData.stationNumber,
  244. timeType: type,
  245. };
  246. apiGetglobalPowerCharts(params).then((datas) => {
  247. that.commonFn(datas, type, "功率");
  248. });
  249. if (that.stationData.itemVal === "0") {
  250. apiGetglobalWindSpeedCharts(params1).then((datas) => {
  251. that.commonFn(datas, type, "风速");
  252. });
  253. } else {
  254. apiGetglobalIrradianceCharts(params1).then((datas) => {
  255. that.commonFn(datas, type, "光伏");
  256. });
  257. }
  258. },
  259. commonFn(datas, type, name) {
  260. if (datas && datas.data) {
  261. let xAxis = [];
  262. let series = [];
  263. let legend = [];
  264. if (datas.data.dateList.length > 0) {
  265. if (type === 2) {
  266. datas.data.dateList.forEach((item) => {
  267. xAxis.push(item.substring(0, item.indexOf(" ")));
  268. });
  269. } else {
  270. xAxis = datas.data.dateList;
  271. }
  272. }
  273. if (name === "功率") {
  274. if (datas.data.dataFormatList.length > 0) {
  275. let powerArr = ["理论", "可用", "AGC", "超短期", "短期", "实际"]
  276. powerArr.forEach(it =>{
  277. datas.data.dataFormatList.forEach((iten) => {
  278. if (it === iten.name) {
  279. legend.push(iten.name);
  280. let seriesObj = {
  281. name: iten.name,
  282. type: "line",
  283. data: iten.data.map((it) => {
  284. return this.$utils.isHasNum(it);
  285. }),
  286. symbol: "none",
  287. };
  288. series.push(seriesObj);
  289. }
  290. });
  291. })
  292. }
  293. this.getglobalLine("centerCharts", name, xAxis, legend, series);
  294. } else {
  295. if (datas.data.dataFormatList.length > 0) {
  296. datas.data.dataFormatList.forEach((iten) => {
  297. legend.push(iten.name);
  298. let seriesObj = {
  299. name: iten.name,
  300. type: "line",
  301. data: iten.data.map((it) => {
  302. return this.$utils.isHasNum(it);
  303. }),
  304. symbol: "none",
  305. };
  306. series.push(seriesObj);
  307. });
  308. }
  309. this.getglobalLine("windCharts", name, xAxis, legend, series);
  310. }
  311. }
  312. },
  313. getglobalLine(name, title, xAxis, legend, series) {
  314. let Yname =
  315. title === "功率" ? "兆瓦(Mw)" : title === "风速" ? "m/s" : "W/㎡";
  316. let option = {
  317. title: {
  318. text: title,
  319. },
  320. tooltip: {
  321. trigger: "axis",
  322. },
  323. legend: {
  324. right: "20",
  325. data: legend,
  326. },
  327. grid: {
  328. left: "5%",
  329. right: "4%",
  330. bottom: "3%",
  331. containLabel: true,
  332. },
  333. xAxis: {
  334. type: "category",
  335. boundaryGap: false,
  336. data: xAxis,
  337. },
  338. yAxis: {
  339. type: "value",
  340. name: Yname,
  341. },
  342. series: series,
  343. };
  344. if (this.from === "index") {
  345. option.backgroundColor = "";
  346. }
  347. if (!this.theme) {
  348. option.backgroundColor = "";
  349. }
  350. // 基于准备好的dom,初始化echarts实例
  351. let dom = document.getElementById(name);
  352. dom.removeAttribute("_echarts_instance_") ?
  353. dom.removeAttribute("_echarts_instance_") :
  354. "";
  355. let myChart = this.$echarts.init(dom, this.echartsTheme);
  356. myChart.setOption(option);
  357. myChart.on("mousemove", this.setTooltip("centerCharts", "windCharts", 0));
  358. window.addEventListener("resize", function () {
  359. myChart.resize();
  360. });
  361. },
  362. setTooltip(name1, name2, num) {
  363. const myChart1 = this.$echarts.init(document.getElementById(name1));
  364. const myChart2 = this.$echarts.init(document.getElementById(name2));
  365. this.$utils.setTooltip(myChart1, myChart2, num);
  366. },
  367. getTableData() {
  368. let pickStartTime = this.getPowerTime(this.pickerTime[0]);
  369. let pickEndTime = this.getPowerTime(this.pickerTime[1]);
  370. let params = {
  371. beginDataTime: pickStartTime,
  372. endDataTime: pickEndTime,
  373. leadTime: this.chooseExceedTimeFv,
  374. stationNumber: this.stationData.stationNumber,
  375. itemVal: this.stationData.itemVal,
  376. timeType: this.dateType,
  377. };
  378. apiGetglobalPowerTable(params).then((datas) => {
  379. if (datas && datas.data) {
  380. if (datas.data.dataFormatList) {
  381. datas.data.dataFormatList.forEach((item) => {
  382. for (let i in item) {
  383. if (i !== "dataTime") {
  384. item[i] = this.$utils.isHasNum(item[i]);
  385. }
  386. }
  387. //同期实际比率
  388. item.tqActualRatio = this.$utils.ratioCalculation(
  389. item.actualPowerDq,
  390. item.actualPowerTq
  391. );
  392. //同期超短期比率
  393. item.tqUltraRatio = this.$utils.ratioCalculation(
  394. item.veryShortTermForecastDq,
  395. item.veryShortTermForecastTq
  396. );
  397. //同期短期比率
  398. item.tqShortRatio = this.$utils.ratioCalculation(
  399. item.shortTermForecastDq,
  400. item.shortTermForecastTq
  401. );
  402. //环比实际比率
  403. item.hbActualRatio = this.$utils.ratioCalculation(
  404. item.actualPowerDq,
  405. item.actualPowerSy
  406. );
  407. //环比超短期比率
  408. item.hbUltraRatio = this.$utils.ratioCalculation(
  409. item.veryShortTermForecastDq,
  410. item.veryShortTermForecastSy
  411. );
  412. //环比短期比率
  413. item.hbShortRatio = this.$utils.ratioCalculation(
  414. item.shortTermForecastDq,
  415. item.shortTermForecastSy
  416. );
  417. });
  418. this.tableData = datas.data.dataFormatList;
  419. this.loading = false;
  420. }
  421. }
  422. });
  423. },
  424. exportExcel() {
  425. try {
  426. const $e = this.$refs["report-table"].$el;
  427. let $table = $e.querySelector(".el-table__fixed");
  428. if (!$table) {
  429. $table = $e;
  430. }
  431. const wb = XLSX.utils.table_to_book($table, {
  432. raw: true,
  433. });
  434. if (wb && wb.Sheets.Sheet1) {
  435. let as = ["!cols", "!fullref", "!merges", "!ref", "!rows"];
  436. let bs = [
  437. "时间",
  438. "理论功率",
  439. "可用功率",
  440. "当期数据",
  441. "实际功率",
  442. "超短期预测",
  443. "短期预测",
  444. "同期数据",
  445. "同期比率",
  446. "环比数据",
  447. "环比比率",
  448. ];
  449. for (let i in wb.Sheets.Sheet1) {
  450. if (as.indexOf(i) < 0) {
  451. if (bs.indexOf(wb.Sheets.Sheet1[i].v) >= 0) {
  452. wb.Sheets.Sheet1[i].s = {
  453. font: {
  454. name: "微软雅黑",
  455. sz: 11,
  456. bold: true,
  457. color: {
  458. rgb: "ffffff",
  459. },
  460. },
  461. alignment: {
  462. horizontal: "center",
  463. vertical: "center",
  464. },
  465. fill: {
  466. fgColor: {
  467. rgb: "4f81bd",
  468. },
  469. },
  470. };
  471. if (i === "A1") {
  472. wb.Sheets.Sheet1["!cols"].push({
  473. wch: 30,
  474. });
  475. } else if (i === "B1") {
  476. wb.Sheets.Sheet1["!cols"].push({
  477. wch: 20,
  478. });
  479. } else {
  480. wb.Sheets.Sheet1["!cols"].push({
  481. wch: 15,
  482. });
  483. }
  484. } else {
  485. wb.Sheets.Sheet1[i].s = {
  486. font: {
  487. name: "微软雅黑",
  488. sz: 10,
  489. bold: false,
  490. color: {
  491. rgb: "000000",
  492. },
  493. },
  494. alignment: {
  495. horizontal: "center",
  496. vertical: "center",
  497. },
  498. // fill:{fgColor: {rgb: '4f81bd'}}
  499. };
  500. }
  501. }
  502. }
  503. }
  504. const wbout = XLSXD.write(wb, {
  505. bookType: "xlsx",
  506. bookSST: true,
  507. type: "array",
  508. });
  509. saveAs(
  510. new Blob([wbout], {
  511. type: "application/octet-stream",
  512. }),
  513. `${this.title}.xlsx`
  514. );
  515. } catch (e) {
  516. if (typeof console !== "undefined") console.error(e);
  517. }
  518. },
  519. },
  520. };
  521. </script>
  522. <style lang="less">
  523. .el-overlay {
  524. .el-overlay-dialog {
  525. .windLifeDialog {
  526. .el-dialog__header {
  527. .el-dialog__title {
  528. color: #fff !important;
  529. }
  530. }
  531. .el-dialog__body {
  532. padding: 10px 20px;
  533. .globalDiaMain {
  534. .main_top {
  535. display: flex;
  536. justify-content: space-between;
  537. .main_top_left {
  538. display: flex;
  539. .exceed {
  540. span {
  541. font-size: 14px;
  542. margin-left: 10px;
  543. }
  544. display: flex;
  545. margin-right: 20px;
  546. .el-select,
  547. .el-select__wrapper {
  548. height: 32px;
  549. }
  550. .el-date-editor {
  551. height: 32px;
  552. .el-input__icon,
  553. .el-range-separator {
  554. line-height: 30px;
  555. }
  556. }
  557. .select-trigger {
  558. .el-input {
  559. .el-input__wrapper {
  560. height: 30px;
  561. }
  562. }
  563. .el-input__suffix {
  564. .el-input__icon {
  565. line-height: 30px;
  566. }
  567. }
  568. }
  569. }
  570. }
  571. .el-button {
  572. height: 30px;
  573. padding: 0 20px;
  574. line-height: 5px;
  575. }
  576. }
  577. .main_charts {
  578. margin-top: 20px;
  579. .chartsStyle {
  580. height: 300px;
  581. width: 100%;
  582. }
  583. }
  584. .main_table {
  585. margin: 20px 0;
  586. .el-table {
  587. .el-table__body-wrapper {
  588. height: 335px !important;
  589. overflow-y: auto;
  590. }
  591. }
  592. }
  593. }
  594. .themeDa {
  595. .main_top {
  596. .main_top_left {
  597. .exceed {
  598. .exceedName {
  599. color: #fff;
  600. margin: 3px 0 0 5px;
  601. }
  602. }
  603. }
  604. }
  605. }
  606. .themeLi {
  607. .main_top {
  608. .main_top_left {
  609. .exceed {
  610. .exceedName {
  611. color: #000;
  612. margin: 3px 0 0 5px;
  613. }
  614. }
  615. }
  616. }
  617. }
  618. }
  619. }
  620. }
  621. }
  622. // .themeDa {
  623. // .main_top {
  624. // .main_top_left {
  625. // display: flex;
  626. // margin-bottom: 10px;
  627. // .exceed {
  628. // color: #fff;
  629. // }
  630. // }
  631. // }
  632. // }
  633. // .themeLi {
  634. // .main_top {
  635. // .main_top_left {
  636. // display: flex;
  637. // margin-bottom: 10px;
  638. // .exceed {
  639. // color: #000;
  640. // }
  641. // }
  642. // }
  643. // }
  644. </style>