index.vue 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497
  1. <template>
  2. <div class="dataAnalysisHotAns" :class="!theme ? 'themeDark' : 'themeLight'">
  3. <div class="dataAnalysisHotAnsMain">
  4. <div class="main_top">
  5. <p class="topPsty">温度与功率分析</p>
  6. </div>
  7. <div class="main">
  8. <div class="main">
  9. <div class="treeDataMain">
  10. <tree-cop
  11. :data="processTreeData"
  12. :height="treeHeight"
  13. :currentNodeKey="currentNodeKey"
  14. @currentChange="funProcessCurrentChange"
  15. @refresh="funGetProcessTree"
  16. ></tree-cop>
  17. </div>
  18. <div class="excelDataMain">
  19. <excel-cop
  20. :data="excelList"
  21. :height="excelHeight"
  22. @excelChange="funExcelChange"
  23. :theme="theme"
  24. >
  25. </excel-cop>
  26. </div>
  27. <div class="tableDataMain">
  28. <div class="">
  29. <el-tabs v-model="activeTab">
  30. <el-tab-pane label="温度曲线" name="1"> </el-tab-pane>
  31. <el-tab-pane label="温度与功率" name="2"> </el-tab-pane>
  32. <el-tab-pane
  33. :label="`表格数据${
  34. tableData?.length ? ' (' + tableData.length + '个)' : ''
  35. }`"
  36. name="3"
  37. >
  38. </el-tab-pane>
  39. <div v-if="activeTab === '2'" :style="{ height: tableHeight }">
  40. <div style="height: 49%">
  41. <el-icon
  42. :style="!theme ? 'color: #fff' : ''"
  43. class="chartIcon"
  44. size="18"
  45. @click="
  46. funActCop(
  47. {
  48. xAxis: barxAxis,
  49. yAxis: baryAxis,
  50. series: barSeries,
  51. },
  52. 'barChartCop'
  53. )
  54. "
  55. >
  56. <ZoomIn />
  57. </el-icon>
  58. <bar-chart-cop
  59. width="100%"
  60. height="100%"
  61. :subtext="`平均功率-额定功率 ${powerproduction}`"
  62. :xAxis="barxAxis"
  63. :theme="theme"
  64. :echartsTheme="echartsTheme"
  65. :yAxis="baryAxis"
  66. :series="barSeries"
  67. >
  68. </bar-chart-cop>
  69. </div>
  70. <div style="height: 49%">
  71. <el-icon
  72. :style="!theme ? 'color: #fff' : ''"
  73. class="chartIcon"
  74. size="18"
  75. @click="
  76. funActCop(
  77. {
  78. xAxis: linexAxis,
  79. yAxis: lineyAxis,
  80. series: lineSeries,
  81. },
  82. 'lineChartCop'
  83. )
  84. "
  85. >
  86. <ZoomIn />
  87. </el-icon>
  88. <line-chart-cop
  89. class=""
  90. height="100%"
  91. width="100%"
  92. :xAxis="linexAxis"
  93. :yAxis="lineyAxis"
  94. :series="lineSeries"
  95. :theme="theme"
  96. :echartsTheme="echartsTheme"
  97. :subtext="`额定功率温度分析 ${powerproduction}`"
  98. :dataset="lineDataSet"
  99. >
  100. </line-chart-cop>
  101. </div>
  102. </div>
  103. <div
  104. v-if="activeTab === '1'"
  105. :style="{
  106. height:
  107. typeof tableHeight === 'string'
  108. ? tableHeight
  109. : tableHeight + 'px',
  110. }"
  111. class="p-[10px]"
  112. >
  113. <CurrentScatterChart
  114. ref="chartRef"
  115. width="100%"
  116. :height="`calc( ${tableHeight} - 20px )`"
  117. :chartTitle="
  118. avgObj.title +
  119. '&nbsp;&nbsp;' +
  120. '平均Cp值:' +
  121. avgObj.cpavg +
  122. '; 静风频率:' +
  123. avgObj.frequency +
  124. '%; 曲线偏差率:' +
  125. avgObj.pcratio +
  126. '%'
  127. "
  128. :xAxisData="xAxisData"
  129. :yAxisData="{ splitLine: { show: false } }"
  130. :seriesData="seriesData"
  131. :showLegend="true"
  132. :brushSelected="false"
  133. :maxMinData="maxMinData"
  134. :theme="theme"
  135. :echartsTheme="echartsTheme"
  136. :dataSet="dataSet"
  137. @getSelected="funhotChartSelect"
  138. />
  139. </div>
  140. <div v-if="activeTab === '3'" :style="{ height: tableHeight }">
  141. <table-cop
  142. class=""
  143. :data="tableData"
  144. :column="tableColumn"
  145. :theme="theme"
  146. fromTableId="3"
  147. :height="tableHeight"
  148. :tableId="tableShowId"
  149. :tableName="tableName"
  150. :tableFilePath="tableFilePath"
  151. style="position: relative; top: -15px"
  152. ></table-cop>
  153. </div>
  154. </el-tabs>
  155. </div>
  156. </div>
  157. </div>
  158. </div>
  159. </div>
  160. <el-dialog
  161. class="windLifeDialog"
  162. draggable
  163. width="80%"
  164. v-model="dialog"
  165. :title="actDiaTitle"
  166. >
  167. <el-form class="whitespace-nowrap" :inline="true" :model="queryForm">
  168. <el-form-item label="" class="!mb-0">
  169. <el-select
  170. style="width: 110px"
  171. v-model="queryForm.checkIds"
  172. clearable
  173. @clear="checkAll = false"
  174. collapse-tags
  175. multiple
  176. >
  177. <el-option
  178. label="全选"
  179. :class="{ selected: checkAll }"
  180. @click="funCheckAll"
  181. ></el-option>
  182. <el-option
  183. v-for="item in chartExcelList"
  184. :key="item.id"
  185. :value="item.id"
  186. :label="item.name"
  187. >
  188. </el-option>
  189. </el-select>
  190. </el-form-item>
  191. <el-form-item class="!mb-0">
  192. <submit-btn desc="查询" @click="funDiaSubmit"></submit-btn>
  193. <submit-btn desc="导出" @click="funDiaExport"></submit-btn>
  194. </el-form-item>
  195. </el-form>
  196. <div v-loading="exportLoading">
  197. <el-row
  198. ref="diaPanelRef"
  199. style="height: 650px; overflow-y: auto; over-x: hidden"
  200. >
  201. <el-col
  202. :span="actCopList.length > 1 ? 12 : 24"
  203. v-for="item in actCopList"
  204. :key="item.id"
  205. style="height: 650px"
  206. >
  207. <component
  208. :is="item.actCop"
  209. width="100%"
  210. height="100%"
  211. :xAxis="item.xAxis"
  212. :subtext="item.subtext"
  213. :title="item.title"
  214. :series="item.series"
  215. :isDiaAlone="actCopList.length === 1"
  216. @dblclick="funDbClick(item)"
  217. :yAxis="item.yAxis"
  218. :dataset="item.dataset"
  219. :brush="item.isBrush"
  220. :theme="theme"
  221. :echartsTheme="echartsTheme"
  222. @getSelected="funChartSelect"
  223. ></component>
  224. </el-col>
  225. </el-row>
  226. </div>
  227. </el-dialog>
  228. <el-dialog
  229. custom-class="windLifeDialog warn-table"
  230. v-model="wtDialog"
  231. draggable
  232. title="风机功率点位"
  233. >
  234. <el-tabs v-model="wtTab">
  235. <el-tab-pane label="数据" name="table">
  236. <el-table :data="wtData" row-key="id" :max-height="550">
  237. <el-table-column property="wtId" align="center" label="风机" />
  238. <el-table-column
  239. property="time"
  240. sortable
  241. :width="160"
  242. align="center"
  243. label="时间"
  244. />
  245. <el-table-column
  246. property="speed"
  247. sortable
  248. align="center"
  249. label="风速(m/s)"
  250. />
  251. <el-table-column
  252. property="power"
  253. sortable
  254. align="center"
  255. label="功率(kW)"
  256. />
  257. <el-table-column
  258. property="rr"
  259. sortable
  260. align="center"
  261. label="转速"
  262. />
  263. <el-table-column
  264. property="filter"
  265. sortable
  266. align="center"
  267. label="是否有用点"
  268. />
  269. </el-table>
  270. </el-tab-pane>
  271. <el-tab-pane label="故障" name="problem" disabled> </el-tab-pane>
  272. <el-tab-pane label="预警" name="warning" disabled> </el-tab-pane>
  273. </el-tabs>
  274. </el-dialog>
  275. </div>
  276. </template>
  277. <script setup name="prepare">
  278. import excelCop from "@/components/generatingCapacityComponent/excel.vue";
  279. import treeCop from "@/components/generatingCapacityComponent/tree.vue";
  280. import tableCop from "@/components/generatingCapacityComponent/table.vue";
  281. import barChartCop from "./components/barChart.vue";
  282. import lineChartCop from "./components/lineChart.vue";
  283. import {
  284. shallowRef,
  285. ref,
  286. nextTick,
  287. onActivated,
  288. onMounted,
  289. reactive,
  290. watch,
  291. } from "vue";
  292. import { useStore } from "vuex";
  293. import httpRequest from "@/utils/request.js";
  294. import tools from "@tools/htmlToPdf.js";
  295. import { ElMessage } from "element-plus";
  296. import util from "@tools/util";
  297. import CurrentScatterChart from "./components/current-scatter-chart.vue";
  298. import jsonData from "./components/data.json";
  299. /**配置参数 */
  300. const treeHeight = ref(window.innerHeight - 111 + "px"); //tree高度
  301. const excelHeight = ref(window.innerHeight - 111 + "px"); //excel高度
  302. const tableHeight = ref(window.innerHeight - 171 + "px");
  303. /** 额定功率 */
  304. const powerproduction = ref("");
  305. const tableData = ref([]);
  306. const tableColumn = ref([]);
  307. const currentNodeKey = ref("");
  308. const tableDataGet = async () => {
  309. const res = await httpRequest.get("/temperature/show", {
  310. params: {
  311. id: excelCheckIds.value.join(),
  312. },
  313. });
  314. tableColumn.value = res.data.title.map((o) => {
  315. return {
  316. prop: o.key,
  317. label: o.des,
  318. width: o.des === "时间" ? 100 : 80,
  319. };
  320. });
  321. tableData.value = res.data.data;
  322. };
  323. /**excel 开始 */
  324. const excelCheckboxShow = ref(false);
  325. const excelCheckIds = ref([]);
  326. const excelList = ref([]);
  327. const tableShowId = ref("");
  328. const tableName = ref("");
  329. const tableFilePath = ref("");
  330. const funExcelChange = async (obj) => {
  331. //点击excel项时
  332. /**次代码供温度功率曲线分析使用 */
  333. excelCheckIds.value = [obj.id]; //当为单选展示风机图表时
  334. tableShowId.value = obj.id;
  335. let tableX = [
  336. "未满发样板机_",
  337. "满发样板机_",
  338. "样板机_",
  339. "未满发_",
  340. "满发_",
  341. "_",
  342. ];
  343. for (let i = 0; i < tableX.length; i++) {
  344. let it = tableX[i];
  345. if (obj.name.indexOf(it) !== -1) {
  346. tableName.value = obj.name.substring(0, obj.name.indexOf(it));
  347. break;
  348. }
  349. }
  350. tableFilePath.value = obj.path;
  351. chartExcelList.value = excelList.value.map((o) => {
  352. return {
  353. ...o,
  354. name: o.code,
  355. };
  356. }); // 选中excel当前项时, excel列表赋值给dialog 下拉框
  357. queryForm.checkIds = excelList.value.map((o) => o.id);
  358. checkAll.value = true;
  359. funSubmit();
  360. tableDataGet();
  361. /**---------------------------- */
  362. // activeTab.value = '1'
  363. isChartArea.value = false;
  364. let chartRes = {
  365. scatterhs: [[]],
  366. scatterls: [[]],
  367. sjgl: [[]],
  368. llgl: [[]],
  369. cpz: [[]],
  370. };
  371. let chartResponse = null;
  372. if (obj.type === "fitting") {
  373. chartResponse = await httpRequest.get("/temperature/curve/analysis", {
  374. params: {
  375. id: obj.id,
  376. p: 1,
  377. },
  378. });
  379. }
  380. if (chartResponse && chartResponse.code === 200) {
  381. chartRes = chartResponse.data;
  382. maxMinData.value = [chartRes.maxhjwd, chartRes.minhjwd];
  383. markDot.pcl5 = chartRes.obj.pc5ratio;
  384. markDot.pcl10 = chartRes.obj.pc10ratio;
  385. markDot.pcl12 = chartRes.obj.pc12ratio;
  386. markDot.pcl25 = chartRes.obj.pc25ratio;
  387. avgObj.title = chartRes.obj.path
  388. .substring(
  389. chartRes.obj.path.indexOf(chartRes.obj.station + "_") +
  390. (chartRes.obj.station + "_").length
  391. )
  392. .split("_")[0];
  393. avgObj.cpavg = Number(chartRes.obj.cpavg).toFixed(2);
  394. avgObj.frequency = Number(chartRes.obj.frequency).toFixed(2);
  395. avgObj.pcratio = Number(chartRes.obj.pcratio).toFixed(2);
  396. const color = [
  397. "#1C99FF",
  398. "#FF8700",
  399. "#3D54BE",
  400. "#fa8c16",
  401. "#1DA0D7",
  402. "#DD5044",
  403. ];
  404. seriesData.value = [
  405. {
  406. name: "拟合功率",
  407. type: "line",
  408. symbol: "line", //设定为实心点
  409. symbolSize: 0, //设定实心点的大小
  410. smooth: true, //这个是把线变成曲线
  411. data: chartRes.sjgl,
  412. xAxisIndex: 0,
  413. },
  414. {
  415. name: "保证功率",
  416. type: "line",
  417. symbol: "line", //设定为实心点
  418. symbolSize: 0, //设定实心点的大小
  419. smooth: true, //这个是把线变成曲线
  420. data: chartRes.llgl,
  421. xAxisIndex: 0,
  422. },
  423. {
  424. type: "effectScatter",
  425. showEffectOn: "emphasis",
  426. rippleEffect: {
  427. scale: 1,
  428. },
  429. name: "数据散点",
  430. symbolSize: 5,
  431. // symbolSize: (data) => {
  432. // return data.s ? data.s > 10 ? 10 : data.s : 4
  433. // },
  434. // datasetIndex: 1,
  435. // encode: {
  436. // x: 'x',
  437. // y: 'y'
  438. // },
  439. data: chartRes.scatter,
  440. xAxisIndex: 0,
  441. yAxisIndex: 0,
  442. },
  443. ];
  444. }
  445. };
  446. const funExcelCheckChange = ({ checkArr, data }) => {
  447. excelCheckIds.value = checkArr;
  448. };
  449. /**prepare tree 开始 */
  450. const treeData = ref([]);
  451. const actTreeNode = ref(null); //当前激活的treeNode
  452. const funRepeatMap = (arr) => {
  453. return arr.map((o) => {
  454. if (o.children) {
  455. const findIndex = o.children.findIndex((p) => !!p.type);
  456. if (findIndex !== -1) {
  457. o.childs = o.children;
  458. o.children = [];
  459. if (!actTreeNode.value) {
  460. //判断当且仅有process获取tree时 赋值
  461. actTreeNode.value = o;
  462. }
  463. }
  464. }
  465. return {
  466. ...o,
  467. children: o.children ? funRepeatMap(o.children) : [],
  468. };
  469. });
  470. };
  471. const funCurrentChange = ({ current, currentNode }) => {
  472. excelCheckboxShow.value = true;
  473. if (current.childs) {
  474. excelList.value = current.childs.map((o) => {
  475. return {
  476. id: o.id,
  477. code: o.code,
  478. interval: o.interval,
  479. path: o.path,
  480. prepareid: o.prepareid,
  481. station: o.station,
  482. time: o.time,
  483. type: o.type,
  484. windturbine: o.windturbine,
  485. name: o.path.substring(
  486. o.path.indexOf(o.station + "_") + (o.station + "_").length
  487. ),
  488. };
  489. });
  490. } else {
  491. excelList.value = [];
  492. }
  493. };
  494. /**process tree 开始 */
  495. const processTreeData = ref([]);
  496. const funGetProcessTree = async () => {
  497. //flag控制是否获取tree的第一项 true为可获取
  498. actTreeNode.value = null;
  499. const res = await httpRequest.get("/power/fitting/tree");
  500. excelList.value = [];
  501. processTreeData.value = funRepeatMap(res.data); //flag控制对actTreeNode赋值
  502. if (actTreeNode.value) {
  503. funProcessCurrentChange({
  504. current: actTreeNode.value,
  505. currentNode: null,
  506. });
  507. const child = actTreeNode.value.childs[0];
  508. const obj = {
  509. id: child.id,
  510. interval: child.interval,
  511. path: child.path,
  512. prepareid: child.prepareid,
  513. station: child.station,
  514. time: child.time,
  515. type: child.type,
  516. windturbine: child.windturbine,
  517. name: child.path.substring(
  518. child.path.indexOf(child.station + "_") + (child.station + "_").length
  519. ),
  520. };
  521. currentNodeKey.value = actTreeNode.value?.id || "";
  522. funExcelChange(obj);
  523. }
  524. };
  525. const funProcessCurrentChange = ({ current, currentNode }) => {
  526. if (current.childs) {
  527. excelList.value = current.childs.map((o) => {
  528. return {
  529. id: o.id,
  530. code: o.code,
  531. interval: o.interval,
  532. path: o.path,
  533. prepareid: o.prepareid,
  534. station: o.station,
  535. time: o.time,
  536. type: o.type,
  537. windturbine: o.windturbine,
  538. name: o.path.substring(
  539. o.path.indexOf(o.station + "_") + (o.station + "_").length
  540. ),
  541. };
  542. });
  543. if (excelList.value.length > 0) {
  544. funExcelChange(excelList.value[0]);
  545. }
  546. } else {
  547. excelList.value = [];
  548. }
  549. };
  550. /**chart */
  551. let chartId = 1;
  552. const powerproductionNum = ref(0);
  553. /**search 开始 */
  554. const funSubmit = async () => {
  555. const tempRes = await httpRequest.get("/temperature/rated/power", {
  556. params: {
  557. ids: excelCheckIds.value.join(","),
  558. },
  559. });
  560. if (tempRes.code === 200) {
  561. if (tempRes.data.length) {
  562. for (const chart of tempRes.data) {
  563. powerproduction.value = `(额定功率=${chart.power.powerProduction}kW)`;
  564. powerproductionNum.value = chart.power.powerProduction;
  565. barxAxis.data = Object.keys(chart.res1);
  566. barSeries[0].data = Object.values(chart.res1);
  567. barSeries[0].markLine.data = [
  568. {
  569. yAxis: 0,
  570. },
  571. ];
  572. chartId++;
  573. lineSeries.value = [
  574. {
  575. type: "effectScatter",
  576. showEffectOn: "emphasis",
  577. rippleEffect: {
  578. scale: 1,
  579. },
  580. legendHoverLink: false,
  581. name: "",
  582. symbolSize: 5,
  583. data: chart.res2,
  584. yAxisIndex: 0,
  585. markLine: {
  586. symbol: "none",
  587. label: {
  588. show: false,
  589. },
  590. lineStyle: {
  591. color: "#F72C5B",
  592. },
  593. data: [
  594. {
  595. yAxis: powerproductionNum.value,
  596. },
  597. ],
  598. },
  599. },
  600. ];
  601. chartId++;
  602. }
  603. }
  604. }
  605. };
  606. /**lineChart */
  607. const linexAxis = reactive({
  608. type: "value",
  609. name: "°C",
  610. splitLine: {
  611. show: false,
  612. },
  613. axisTick: {
  614. show: true,
  615. },
  616. axisLine: {
  617. onZero: false,
  618. },
  619. });
  620. const lineyAxis = reactive([
  621. {
  622. type: "value",
  623. name: "kW",
  624. splitLine: {
  625. show: false,
  626. },
  627. axisTick: {
  628. show: true,
  629. },
  630. axisLine: {
  631. onZero: false,
  632. },
  633. },
  634. ]);
  635. const lineSeries = ref([]);
  636. const lineDataSet = reactive([
  637. {
  638. source: [],
  639. },
  640. ]);
  641. // 圈选散点触发函数
  642. const funChartSelect = async (batch) => {
  643. const wDataArr = [];
  644. const yDataArr = [];
  645. let scatterls = [];
  646. let dataSetObj = [];
  647. wtData.value = [];
  648. if (batch.length && actCopList.value[0].dataset) {
  649. scatterls = batch[0].selected[1].dataIndex;
  650. if (scatterls.length) {
  651. dataSetObj = JSON.parse(actCopList.value[0].dataset);
  652. if (scatterls.length) {
  653. for (const scatterIndex of scatterls) {
  654. wDataArr.push(dataSetObj[0].source[scatterIndex].k);
  655. }
  656. }
  657. const wtRes = await httpRequest.get("/power/fitting/filter", {
  658. params: {
  659. yk: yDataArr.join(","),
  660. wk: wDataArr.join(","),
  661. },
  662. });
  663. if (wtRes.code === 200) {
  664. let id = 1;
  665. const tempArr = []; //用于以风机id 聚合dataArr
  666. if (wtRes.data.length) {
  667. for (const data of wtRes.data) {
  668. if (tempArr.length) {
  669. const findIndex = tempArr.findIndex((o) => o.wtId === data.wtId);
  670. if (findIndex !== -1) {
  671. if (!tempArr[findIndex].children) {
  672. tempArr[findIndex].children = [];
  673. }
  674. tempArr[findIndex].children.push({
  675. ...data,
  676. id: id,
  677. filter: data.filter === 0 ? "是" : "否",
  678. });
  679. id++;
  680. } else {
  681. tempArr.push({
  682. ...data,
  683. id: id,
  684. filter: data.filter === 0 ? "是" : "否",
  685. });
  686. id++;
  687. }
  688. } else {
  689. tempArr.push({
  690. ...data,
  691. id: id,
  692. filter: data.filter === 0 ? "是" : "否",
  693. });
  694. id++;
  695. }
  696. }
  697. wtDialog.value = true;
  698. nextTick(() => {
  699. wtTab.value = "table";
  700. wtData.value = tempArr;
  701. });
  702. }
  703. }
  704. }
  705. }
  706. };
  707. /**barChart */
  708. const barxAxis = reactive({
  709. type: "category",
  710. name: "℃",
  711. data: [],
  712. splitLine: {
  713. show: false,
  714. },
  715. axisTick: {
  716. show: true,
  717. },
  718. axisLine: {
  719. onZero: false,
  720. },
  721. });
  722. const baryAxis = reactive({
  723. type: "value",
  724. name: "kW",
  725. splitLine: {
  726. show: false,
  727. },
  728. axisTick: {
  729. show: true,
  730. },
  731. axisLine: {
  732. onZero: false,
  733. },
  734. });
  735. const barSeries = reactive([
  736. {
  737. name: "",
  738. type: "bar",
  739. data: [],
  740. markLine: {
  741. symbol: "none",
  742. label: {
  743. show: false,
  744. },
  745. lineStyle: {
  746. color: "#F72C5B",
  747. },
  748. data: [],
  749. },
  750. },
  751. ]);
  752. /**chart Data */
  753. const avgObj = reactive({
  754. //平均cpz等
  755. title: "",
  756. cpavg: "",
  757. frequency: "",
  758. pcratio: "",
  759. });
  760. const markDot = reactive({
  761. //3-5 point点等
  762. pcl5: null,
  763. pcl10: null,
  764. pcl12: null,
  765. pcl25: null,
  766. });
  767. const xAxisData = ref([]);
  768. const chartRef = ref(); //chart 的ref
  769. const seriesData = ref([]);
  770. const maxMinData = ref([]);
  771. const isChartArea = ref(false); // 用来控制图表是否区域划分
  772. const dataSet = ref("");
  773. const funhotChartSelect = async (batch) => {
  774. const wDataArr = [];
  775. const yDataArr = [];
  776. let scatterls = [];
  777. let scatterhs = [];
  778. let dataSetObj = [];
  779. wtData.value = [];
  780. if (batch.length && dataSet.value) {
  781. scatterls = batch[0].selected[2].dataIndex;
  782. scatterhs = batch[0].selected[3].dataIndex;
  783. if (scatterls.length || scatterhs.length) {
  784. dataSetObj = JSON.parse(dataSet.value);
  785. if (scatterls.length) {
  786. for (const scatterIndex of scatterls) {
  787. wDataArr.push(dataSetObj[0].source[scatterIndex].k);
  788. }
  789. }
  790. if (scatterhs.length) {
  791. for (const scatterIndex of scatterhs) {
  792. yDataArr.push(dataSetObj[1].source[scatterIndex].k);
  793. }
  794. }
  795. const wtRes = await httpRequest.get("/power/fitting/filter", {
  796. params: {
  797. yk: yDataArr.join(","),
  798. wk: wDataArr.join(","),
  799. },
  800. });
  801. if (wtRes.code === 200) {
  802. let id = 1;
  803. const tempArr = []; //用于以风机id 聚合dataArr
  804. if (wtRes.data.length) {
  805. for (const data of wtRes.data) {
  806. if (tempArr.length) {
  807. const findIndex = tempArr.findIndex((o) => o.wtId === data.wtId);
  808. if (findIndex !== -1) {
  809. if (!tempArr[findIndex].children) {
  810. tempArr[findIndex].children = [];
  811. }
  812. tempArr[findIndex].children.push({
  813. ...data,
  814. id: id,
  815. filter: data.filter === 0 ? "是" : "否",
  816. });
  817. id++;
  818. } else {
  819. tempArr.push({
  820. ...data,
  821. id: id,
  822. filter: data.filter === 0 ? "是" : "否",
  823. });
  824. id++;
  825. }
  826. } else {
  827. tempArr.push({
  828. ...data,
  829. id: id,
  830. filter: data.filter === 0 ? "是" : "否",
  831. });
  832. id++;
  833. }
  834. }
  835. wtDialog.value = true;
  836. nextTick(() => {
  837. wtTab.value = "table";
  838. wtData.value = tempArr;
  839. });
  840. }
  841. }
  842. }
  843. }
  844. };
  845. const funChartArea = () => {
  846. if (seriesData.value.length) {
  847. if (!isChartArea.value) {
  848. // 请求一下
  849. seriesData.value[0] = {
  850. ...seriesData.value[0],
  851. markLine: {
  852. symbol: "none",
  853. label: {
  854. show: false,
  855. },
  856. lineStyle: {
  857. color: "rgba(96,174,255, 1)",
  858. },
  859. data: [
  860. {
  861. xAxis: 3,
  862. valueIndex: 0,
  863. },
  864. {
  865. xAxis: 5,
  866. valueIndex: 0,
  867. },
  868. {
  869. xAxis: 10,
  870. valueIndex: 0,
  871. },
  872. {
  873. xAxis: 12,
  874. valueIndex: 0,
  875. },
  876. {
  877. xAxis: 25,
  878. valueIndex: 0,
  879. },
  880. ],
  881. },
  882. markArea: {
  883. label: {
  884. fontSize: util.vh(12),
  885. },
  886. itemStyle: {
  887. color: "rgba(236,245,255, 0)",
  888. },
  889. emphasis: {
  890. itemStyle: {
  891. color: "rgba(96,174,255, 0.5)",
  892. },
  893. },
  894. data: [
  895. [
  896. {
  897. name: `3~5m 偏差率: ${markDot.pcl5}%`,
  898. xAxis: 3,
  899. },
  900. {
  901. xAxis: 5,
  902. },
  903. ],
  904. [
  905. {
  906. name: `5~10m 偏差率: ${markDot.pcl10}%`,
  907. xAxis: 5,
  908. },
  909. {
  910. xAxis: 10,
  911. },
  912. ],
  913. [
  914. {
  915. name: `10~12m 偏差率: ${markDot.pcl12}%`,
  916. xAxis: 10,
  917. },
  918. {
  919. xAxis: 12,
  920. },
  921. ],
  922. [
  923. {
  924. name: `12~25m 偏差率: ${markDot.pcl25}%`,
  925. xAxis: 12,
  926. },
  927. {
  928. xAxis: 25,
  929. },
  930. ],
  931. ],
  932. },
  933. };
  934. isChartArea.value = true;
  935. } else {
  936. seriesData.value[0] = {
  937. ...seriesData.value[0],
  938. markLine: null,
  939. markArea: null,
  940. };
  941. isChartArea.value = false;
  942. }
  943. }
  944. };
  945. /**dialog 数据 */
  946. const wtDialog = ref(false);
  947. const wtData = ref([]);
  948. const wtTab = ref("table");
  949. /**dialog */
  950. const dialog = ref(false);
  951. const actChartName = ref("");
  952. const actDiaTitle = ref("");
  953. const diaPanelRef = ref();
  954. const exportLoading = ref(false);
  955. const actCopList = ref([
  956. // {
  957. // xAxis: [],
  958. // subtext: '',
  959. // title: '',
  960. // isRadar: false,
  961. // series: [],
  962. // yAxis: [],
  963. // dataset: []
  964. // }
  965. ]);
  966. // 作为actCopList的备份 在actCopList赋值多个时 同时赋值, 在dialog弹出时清空. 作用: 在actCopList变化时, 重新赋值原始数据
  967. const actCopListBak = ref([]);
  968. const checkAll = ref(true);
  969. const queryForm = reactive({
  970. checkIds: [],
  971. });
  972. const funCheckAll = () => {
  973. checkAll.value = !checkAll.value;
  974. if (checkAll.value) {
  975. queryForm.checkIds = chartExcelList.value.map((o) => o.id);
  976. } else {
  977. queryForm.checkIds = [];
  978. }
  979. };
  980. const chartExcelList = ref([]); //dialog 下拉项
  981. const funActCop = (obj, type) => {
  982. switch (type) {
  983. case "barChartCop":
  984. actChartName.value = "barChartCop";
  985. obj.actCop = shallowRef(barChartCop);
  986. actDiaTitle.value = "平均功率-额定功率";
  987. break;
  988. case "lineChartCop":
  989. actChartName.value = "lineChartCop";
  990. obj.actCop = shallowRef(lineChartCop);
  991. actDiaTitle.value = "额定功率温度分析";
  992. break;
  993. // case 'CurrentScatterChartCop':
  994. // actChartName.value = 'CurrentScatterChartCop'
  995. // obj.actCop = shallowRef(CurrentScatte // console.log(res)rChartCop)
  996. // actDiaTitle.value = '静态偏航对风分析图'
  997. // break
  998. }
  999. obj.isBrush = false;
  1000. obj.id = chartId;
  1001. chartId++;
  1002. dialog.value = true;
  1003. actCopListBak.value = [];
  1004. nextTick(() => {
  1005. actCopList.value = [obj];
  1006. });
  1007. };
  1008. const funDiaSubmit = async () => {
  1009. let url = "";
  1010. switch (actChartName.value) {
  1011. case "barChartCop":
  1012. url = "/temperature/rated/power";
  1013. break;
  1014. case "lineChartCop":
  1015. url = "/temperature/rated/power";
  1016. break;
  1017. // case 'CurrentScatterChartCop':
  1018. // url = '' //暂无接口
  1019. // break
  1020. }
  1021. if (url) {
  1022. const res = await httpRequest.get(url, {
  1023. params: {
  1024. ids: queryForm.checkIds.join(","),
  1025. mode: 0,
  1026. },
  1027. });
  1028. if (res.code === 200) {
  1029. actCopList.value = [];
  1030. actCopListBak.value = []; //清空备份
  1031. if (res.data.length) {
  1032. for (const chart of res.data) {
  1033. if (actChartName.value === "barChartCop") {
  1034. actCopList.value.push({
  1035. id: chartId,
  1036. isBrush: false,
  1037. actCop: shallowRef(barChartCop),
  1038. title: chart.wt,
  1039. subtext: `平均功率-额定功率(额定功率=${chart.power.powerProduction}kW)`,
  1040. xAxis: {
  1041. ...barxAxis,
  1042. data: Object.keys(chart.res1),
  1043. },
  1044. yAxis: baryAxis,
  1045. series: [
  1046. {
  1047. name: "",
  1048. type: "bar",
  1049. data: Object.values(chart.res1),
  1050. markLine: {
  1051. symbol: "none",
  1052. label: {
  1053. show: false,
  1054. },
  1055. lineStyle: {
  1056. color: "#F72C5B",
  1057. },
  1058. data: [
  1059. {
  1060. yAxis: 0,
  1061. },
  1062. ],
  1063. },
  1064. },
  1065. ],
  1066. });
  1067. chartId++;
  1068. }
  1069. if (actChartName.value === "lineChartCop") {
  1070. actCopList.value.push({
  1071. id: chartId,
  1072. isBrush: false,
  1073. actCop: shallowRef(lineChartCop),
  1074. title: chart.wt,
  1075. subtext: `额定功率温度分析(额定功率=${chart.power.powerProduction}kW)`,
  1076. xAxis: linexAxis,
  1077. yAxis: lineyAxis,
  1078. dataset: lineDataSet,
  1079. series: [
  1080. {
  1081. type: "effectScatter",
  1082. showEffectOn: "emphasis",
  1083. rippleEffect: {
  1084. scale: 1,
  1085. },
  1086. legendHoverLink: false,
  1087. name: "",
  1088. symbolSize: 5,
  1089. data: chart.res2,
  1090. yAxisIndex: 0,
  1091. markLine: {
  1092. symbol: "none",
  1093. label: {
  1094. show: false,
  1095. },
  1096. lineStyle: {
  1097. color: "#F72C5B",
  1098. },
  1099. data: [
  1100. {
  1101. yAxis: chart.power.powerProduction,
  1102. },
  1103. ],
  1104. },
  1105. },
  1106. ],
  1107. });
  1108. chartId++;
  1109. }
  1110. }
  1111. actCopListBak.value = actCopList.value;
  1112. }
  1113. }
  1114. }
  1115. };
  1116. const funDiaExport = () => {
  1117. exportLoading.value = true;
  1118. tools.scrollToPDF(diaPanelRef.value, actDiaTitle.value, () => {
  1119. exportLoading.value = false;
  1120. });
  1121. };
  1122. const funDbClick = (obj) => {
  1123. if (actCopListBak.value.length > 1) {
  1124. //判断大于1时, 才有双击放大功能
  1125. if (actCopList.value.length === 1) {
  1126. actCopList.value = actCopListBak.value;
  1127. } else {
  1128. actCopList.value = [obj];
  1129. }
  1130. }
  1131. };
  1132. /**tab */
  1133. const activeTab = ref("1");
  1134. /**created */
  1135. // funGetProcessTree()
  1136. const theme = ref(null);
  1137. const echartsTheme = ref("");
  1138. const store = useStore();
  1139. watch(
  1140. () => store.state.theme,
  1141. (newVal, oldVal) => {
  1142. theme.value = newVal;
  1143. echartsTheme.value = !newVal ? "dark" : "";
  1144. funGetProcessTree();
  1145. },
  1146. {
  1147. deep: true,
  1148. }
  1149. );
  1150. const initPageData = () => {
  1151. //flag控制是否获取tree的第一项 true为可获取
  1152. actTreeNode.value = null;
  1153. excelList.value = [];
  1154. processTreeData.value = funRepeatMap(
  1155. JSON.parse(JSON.stringify(jsonData.treeData))
  1156. ); //flag控制对actTreeNode赋值
  1157. if (actTreeNode.value) {
  1158. if (actTreeNode.value.childs) {
  1159. excelList.value = actTreeNode.value.childs.map((o) => {
  1160. return {
  1161. id: o.id,
  1162. code: o.code,
  1163. interval: o.interval,
  1164. path: o.path,
  1165. prepareid: o.prepareid,
  1166. station: o.station,
  1167. time: o.time,
  1168. type: o.type,
  1169. windturbine: o.windturbine,
  1170. isCheck: false,
  1171. name: o.path.substring(
  1172. o.path.indexOf(o.station + "_") + (o.station + "_").length
  1173. ),
  1174. };
  1175. });
  1176. } else {
  1177. excelList.value = [];
  1178. }
  1179. const child = actTreeNode.value.childs[0];
  1180. const obj = {
  1181. id: child.id,
  1182. interval: child.interval,
  1183. path: child.path,
  1184. prepareid: child.prepareid,
  1185. station: child.station,
  1186. time: child.time,
  1187. type: child.type,
  1188. windturbine: child.windturbine,
  1189. name: child.path.substring(
  1190. child.path.indexOf(child.station + "_") + (child.station + "_").length
  1191. ),
  1192. };
  1193. currentNodeKey.value = actTreeNode.value?.id || "";
  1194. excelCheckIds.value = [obj.id]; //当为单选展示风机图表时
  1195. tableShowId.value = obj.id;
  1196. let tableX = [
  1197. "未满发样板机_",
  1198. "满发样板机_",
  1199. "样板机_",
  1200. "未满发_",
  1201. "满发_",
  1202. "_",
  1203. ];
  1204. for (let i = 0; i < tableX.length; i++) {
  1205. let it = tableX[i];
  1206. if (obj.name.indexOf(it) !== -1) {
  1207. tableName.value = obj.name.substring(0, obj.name.indexOf(it));
  1208. break;
  1209. }
  1210. }
  1211. tableFilePath.value = obj.path;
  1212. chartExcelList.value = excelList.value.map((o) => {
  1213. return {
  1214. ...o,
  1215. name: o.windturbine,
  1216. };
  1217. }); // 选中excel当前项时, excel列表赋值给dialog 下拉框
  1218. queryForm.checkIds = excelList.value.map((o) => o.id);
  1219. checkAll.value = true;
  1220. for (const chart of jsonData.powerData) {
  1221. powerproduction.value = `(额定功率=${chart.power.powerProduction}kW)`;
  1222. powerproductionNum.value = chart.power.powerProduction;
  1223. barxAxis.data = Object.keys(chart.res1);
  1224. barSeries[0].data = Object.values(chart.res1);
  1225. barSeries[0].markLine.data = [
  1226. {
  1227. yAxis: 0,
  1228. },
  1229. ];
  1230. chartId++;
  1231. lineSeries.value = [
  1232. {
  1233. type: "effectScatter",
  1234. showEffectOn: "emphasis",
  1235. rippleEffect: {
  1236. scale: 1,
  1237. },
  1238. legendHoverLink: false,
  1239. name: "",
  1240. symbolSize: 5,
  1241. data: chart.res2,
  1242. yAxisIndex: 0,
  1243. markLine: {
  1244. symbol: "none",
  1245. label: {
  1246. show: false,
  1247. },
  1248. lineStyle: {
  1249. color: "#F72C5B",
  1250. },
  1251. data: [
  1252. {
  1253. yAxis: powerproductionNum.value,
  1254. },
  1255. ],
  1256. },
  1257. },
  1258. ];
  1259. chartId++;
  1260. }
  1261. tableColumn.value = jsonData.tableData.title.map((o) => {
  1262. return {
  1263. prop: o.key,
  1264. label: o.des,
  1265. width: o.des === "时间" ? 100 : 80,
  1266. };
  1267. });
  1268. tableData.value = jsonData.tableData.data;
  1269. /**---------------------------- */
  1270. // activeTab.value = '1'
  1271. isChartArea.value = false;
  1272. const chartRes = jsonData.analysisData;
  1273. maxMinData.value = [chartRes.maxhjwd, chartRes.minhjwd];
  1274. markDot.pcl5 = chartRes.obj.pc5ratio;
  1275. markDot.pcl10 = chartRes.obj.pc10ratio;
  1276. markDot.pcl12 = chartRes.obj.pc12ratio;
  1277. markDot.pcl25 = chartRes.obj.pc25ratio;
  1278. avgObj.title = chartRes.obj.path
  1279. .substring(
  1280. chartRes.obj.path.indexOf(chartRes.obj.station + "_") +
  1281. (chartRes.obj.station + "_").length
  1282. )
  1283. .split("_")[0];
  1284. avgObj.cpavg = Number(chartRes.obj.cpavg).toFixed(2);
  1285. avgObj.frequency = Number(chartRes.obj.frequency).toFixed(2);
  1286. avgObj.pcratio = Number(chartRes.obj.pcratio).toFixed(2);
  1287. const color = [
  1288. "#1C99FF",
  1289. "#FF8700",
  1290. "#3D54BE",
  1291. "#fa8c16",
  1292. "#1DA0D7",
  1293. "#DD5044",
  1294. ];
  1295. seriesData.value = [
  1296. {
  1297. name: "拟合功率",
  1298. type: "line",
  1299. symbol: "line", //设定为实心点
  1300. symbolSize: 0, //设定实心点的大小
  1301. smooth: true, //这个是把线变成曲线
  1302. data: chartRes.sjgl,
  1303. xAxisIndex: 0,
  1304. },
  1305. {
  1306. name: "保证功率",
  1307. type: "line",
  1308. symbol: "line", //设定为实心点
  1309. symbolSize: 0, //设定实心点的大小
  1310. smooth: true, //这个是把线变成曲线
  1311. data: chartRes.llgl,
  1312. xAxisIndex: 0,
  1313. },
  1314. {
  1315. type: "effectScatter",
  1316. showEffectOn: "emphasis",
  1317. rippleEffect: {
  1318. scale: 1,
  1319. },
  1320. name: "数据散点",
  1321. symbolSize: 5,
  1322. // symbolSize: (data) => {
  1323. // return data.s ? data.s > 10 ? 10 : data.s : 4
  1324. // },
  1325. // datasetIndex: 1,
  1326. // encode: {
  1327. // x: 'x',
  1328. // y: 'y'
  1329. // },
  1330. data: chartRes.scatter,
  1331. xAxisIndex: 0,
  1332. yAxisIndex: 0,
  1333. },
  1334. ];
  1335. }
  1336. };
  1337. /**mounted */
  1338. onMounted(() => {
  1339. initPageData();
  1340. funGetProcessTree();
  1341. theme.value = store.state.theme;
  1342. echartsTheme.value = !theme.value ? "dark" : "";
  1343. tableHeight.value = window.innerHeight - 171 + "px";
  1344. excelHeight.value = window.innerHeight - 111 + "px";
  1345. treeHeight.value = window.innerHeight - 111 + "px";
  1346. window.addEventListener("resize", () => {
  1347. tableHeight.value = window.innerHeight - 171 + "px";
  1348. excelHeight.value = window.innerHeight - 111 + "px";
  1349. treeHeight.value = window.innerHeight - 111 + "px";
  1350. });
  1351. /**test */
  1352. // funExcelChange({
  1353. // id: 1,
  1354. // name: 'excel',
  1355. // type: 'fitting',
  1356. // })
  1357. });
  1358. /**activated */
  1359. onActivated(() => {
  1360. // funGetProcessTree()
  1361. });
  1362. </script>
  1363. <style lang="less" scoped>
  1364. .dataAnalysisHotAns {
  1365. height: 100%;
  1366. .dataAnalysisHotAnsMain {
  1367. height: 100%;
  1368. .main_top {
  1369. height: 40px;
  1370. display: flex;
  1371. align-items: center;
  1372. .topPsty {
  1373. position: relative;
  1374. top: 5px;
  1375. padding: 7px 20px;
  1376. font-size: 12px;
  1377. font-weight: 600;
  1378. margin-left: 10px;
  1379. border-radius: 3px;
  1380. }
  1381. }
  1382. .main {
  1383. display: flex;
  1384. width: 100%;
  1385. .treeDataMain,
  1386. .excelDataMain,
  1387. .tableDataMain {
  1388. border-radius: 10px;
  1389. }
  1390. .treeDataMain {
  1391. margin-right: 10px;
  1392. padding: 10px 0 10px 10px;
  1393. width: calc(19% - 20px);
  1394. }
  1395. .excelDataMain {
  1396. margin-right: 10px;
  1397. padding: 10px 0 10px 10px;
  1398. width: calc(15% - 20px);
  1399. }
  1400. .tableDataMain {
  1401. padding: 10px;
  1402. width: calc(66% - 20px);
  1403. position: relative;
  1404. .chartIcon {
  1405. cursor: pointer;
  1406. }
  1407. .butten_com {
  1408. position: absolute;
  1409. right: 20px;
  1410. z-index: 111111;
  1411. }
  1412. }
  1413. }
  1414. }
  1415. }
  1416. .themeDark {
  1417. .dataAnalysisHotAnsMain {
  1418. .main_top {
  1419. .topPsty {
  1420. color: #1c99ff;
  1421. background: #1e2126;
  1422. }
  1423. }
  1424. .main {
  1425. background: #13171e;
  1426. .treeDataMain {
  1427. background: transparent;
  1428. }
  1429. .excelDataMain {
  1430. background: #313233;
  1431. }
  1432. .tableDataMain {
  1433. margin-top: 5px;
  1434. background: #212223;
  1435. }
  1436. }
  1437. }
  1438. }
  1439. .themeLight {
  1440. padding: 0;
  1441. .dataAnalysisHotAnsMain {
  1442. .main_top {
  1443. .topPsty {
  1444. color: #2778ff;
  1445. background: #ffffff;
  1446. }
  1447. }
  1448. .main {
  1449. background: #e6e8f2;
  1450. .treeDataMain {
  1451. background: transparent;
  1452. }
  1453. .excelDataMain {
  1454. background: #f4f6fb;
  1455. }
  1456. .tableDataMain {
  1457. background: #fff;
  1458. margin-top: 5px;
  1459. }
  1460. }
  1461. }
  1462. }
  1463. </style>