index.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. <template>
  2. <div class="dataAnalysisWindAna" :class="!theme ? 'themeDark' : 'themeLight'">
  3. <div class="dataAnalysisWindAnaMain">
  4. <div class="main_top">
  5. <p class="topPsty">损失电量分析</p>
  6. </div>
  7. <div class="main">
  8. <div class="treeDataMain">
  9. <tree-cop
  10. ref="treeCopRef"
  11. :data="treeData"
  12. @checkChange="funTreeCheckChange"
  13. :show-checkbox="true"
  14. :height="treeHeight"
  15. @currentChange="funCurrentChange"
  16. @refresh="funGetTree"
  17. ></tree-cop>
  18. </div>
  19. <div class="excelDataMain">
  20. <excel-cop
  21. :checkIds="excelCheckIds"
  22. :showCheckbox="excelCheckboxShow"
  23. :data="excelList"
  24. :theme="theme"
  25. :height="excelHeight"
  26. @excelChange="funExcelChange"
  27. @checkChange="funExcelCheckChange"
  28. >
  29. </excel-cop>
  30. </div>
  31. <div class="tableDataMain">
  32. <div class="px-[10px] shadow rounded-[6px] shadow-blue-500">
  33. <el-tabs v-model="activeTab">
  34. <el-tab-pane label="图表展示" name="1"> </el-tab-pane>
  35. <el-tab-pane label="表格数据" name="2"> </el-tab-pane>
  36. <table-cop
  37. class=""
  38. v-show="activeTab === '2'"
  39. :data="tableData"
  40. :showSummary="true"
  41. :summaryMethod="funSummary"
  42. :column="tableColumn"
  43. :loading="tableLoading"
  44. :theme="theme"
  45. :height="tableHeight"
  46. :tableId="tableShowId"
  47. :tableName="tableName"
  48. ></table-cop>
  49. <div
  50. v-show="activeTab === '1'"
  51. :style="{
  52. height:
  53. typeof tableHeight === 'string'
  54. ? tableHeight
  55. : tableHeight + 'px',
  56. }"
  57. class="p-[10px]"
  58. >
  59. <bar-line-chart-cop
  60. v-show="lineData.length"
  61. :height="tableHeight"
  62. :bardata="barData"
  63. :lineData="lineData"
  64. :color="barColor"
  65. lineName="理论发电量"
  66. ></bar-line-chart-cop>
  67. <el-empty
  68. v-show="!lineData.length"
  69. description="请选择条件"
  70. ></el-empty>
  71. </div>
  72. </el-tabs>
  73. </div>
  74. </div>
  75. </div>
  76. </div>
  77. </div>
  78. </template>
  79. <script setup name="prepare">
  80. import tableCop from "@/components/generatingCapacityComponent/table.vue";
  81. import excelCop from "@/components/generatingCapacityComponent/excel.vue";
  82. import treeCop from "@/components/generatingCapacityComponent/tree.vue";
  83. import barLineChartCop from "./components/barLineChart.vue";
  84. import { ElMessage } from "element-plus";
  85. import { onMounted, ref, onActivated, watch } from "vue";
  86. import { useStore } from "vuex";
  87. import httpRequest from "@/utils/request.js";
  88. import jsonData from "./components/data.json";
  89. /**配置参数 */
  90. const treeHeight = ref(window.innerHeight - 111 + "px"); //tree高度
  91. const excelHeight = ref(window.innerHeight - 111 + "px"); //excel高度
  92. const tableHeight = ref(window.innerHeight - 175 + "px");
  93. /**table 开始 */
  94. const tableShowId = ref("");
  95. const tableName = ref("");
  96. const tableFilePath = ref("");
  97. const tableColumn = ref([]);
  98. const tableLoading = ref(false);
  99. const tableData = ref([]);
  100. const funSummary = ({ columns, data }) => {
  101. const sums = [];
  102. columns.forEach((column, index) => {
  103. if (index === 0) {
  104. sums[index] = "合计";
  105. return;
  106. }
  107. const values = data.map((item) => Number(item[column.property]));
  108. if (!values.every((value) => Number.isNaN(value))) {
  109. sums[index] = values.reduce((prev, curr) => {
  110. const value = Number(curr);
  111. if (!Number.isNaN(value)) {
  112. return Number((prev + curr).toFixed(2));
  113. } else {
  114. return Number(prev.toFixed(2));
  115. }
  116. }, 0);
  117. } else {
  118. sums[index] = "--";
  119. }
  120. if (["speed", "fnlly"].includes(column.property)) {
  121. if (!Number.isNaN(sums[index])) {
  122. sums[index] = Number((sums[index] / data.length).toFixed(2));
  123. }
  124. }
  125. });
  126. return sums;
  127. };
  128. const funSubmit = async () => {
  129. if (!excelCheckIds.value.length) {
  130. ElMessage.error("请勾选要展现的项");
  131. return false;
  132. }
  133. tableLoading.value = true;
  134. tableData.value = [];
  135. barData.value = {
  136. area: [],
  137. legend: [],
  138. data: [],
  139. };
  140. lineData.value = [];
  141. const res = await httpRequest.get("/fjjxb/five/loss/cal", {
  142. params: {
  143. ids: excelCheckIds.value.join(),
  144. },
  145. });
  146. if (res.code !== 200 || !res.data.title) {
  147. tableLoading.value = false;
  148. return false;
  149. }
  150. ElMessage.success(res.msg);
  151. tableColumn.value = res.data.title.map((o) => {
  152. return {
  153. prop: o.key,
  154. label: o.des,
  155. width: o.des === "时间" ? 100 : 80,
  156. };
  157. });
  158. tableData.value = res.data.data;
  159. const name = [],
  160. data = [],
  161. llfdl = [],
  162. legend = [
  163. {
  164. name: "实际电量",
  165. icon: "rect",
  166. },
  167. {
  168. name: "计划检修损失",
  169. icon: "rect",
  170. },
  171. {
  172. name: "非计划检修损失",
  173. icon: "rect",
  174. },
  175. {
  176. name: "限电损失",
  177. icon: "rect",
  178. },
  179. {
  180. name: "受累损失",
  181. icon: "rect",
  182. },
  183. {
  184. name: "性能损失",
  185. icon: "rect",
  186. },
  187. {
  188. name: "理论发电量",
  189. icon: "circle",
  190. },
  191. ],
  192. // legend = [
  193. // "实际电量",
  194. // "计划检修损失",
  195. // "非计划检修损失",
  196. // "限电损失",
  197. // "受累损失",
  198. // "性能损失",
  199. // "理论发电量"
  200. // ],
  201. data2 = []; //项目列表
  202. // if (params.station) {
  203. // let arr = [];
  204. // let hj = res.data.data.pop();
  205. // res.data.data.forEach((ele, index) => {
  206. // arr[ele.id.split('_')[1] - 1] = ele
  207. // })
  208. // arr.push(hj);
  209. // res.data.data = arr;
  210. // }
  211. res.data.data.forEach((item, index) => {
  212. name.push(item.name);
  213. data.push([item.sjfdl, item.jhjx, item.fjhjx, item.xd, item.sl, item.xn]);
  214. llfdl.push(item.llfdl);
  215. data2.push({
  216. index: index + 1,
  217. name: item.name,
  218. llfdl: item.llfdl,
  219. sjfdl: item.sjfdl,
  220. speed: item.speed,
  221. fjhjx: item.fjhjx,
  222. jhjx: item.jhjx,
  223. sl: item.sl,
  224. xd: item.xd,
  225. xn: item.xn,
  226. fnlly: item.fnlly,
  227. is_light: false,
  228. });
  229. });
  230. if (data.length > 0) {
  231. let arr1 = [];
  232. const length = data[0].length;
  233. for (var i = 0; i < length; i++) {
  234. let arr2 = [];
  235. data.forEach((ele) => {
  236. arr2.push(ele[i]);
  237. });
  238. arr1.push(arr2);
  239. }
  240. lineData.value = llfdl;
  241. barData.value = {
  242. area: name,
  243. legend: legend,
  244. data: arr1,
  245. };
  246. }
  247. tableLoading.value = false;
  248. activeTab.value = "1";
  249. };
  250. /**barlineChart 开始 */
  251. const barData = ref({
  252. area: [],
  253. legend: [],
  254. data: [],
  255. });
  256. const lineData = ref([]);
  257. const barColor = [
  258. "#4b55ae",
  259. "#e17e23",
  260. "#ba3237",
  261. "#c531c7",
  262. "rgb(63,177,227)",
  263. "#05bb4c",
  264. ];
  265. /**tabs */
  266. const activeTab = ref("1");
  267. /**excel 开始 */
  268. const excelCheckboxShow = ref(false);
  269. const excelType = ref("");
  270. const treeCopRef = ref(); //treeCop ref
  271. const excelCheckIds = ref([]);
  272. const excelList = ref([]);
  273. const funExcelChange = async (obj) => {
  274. //点击excel项时
  275. // return false;
  276. tableName.value = "损失电量";
  277. tableFilePath.value = obj.path;
  278. };
  279. const funExcelCheckChange = ({ checkArr, data }) => {
  280. //bug
  281. excelCheckIds.value = checkArr;
  282. funSubmit();
  283. };
  284. /**prepare tree 开始 */
  285. const treeData = ref([]);
  286. const actTreeNode = ref(null); //当前激活的treeNode
  287. const funRepeatMap = (arr) => {
  288. return arr.map((o) => {
  289. if (o.children) {
  290. const findIndex = o.children.findIndex((p) => !!p.type);
  291. if (findIndex !== -1) {
  292. o.childs = o.children;
  293. o.children = [];
  294. if (!actTreeNode.value) {
  295. //判断当且仅有process获取tree时 赋值
  296. actTreeNode.value = o;
  297. }
  298. }
  299. }
  300. return {
  301. ...o,
  302. children: o.children ? funRepeatMap(o.children) : [],
  303. };
  304. });
  305. };
  306. const funGetTree = async () => {
  307. actTreeNode.value = null;
  308. const res = await httpRequest.get("/power/process/tree");
  309. treeData.value = funRepeatMap(res.data);
  310. excelList.value = [];
  311. if (actTreeNode.value) {
  312. funCurrentChange({
  313. current: actTreeNode.value,
  314. currentNode: null,
  315. });
  316. if (treeCopRef.value) {
  317. treeCopRef.value.$refs.tree.setCheckedKeys([actTreeNode.value.id]);
  318. excelCheckIds.value = actTreeNode.value.childs.map((o) => o.id);
  319. tableShowId.value = excelCheckIds.value.join(',');
  320. funSubmit();
  321. }
  322. }
  323. };
  324. const funCurrentChange = ({ current, currentNode }) => {
  325. excelCheckboxShow.value = true;
  326. if (current.childs) {
  327. excelList.value = current.childs.map((o) => {
  328. return {
  329. id: o.id,
  330. interval: o.interval,
  331. path: o.path,
  332. prepareid: o.prepareid,
  333. station: o.station,
  334. time: o.time,
  335. type: o.type,
  336. windturbine: o.windturbine,
  337. name: o.path.substring(
  338. o.path.indexOf(o.station + "_") + (o.station + "_").length
  339. ),
  340. };
  341. });
  342. } else {
  343. excelList.value = [];
  344. }
  345. };
  346. const funTreeCheckChange = ({
  347. current,
  348. checkedNodes,
  349. checkedKeys,
  350. halfCheckedNodes,
  351. halfCheckedKeys,
  352. }) => {
  353. //tree change -> excel change
  354. funCurrentChange({
  355. current,
  356. currentNode: "",
  357. });
  358. const checkIds = [];
  359. if (checkedNodes.checkedNodes.length) {
  360. let checkArr = checkedNodes.checkedNodes;
  361. checkArr.forEach((it) => {
  362. if (it.childs && it.childs.length) {
  363. it.childs.forEach((iv) => {
  364. checkIds.push(iv.id);
  365. });
  366. }
  367. });
  368. }
  369. excelCheckIds.value = checkIds;
  370. funSubmit();
  371. };
  372. /**created */
  373. const theme = ref(null);
  374. const echartsTheme = ref("");
  375. const store = useStore();
  376. watch(
  377. () => store.state.theme,
  378. (newVal, oldVal) => {
  379. theme.value = newVal;
  380. echartsTheme.value = !newVal ? "dark" : "";
  381. funGetTree();
  382. },
  383. {
  384. deep: true,
  385. }
  386. );
  387. const initPageData = () => {
  388. actTreeNode.value = null;
  389. treeData.value = funRepeatMap(JSON.parse(JSON.stringify(jsonData.treeData)));
  390. excelList.value = [];
  391. if (actTreeNode.value) {
  392. if (actTreeNode.value.childs) {
  393. excelList.value = actTreeNode.value.childs.map((o) => {
  394. return {
  395. id: o.id,
  396. interval: o.interval,
  397. path: o.path,
  398. prepareid: o.prepareid,
  399. station: o.station,
  400. time: o.time,
  401. type: o.type,
  402. windturbine: o.windturbine,
  403. isCheck: false,
  404. name: o.path.substring(
  405. o.path.indexOf(o.station + "_") + (o.station + "_").length
  406. ),
  407. };
  408. });
  409. } else {
  410. excelList.value = [];
  411. }
  412. const child = actTreeNode.value.childs[0];
  413. const obj = {
  414. path: child.path,
  415. name: child.path.substring(
  416. child.path.indexOf(child.station + "_") + (child.station + "_").length
  417. ),
  418. };
  419. tableName.value = "损失电量"
  420. tableFilePath.value = obj.path;
  421. if (treeCopRef.value) {
  422. treeCopRef.value.$refs.tree.setCheckedKeys([actTreeNode.value.id]);
  423. excelCheckIds.value = actTreeNode.value.childs.map((o) => o.id);
  424. tableShowId.value = excelCheckIds.value.join(',');
  425. tableLoading.value = true;
  426. tableData.value = [];
  427. barData.value = {
  428. area: [],
  429. legend: [],
  430. data: [],
  431. };
  432. lineData.value = [];
  433. tableColumn.value = jsonData.tableData.title.map((o) => {
  434. return {
  435. prop: o.key,
  436. label: o.des,
  437. width: o.des === "时间" ? 100 : 80,
  438. };
  439. });
  440. tableData.value = jsonData.tableData.data;
  441. const name = [],
  442. data = [],
  443. llfdl = [],
  444. legend = [
  445. {
  446. name: "实际电量",
  447. icon: "rect",
  448. },
  449. {
  450. name: "计划检修损失",
  451. icon: "rect",
  452. },
  453. {
  454. name: "非计划检修损失",
  455. icon: "rect",
  456. },
  457. {
  458. name: "限电损失",
  459. icon: "rect",
  460. },
  461. {
  462. name: "受累损失",
  463. icon: "rect",
  464. },
  465. {
  466. name: "性能损失",
  467. icon: "rect",
  468. },
  469. {
  470. name: "理论发电量",
  471. icon: "circle",
  472. },
  473. ],
  474. data2 = []; //项目列表
  475. jsonData.tableData.data.forEach((item, index) => {
  476. name.push(item.name);
  477. data.push([
  478. item.sjfdl,
  479. item.jhjx,
  480. item.fjhjx,
  481. item.xd,
  482. item.sl,
  483. item.xn,
  484. ]);
  485. llfdl.push(item.llfdl);
  486. data2.push({
  487. index: index + 1,
  488. name: item.name,
  489. llfdl: item.llfdl,
  490. sjfdl: item.sjfdl,
  491. speed: item.speed,
  492. fjhjx: item.fjhjx,
  493. jhjx: item.jhjx,
  494. sl: item.sl,
  495. xd: item.xd,
  496. xn: item.xn,
  497. fnlly: item.fnlly,
  498. is_light: false,
  499. });
  500. });
  501. if (data.length > 0) {
  502. let arr1 = [];
  503. const length = data[0].length;
  504. for (var i = 0; i < length; i++) {
  505. let arr2 = [];
  506. data.forEach((ele) => {
  507. arr2.push(ele[i]);
  508. });
  509. arr1.push(arr2);
  510. }
  511. lineData.value = llfdl;
  512. barData.value = {
  513. area: name,
  514. legend: legend,
  515. data: arr1,
  516. };
  517. }
  518. tableLoading.value = false;
  519. activeTab.value = "1";
  520. }
  521. }
  522. };
  523. /**mounted */
  524. onMounted(() => {
  525. initPageData();
  526. funGetTree();
  527. theme.value = store.state.theme;
  528. echartsTheme.value = !theme.value ? "dark" : "";
  529. tableHeight.value = window.innerHeight - 175 + "px";
  530. excelHeight.value = window.innerHeight - 111 + "px";
  531. treeHeight.value = window.innerHeight - 111 + "px";
  532. window.addEventListener("resize", () => {
  533. tableHeight.value = window.innerHeight - 175 + "px";
  534. excelHeight.value = window.innerHeight - 111 + "px";
  535. treeHeight.value = window.innerHeight - 111 + "px";
  536. });
  537. });
  538. /**activated */
  539. onActivated(() => {
  540. // funGetTree()
  541. });
  542. </script>
  543. <style lang="less" scoped>
  544. .dataAnalysisWindAna {
  545. height: 100%;
  546. .dataAnalysisWindAnaMain {
  547. height: 100%;
  548. .main_top {
  549. height: 40px;
  550. display: flex;
  551. align-items: center;
  552. .topPsty {
  553. position: relative;
  554. top: 5px;
  555. padding: 7px 20px;
  556. font-size: 12px;
  557. font-weight: 600;
  558. margin-left: 10px;
  559. border-radius: 3px;
  560. }
  561. }
  562. .main {
  563. display: flex;
  564. width: 100%;
  565. .treeDataMain,
  566. .excelDataMain,
  567. .tableDataMain {
  568. border-radius: 10px;
  569. }
  570. .treeDataMain {
  571. margin-right: 10px;
  572. padding: 10px 0 10px 10px;
  573. width: calc(19% - 20px);
  574. }
  575. .excelDataMain {
  576. margin-right: 10px;
  577. padding: 10px 0 10px 10px;
  578. width: calc(15% - 20px);
  579. }
  580. .tableDataMain {
  581. padding: 10px;
  582. width: calc(66% - 20px);
  583. position: relative;
  584. .butten_com {
  585. position: absolute;
  586. right: 20px;
  587. z-index: 111111;
  588. }
  589. }
  590. }
  591. }
  592. }
  593. .themeDark {
  594. .dataAnalysisWindAnaMain {
  595. .main_top {
  596. .topPsty {
  597. color: #1c99ff;
  598. background: #1e2126;
  599. }
  600. }
  601. .main {
  602. background: #13171e;
  603. .treeDataMain {
  604. background: transparent;
  605. }
  606. .excelDataMain {
  607. background: #313233;
  608. }
  609. .tableDataMain {
  610. margin-top: 5px;
  611. background: #212223;
  612. }
  613. }
  614. }
  615. }
  616. .themeLight {
  617. padding: 0;
  618. .dataAnalysisWindAnaMain {
  619. .main_top {
  620. .topPsty {
  621. color: #2778ff;
  622. background: #ffffff;
  623. }
  624. }
  625. .main {
  626. background: #e6e8f2;
  627. .treeDataMain {
  628. background: transparent;
  629. }
  630. .excelDataMain {
  631. background: #f4f6fb;
  632. }
  633. .tableDataMain {
  634. background: #fff;
  635. margin-top: 5px;
  636. }
  637. }
  638. }
  639. }
  640. </style>