index.vue 20 KB

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