index.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. <template>
  2. <div class="draught-fan-list">
  3. <div class="form-wrapper">
  4. <div class="search mg-b-8">
  5. <div class="search-items">
  6. <div class="search-item">
  7. <div class="lable">电站:</div>
  8. <div class="search-content">
  9. <el-select
  10. v-model="station"
  11. clearable
  12. size="mini"
  13. placeholder="请选择"
  14. popper-class="select"
  15. @change="
  16. (station) => {
  17. getWt(station, true);
  18. }
  19. "
  20. >
  21. <el-option
  22. v-for="item in wpArray"
  23. :key="item.id"
  24. :value="item.id"
  25. :label="item.name"
  26. />
  27. </el-select>
  28. </div>
  29. </div>
  30. <div class="search-item">
  31. <div class="lable">设备:</div>
  32. <div class="search-content">
  33. <el-select
  34. v-model="inverters"
  35. clearable
  36. size="mini"
  37. placeholder="请选择"
  38. popper-class="select"
  39. >
  40. <el-option
  41. v-for="item in wtArray"
  42. :key="item.id"
  43. :value="item.id"
  44. :label="item.name"
  45. />
  46. </el-select>
  47. </div>
  48. </div>
  49. <div class="search-item">
  50. <div class="lable">开始时间:</div>
  51. <div class="search-content">
  52. <el-date-picker
  53. v-model="startdate"
  54. type="datetime"
  55. size="mini"
  56. :disabled-date="disabledDate"
  57. placeholder="选择日期时间"
  58. popper-class="date-select"
  59. >
  60. </el-date-picker>
  61. </div>
  62. </div>
  63. <div class="search-item">
  64. <div class="lable">结束时间:</div>
  65. <div class="search-content">
  66. <el-date-picker
  67. v-model="enddate"
  68. type="datetime"
  69. :disabled-date="disabledDate2"
  70. size="mini"
  71. placeholder="选择日期时间"
  72. popper-class="date-select"
  73. >
  74. </el-date-picker>
  75. </div>
  76. </div>
  77. </div>
  78. <div class="search-actions">
  79. <el-button size="mini" round class="buttons" @click="search"
  80. >查 询</el-button
  81. >
  82. <!-- <el-button
  83. size="mini"
  84. :class="{ 'btn-active': isChartArea }"
  85. :disabled="!seriesData?.length"
  86. @click="funChartArea"
  87. >区域划分</el-button
  88. > -->
  89. </div>
  90. </div>
  91. </div>
  92. <div style="height: calc(100% - 40px); padding-bottom: 10px">
  93. <el-tabs v-model="activeTab">
  94. <el-tab-pane label="表格数据" name="1"> </el-tab-pane>
  95. <el-tab-pane label="图表展示" name="2"> </el-tab-pane>
  96. <table-cop
  97. v-show="activeTab === '1'"
  98. :data="tableData"
  99. :loading="tableLoading"
  100. :column="tableColumn"
  101. height="calc(100% - 20px)"
  102. :tableId="tableShowId"
  103. :tableName="tableName"
  104. ></table-cop>
  105. <div v-show="activeTab === '2'" style="height: 100%">
  106. <CurrentScatterChart
  107. ref="chartRef"
  108. width="100%"
  109. height="100%"
  110. :chartTitle="''"
  111. :xAxisData="xAxisData"
  112. :seriesData="seriesData"
  113. :showLegend="true"
  114. :brushSelected="false"
  115. :dataSet="dataSet"
  116. @getSelected="funChartSelect"
  117. />
  118. </div>
  119. </el-tabs>
  120. </div>
  121. <el-dialog v-model="wtDialog" width="60%" top="120px" draggable>
  122. <template #title>
  123. <div class="dialog-title">
  124. <div class="title">风机功率点位</div>
  125. </div>
  126. </template>
  127. <el-tabs v-model="wtTab">
  128. <el-tab-pane label="数据" name="table">
  129. <el-table :data="wtData" row-key="id" :max-height="550">
  130. <el-table-column property="wtId" align="center" label="风机" />
  131. <el-table-column
  132. property="time"
  133. sortable
  134. width="200"
  135. align="center"
  136. label="时间"
  137. />
  138. <el-table-column
  139. property="speed"
  140. sortable
  141. width="140"
  142. align="center"
  143. label="风速(m/s)"
  144. />
  145. <el-table-column
  146. property="power"
  147. sortable
  148. width="140"
  149. align="center"
  150. label="功率(kW)"
  151. />
  152. <el-table-column
  153. property="rr"
  154. sortable
  155. width="140"
  156. align="center"
  157. label="转速"
  158. />
  159. <el-table-column
  160. property="filter"
  161. sortable
  162. width="140"
  163. align="center"
  164. label="是否有用点"
  165. />
  166. </el-table>
  167. </el-tab-pane>
  168. <el-tab-pane label="故障" name="problem" disabled> </el-tab-pane>
  169. <el-tab-pane label="预警" name="warning" disabled> </el-tab-pane>
  170. </el-tabs>
  171. </el-dialog>
  172. </div>
  173. </template>
  174. <script>
  175. // import ScatterLineChart from "@com/chart/combination/scatter-line-chart.vue";
  176. import tableCop from "./components/table.vue";
  177. import CurrentScatterChart from "./components/current-scatter-chart.vue";
  178. import api1 from "@api/economic/index.js";
  179. // import api from "@api/wisdomOverhaul/energy/index.js";
  180. import dayjs from "dayjs";
  181. import {
  182. getIntervers,
  183. getPowerFittingGF,
  184. getPowerFittingChartGF,
  185. getPowerFittingChart,
  186. getPowerFittingTable,
  187. getPowerFittingSelectedChart,
  188. } from "@/api/powerAnalyse.js";
  189. export default {
  190. // 名称
  191. name: "PowerAnalyse",
  192. // 使用组件
  193. components: {
  194. // ScatterLineChart,
  195. CurrentScatterChart,
  196. tableCop,
  197. },
  198. // 数据
  199. data() {
  200. return {
  201. activeTab: "2",
  202. checkList: [
  203. { name: "非并网", code: "isfbw" },
  204. { name: "非合理值", code: "isfhl" },
  205. { name: "并网后十分钟", code: "isbw" },
  206. { name: "停机前十分钟", code: "istj" },
  207. { name: "功率曲线偏差", code: "isglpc" },
  208. ],
  209. selectList: [
  210. { name: "单台拟合", code: 0 },
  211. { name: "合并拟合", code: 1 },
  212. // { name: "同名拟合", code: 2 },
  213. ],
  214. radioList: [
  215. { name: "一秒钟", code: 1 },
  216. { name: "一分钟", code: 60 },
  217. { name: "十分钟", code: 600 },
  218. { name: "十五分钟", code: 900 },
  219. ],
  220. isAsc: "asc",
  221. wpArray: [],
  222. wtArray: [],
  223. station: "",
  224. inverters: "",
  225. startdate: dayjs()
  226. .add(-1, "month")
  227. // .startOf("month")
  228. .startOf("day")
  229. .format("YYYY-MM-DD HH:mm:ss"),
  230. enddate: dayjs().startOf("day").format("YYYY-MM-DD HH:mm:ss"),
  231. interval: 600,
  232. maxs: 25,
  233. mins: 3,
  234. maxp: 2500,
  235. minp: 0,
  236. checkedList: ["isfbw", "isfhl", "isbw", "istj", "isglpc"],
  237. dimension: 10,
  238. mode: 0,
  239. fittingId: "",
  240. seriesData: [],
  241. avgObj: {
  242. //平均cpz等
  243. title: "",
  244. cpavg: "",
  245. frequency: "",
  246. pcratio: "",
  247. },
  248. markDot: {
  249. //3-5 point点等
  250. pcl5: null,
  251. pcl10: null,
  252. pcl12: null,
  253. pcl25: null,
  254. },
  255. xAxisData: [],
  256. dataSet: "",
  257. isChartArea: false,
  258. tableShowId: "",
  259. tableColumn: [],
  260. tableLoading: false,
  261. tableName: "",
  262. tableData: [],
  263. wtTab: "table",
  264. wtDialog: false,
  265. wtData: [],
  266. };
  267. },
  268. // 函数
  269. methods: {
  270. // 时间选择器第一个禁用
  271. disabledDate(time) {
  272. if (this.enddate) {
  273. return time.getTime() > Date.parse(this.enddate);
  274. } else {
  275. return null;
  276. }
  277. },
  278. // 时间选择器第二个禁用
  279. disabledDate2(time) {
  280. if (this.startdate) {
  281. return time.getTime() < Date.parse(this.startdate);
  282. } else {
  283. return null;
  284. }
  285. },
  286. // 获取风场
  287. getWp(reGetWp) {
  288. api1
  289. .getWpList({
  290. type: "-2",
  291. })
  292. .then((res) => {
  293. if (res.data.code === 200) {
  294. this.wpArray = res.data.data;
  295. this.station = res.data.data[0].id;
  296. this.getWt(this.station, reGetWp);
  297. }
  298. });
  299. },
  300. // 获取风机
  301. getWt(wpid, reGetWp) {
  302. if (wpid) {
  303. getIntervers({
  304. wpids: wpid,
  305. }).then(({ data: res }) => {
  306. if (res.code === 200) {
  307. this.wtArray = res.data;
  308. this.inverters = res.data.length ? res.data[0].id : "";
  309. if (!reGetWp) {
  310. this.search();
  311. }
  312. }
  313. });
  314. }
  315. },
  316. //获取拟合id
  317. getChartId() {
  318. this.BASE.showLoading();
  319. this.activeTab = "2";
  320. let params = {
  321. station: this.station,
  322. inverters: this.inverters,
  323. startdate: dayjs(this.startdate).valueOf(),
  324. enddate: dayjs(this.enddate).valueOf(),
  325. };
  326. this.getChartData(params);
  327. // this.getTableData();
  328. },
  329. //清空数据
  330. clear() {
  331. this.fittingId = "";
  332. this.seriesData = [];
  333. this.avgObj = {
  334. //平均cpz等
  335. title: "",
  336. cpavg: "",
  337. frequency: "",
  338. pcratio: "",
  339. };
  340. this.markDot = {
  341. //3-5 point点等
  342. pcl5: null,
  343. pcl10: null,
  344. pcl12: null,
  345. pcl25: null,
  346. };
  347. this.xAxisData = [];
  348. this.dataSet = "";
  349. },
  350. //是否区域划分
  351. funChartArea() {
  352. this.BASE.showLoading();
  353. if (this.seriesData.length) {
  354. if (!this.isChartArea) {
  355. // 请求一下
  356. this.seriesData[0] = {
  357. ...this.seriesData[0],
  358. markLine: {
  359. symbol: "none",
  360. label: {
  361. show: false,
  362. },
  363. lineStyle: {
  364. color: "rgba(96,174,255, 1)",
  365. },
  366. data: [
  367. {
  368. xAxis: 3,
  369. valueIndex: 0,
  370. },
  371. {
  372. xAxis: 5,
  373. valueIndex: 0,
  374. },
  375. {
  376. xAxis: 10,
  377. valueIndex: 0,
  378. },
  379. {
  380. xAxis: 12,
  381. valueIndex: 0,
  382. },
  383. {
  384. xAxis: 25,
  385. valueIndex: 0,
  386. },
  387. ],
  388. },
  389. markArea: {
  390. label: {
  391. fontSize: 13,
  392. color: "#ccc",
  393. fontWeight: "normal",
  394. fontFamily: "Arial",
  395. },
  396. itemStyle: {
  397. color: "rgba(236,245,255, 0)",
  398. },
  399. emphasis: {
  400. itemStyle: {
  401. color: "rgba(96,174,255, 0.5)",
  402. },
  403. },
  404. data: [
  405. [
  406. {
  407. name: `3~5m 偏差率: ${this.markDot.pcl5}%`,
  408. xAxis: 3,
  409. },
  410. {
  411. xAxis: 5,
  412. },
  413. ],
  414. [
  415. {
  416. name: `5~10m 偏差率: ${this.markDot.pcl10}%`,
  417. xAxis: 5,
  418. },
  419. {
  420. xAxis: 10,
  421. },
  422. ],
  423. [
  424. {
  425. name: `10~12m 偏差率: ${this.markDot.pcl12}%`,
  426. xAxis: 10,
  427. },
  428. {
  429. xAxis: 12,
  430. },
  431. ],
  432. [
  433. {
  434. name: `12~25m 偏差率: ${this.markDot.pcl25}%`,
  435. xAxis: 12,
  436. },
  437. {
  438. xAxis: 25,
  439. },
  440. ],
  441. ],
  442. },
  443. };
  444. this.isChartArea = true;
  445. this.BASE.closeLoading();
  446. } else {
  447. this.seriesData[0] = {
  448. ...this.seriesData[0],
  449. markLine: null,
  450. markArea: null,
  451. };
  452. this.isChartArea = false;
  453. this.BASE.closeLoading();
  454. }
  455. }
  456. },
  457. // // 获取表格数据
  458. // getTableData() {
  459. // this.tableLoading = true;
  460. // getPowerFittingTable({
  461. // id: this.fittingId,
  462. // }).then((res) => {
  463. // if (res.code == 200) {
  464. // this.tableColumn = res.data.title.map((o) => {
  465. // return {
  466. // prop: o.key,
  467. // width: o.des === "时间" ? 100 : 80,
  468. // label: o.des,
  469. // };
  470. // });
  471. // this.tableData = res.data.data;
  472. // this.$message.success(res.msg);
  473. // }
  474. // this.tableLoading = false;
  475. // });
  476. // },
  477. // 获取图表数据
  478. getChartData(params) {
  479. getPowerFittingChartGF(params).then((res) => {
  480. this.tableData = [];
  481. if (res.code == 200) {
  482. this.tableColumn = res.data.title.map((o) => {
  483. return {
  484. prop: o.key,
  485. label: o.des,
  486. width: o.des === "时间" ? 100 : 80,
  487. };
  488. });
  489. const wtIds = Object.keys(res.data.data);
  490. const xAxis = [];
  491. const series = [];
  492. if (!res.data.data || !wtIds.length) {
  493. this.tableLoading = false;
  494. return false;
  495. }
  496. for (const index in wtIds) {
  497. const llgl = [];
  498. const sjgl = [];
  499. for (const o of res.data.data[wtIds[index]]) {
  500. if (index === "0") {
  501. xAxis.push(o.datetime);
  502. }
  503. this.tableData.push(o);
  504. llgl.push(o.ideaP);
  505. sjgl.push(o.actualP);
  506. }
  507. series.push({
  508. name: res.data.name + "实际功率",
  509. type: "line",
  510. symbol: "line", //设定为实心点
  511. symbolSize: 0, //设定实心点的大小
  512. smooth: false, //这个是把线变成曲线
  513. data: sjgl,
  514. xAxisIndex: 0,
  515. });
  516. series.push({
  517. name: res.data.name + "理论功率",
  518. type: "line",
  519. symbol: "line", //设定为实心点
  520. symbolSize: 0, //设定实心点的大小
  521. smooth: false, //这个是把线变成曲线
  522. data: llgl,
  523. xAxisIndex: 0,
  524. });
  525. }
  526. this.xAxisData = xAxis;
  527. this.seriesData = series;
  528. console.log(this.seriesData);
  529. this.$message.success(res.msg);
  530. } else {
  531. this.tableColumn = [];
  532. this.tableData = [];
  533. this.xAxisData = {};
  534. this.seriesData = {};
  535. }
  536. this.BASE.closeLoading();
  537. });
  538. },
  539. //拟合按钮
  540. search() {
  541. this.isChartArea = false;
  542. if (!this.station || !this.inverters) {
  543. this.BASE.showMsg({
  544. msg: "场站与风机为必选项",
  545. });
  546. } else {
  547. this.getChartId();
  548. }
  549. },
  550. async funChartSelect(batch) {
  551. const wDataArr = [];
  552. const yDataArr = [];
  553. let scatterls = [];
  554. let scatterhs = [];
  555. let dataSetObj = [];
  556. this.wtData = [];
  557. if (batch?.length && this.dataSet) {
  558. scatterls = batch[0].selected[2].dataIndex;
  559. scatterhs = batch[0].selected[3].dataIndex;
  560. if (scatterls?.length || scatterhs?.length) {
  561. dataSetObj = JSON.parse(this.dataSet);
  562. if (scatterls?.length) {
  563. for (const scatterIndex of scatterls) {
  564. wDataArr.push(dataSetObj[0].source[scatterIndex].k);
  565. }
  566. }
  567. if (scatterhs?.length) {
  568. for (const scatterIndex of scatterhs) {
  569. yDataArr.push(dataSetObj[1].source[scatterIndex].k);
  570. }
  571. }
  572. const wtRes = await getPowerFittingSelectedChart({
  573. yk: yDataArr.join(","),
  574. wk: wDataArr.join(","),
  575. });
  576. if (wtRes.code === 200) {
  577. let id = 1;
  578. const tempArr = []; //用于以风机id 聚合dataArr
  579. if (wtRes.data?.length) {
  580. for (const data of wtRes.data) {
  581. if (tempArr.length) {
  582. const findIndex = tempArr.findIndex(
  583. (o) => o.wtId === data.wtId
  584. );
  585. if (findIndex !== -1) {
  586. if (!tempArr[findIndex].children) {
  587. tempArr[findIndex].children = [];
  588. }
  589. tempArr[findIndex].children.push({
  590. ...data,
  591. id: id,
  592. filter: data.filter === 0 ? "是" : "否",
  593. });
  594. id++;
  595. } else {
  596. tempArr.push({
  597. ...data,
  598. id: id,
  599. filter: data.filter === 0 ? "是" : "否",
  600. });
  601. id++;
  602. }
  603. } else {
  604. tempArr.push({
  605. ...data,
  606. id: id,
  607. filter: data.filter === 0 ? "是" : "否",
  608. });
  609. id++;
  610. }
  611. }
  612. this.wtDialog = true;
  613. this.$nextTick(() => {
  614. this.wtTab = "table";
  615. this.wtData = tempArr;
  616. });
  617. }
  618. }
  619. }
  620. }
  621. },
  622. },
  623. created() {
  624. this.getWp();
  625. },
  626. watch: {},
  627. unmounted() {},
  628. };
  629. </script>
  630. <style lang="less" scoped>
  631. .draught-fan-list {
  632. width: 100%;
  633. height: 100%;
  634. display: flex;
  635. flex-direction: column;
  636. padding: 10px 20px;
  637. .form-wrapper ::v-deep {
  638. .el-checkbox__input {
  639. display: block;
  640. }
  641. .el-input-number {
  642. width: 100%;
  643. .el-input-number__decrease,
  644. .el-input-number__increase {
  645. background: rgba(67, 81, 107, 0.2) !important;
  646. position: absolute;
  647. z-index: 10;
  648. border: 0;
  649. // height: 33px;
  650. // line-height: 33px;
  651. &:hover {
  652. color: #05be4c;
  653. }
  654. }
  655. }
  656. .el-date-editor,
  657. .el-select {
  658. width: 100%;
  659. }
  660. .el-radio-group {
  661. width: 100%;
  662. display: flex;
  663. .el-radio {
  664. flex: 1;
  665. }
  666. }
  667. .search {
  668. display: flex;
  669. align-items: center;
  670. .search-items {
  671. display: flex;
  672. align-items: center;
  673. .search-item {
  674. width: 296px;
  675. display: flex;
  676. align-items: center;
  677. margin-right: 10px;
  678. .lable {
  679. font-size: 14px;
  680. font-family: Microsoft YaHei;
  681. font-weight: 400;
  682. color: #b3b3b3;
  683. margin-right: 5px;
  684. width: 65px;
  685. white-space: nowrap;
  686. }
  687. .search-content {
  688. flex: 1;
  689. }
  690. &:nth-last-child(1) {
  691. margin-right: 0;
  692. }
  693. }
  694. .custom {
  695. width: auto;
  696. }
  697. }
  698. .search-actions {
  699. margin-left: 15px;
  700. .buttons {
  701. background-color: rgba(5, 187, 76, 0.2);
  702. border: 1px solid #3b6c53;
  703. color: #b3b3b3;
  704. font-size: 14px;
  705. &:hover,
  706. &.active {
  707. background-color: rgba(5, 187, 76, 0.5);
  708. color: #ffffff;
  709. }
  710. }
  711. }
  712. }
  713. }
  714. .el-tabs ::v-deep {
  715. height: 100%;
  716. .el-tabs__item {
  717. color: #b3b3b3;
  718. }
  719. .el-tabs__nav-wrap::after {
  720. background-color: #14221f;
  721. }
  722. .el-tabs__active-bar {
  723. background-color: #05bb4c;
  724. }
  725. .el-tabs__item.is-active,
  726. .el-tabs__item:hover {
  727. color: #05bb4c;
  728. }
  729. .el-tabs__content {
  730. height: calc(100% - 53px);
  731. }
  732. }
  733. }
  734. </style>