index.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. <template>
  2. <div>
  3. <BasicTable class="basic-table-cl" :clickToRowSelect="false" @row-click="rowCLick" @register="registerTable">
  4. <template #form-formHeader="{ model, field }">
  5. <div class="form-box">
  6. <a-row>
  7. <a-col :span="12">
  8. <span class="span-label"> 关键字: </span>
  9. <a-input class="custom-input" v-model:value="formState.value" placeholder="支持流域搜索" />
  10. </a-col>
  11. <a-col :span="12">
  12. <span class="span-label"> 监测站点: </span>
  13. <a-select class="custom-input sitemore" mode="multiple" placeholder="监测站点(可多选)" :maxTagCount="2"
  14. :maxTagTextLength="4" v-model:value="formState.senid" label-in-value :options="optionArr" />
  15. </a-col>
  16. </a-row>
  17. </div>
  18. </template>
  19. <template #toolbar>
  20. <Authority>
  21. <a-button type="primary" @click="exportDataFn('水情查询.xlsx')">导出</a-button>
  22. </Authority>
  23. </template>
  24. </BasicTable>
  25. <BasicModal :clickToRowSelect="false" :footer="null" @cancel="cancel" :visible="showModal" :width="1200"
  26. :minHeight="600" :title="basicModalTitle">
  27. <div class="box-basic">
  28. <div class="top-search">
  29. 时间范围:
  30. <a-range-picker :value="timeData.time" :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss"
  31. :placeholder="['开始时间', '结束时间']" @change="onChange" :allowClear="true" />
  32. <a-button @click="getHistoryRain" class="marg-left" type="primary">查询</a-button>
  33. </div>
  34. <div class="moddal-box" id="myElement">
  35. <div class="left-box">
  36. <div id="charts-box" style="width: 100%; height: 100%"> </div>
  37. </div>
  38. <div class="right-box">
  39. <div>
  40. <ul>
  41. <li>
  42. <div>时间</div>
  43. <div>水位(m)</div>
  44. <div>流量(m³/s)</div>
  45. </li>
  46. <li v-for="(item, index) in modalData.optimizeData" :key="index">
  47. <div>{{ item.time }}</div>
  48. <div>{{ item.z }}</div>
  49. <div>{{ item.q }}</div>
  50. </li>
  51. </ul>
  52. </div>
  53. </div>
  54. </div>
  55. </div>
  56. </BasicModal>
  57. </div>
  58. </template>
  59. <script lang="ts" setup>
  60. import { defineComponent, ref, watch, onMounted, reactive } from 'vue';
  61. import { BasicTable, useTable } from '/@/components/Table';
  62. import elementResizeDetectorMaker from 'element-resize-detector';
  63. let erd = elementResizeDetectorMaker(); //创建实例
  64. import { BasicModal } from '/@/components/Modal/index';
  65. import { exportData } from '/@/utils/fnUtils.ts';
  66. import * as echarts from 'echarts';
  67. import { ImpExcel, ExcelData, jsonToSheetXlsx } from '/@/components/Excel';
  68. import {
  69. realWsaters,
  70. // waterRegimen,
  71. // getMonitorInfo,
  72. // getRiverTree,
  73. // historyRain,
  74. postRealWaterZq
  75. } from '/@/api/swHome/index';
  76. import { getNowTime } from '/@/utils/fnUtils.ts';
  77. let columns = [];
  78. let searchFormSchema = [];
  79. let chart;
  80. const [registerTable, { reload, setColumns, setTableData }] = useTable({
  81. // 表格头部
  82. title: '水情查询',
  83. inset: true,
  84. // api: realWsaters,
  85. columns,
  86. showIndexColumn: true,
  87. clickToRowSelect: false,
  88. beforeFetch: (T) => {
  89. console.log(T);
  90. },
  91. // 搜索表格
  92. formConfig: {
  93. labelWidth: 120,
  94. schemas: searchFormSchema,
  95. // 自定义提交逻辑
  96. submitFunc: submitFunc,
  97. // 自定义重置逻辑
  98. resetFunc: resetFunc,
  99. },
  100. // 是否需要搜索框
  101. useSearchForm: true,
  102. // 是否需要表格设置框
  103. showTableSetting: true,
  104. tableSetting: {
  105. redo: false,
  106. setting: false,
  107. },
  108. // rowSelection: { type: 'checkbox' },
  109. // 是否需要边框
  110. bordered: true,
  111. rowKey: 'id',
  112. ellipsis: false,
  113. fetchSetting: {
  114. listField: 'data.table_value',
  115. },
  116. pagination: false
  117. });
  118. // 表单数据
  119. let formState = reactive({
  120. value: '',
  121. senid: [],
  122. });
  123. // 所有的数据
  124. let allAll = [];
  125. // 弹窗控制
  126. let basicModalTitle = ref('');
  127. let showModal = ref(false);
  128. let timeData = reactive({
  129. time: [],
  130. });
  131. // 导出
  132. const exportDataFn = (name) => {
  133. let exportColumns = JSON.parse(JSON.stringify(dataCenter.exportColumns))
  134. let exportdataSource = JSON.parse(JSON.stringify(dataCenter.exportdataSource))
  135. exportdataSource.forEach(element => {
  136. delete element.q
  137. delete element.z
  138. });
  139. exportData(exportColumns, exportdataSource, name)
  140. }
  141. function onChange(value, dateString) {
  142. timeData.time = dateString;
  143. }
  144. function cancel(e) {
  145. showModal.value = false;
  146. }
  147. // rowCLick
  148. let activeItem = {};
  149. function rowCLick(item) {
  150. timeData.time = [getNowTime(2), getNowTime(1)];
  151. activeItem = item;
  152. basicModalTitle.value = `水位流量过程线(${item.st_name})`;
  153. showModal.value = true;
  154. getHistoryRain();
  155. setTimeout(() => {
  156. erd.listenTo(document.getElementById('myElement'), () => {
  157. if (chart) {
  158. chart.resize();
  159. }
  160. });
  161. }, 300);
  162. }
  163. // 查询雨情历史数据
  164. let historyFormData = reactive({
  165. stcd: '',
  166. start_time: '',
  167. end_time: '',
  168. });
  169. let modalData = reactive({
  170. data: {},
  171. optimizeData: {},
  172. });
  173. //q:流量,z:水位
  174. async function getHistoryRain() {
  175. echartsData.time = []
  176. echartsData.q = []
  177. echartsData.z = []
  178. historyFormData.stcd = activeItem.stcd;
  179. historyFormData.start_time = timeData.time[0] ? timeData.time[0] : '';
  180. historyFormData.end_time = timeData.time[1] ? timeData.time[1] : '';
  181. //查询水位,流量过程线
  182. let qwData = await postRealWaterZq(historyFormData).then(res => {
  183. console.log(res)
  184. modalData.optimizeData = res.data
  185. res.data.forEach(element => {
  186. echartsData.time.push(element.time)
  187. echartsData.q.push(element.q)
  188. echartsData.z.push(element.z)
  189. });
  190. })
  191. // 查询流量过程线
  192. // let qData = await getMonitorInfo(historyFormData).then((res) => {
  193. // return res.data;
  194. // });
  195. // // 查询水位过程线
  196. // historyFormData.senid = activeItem.z.senid;
  197. // let zData = await getMonitorInfo(historyFormData).then((res) => {
  198. // return res.data;
  199. // });
  200. // modalDataFn(qData, zData);
  201. echarts1();
  202. }
  203. let echartsData = reactive({
  204. time: [],
  205. q: [],
  206. z: [],
  207. });
  208. // 弹窗数据处理
  209. function modalDataFn(qData, zData) {
  210. modalData.optimizeData = [];
  211. echartsData.time = [];
  212. echartsData.q = [];
  213. echartsData.z = [];
  214. for (let index = 0; index < qData.length; index++) {
  215. let itemData = {};
  216. const elementq = qData[index];
  217. const elementz = zData[index];
  218. itemData.time = elementq.time;
  219. itemData.q = elementq.factv;
  220. itemData.z = elementz.factv;
  221. echartsData.time.push(elementq.time);
  222. echartsData.q.push(elementq.factv);
  223. echartsData.z.push(elementz.factv);
  224. modalData.optimizeData.push(itemData);
  225. }
  226. }
  227. // 计算最大值
  228. function getMaxValue(arr) {
  229. const max = Math.max(...arr);
  230. // 这样处理是为了不让最大值刚好到坐标轴最顶部
  231. return Math.ceil(max / 9.5) * 10;
  232. }
  233. // 计算最小值
  234. function getMinValue(arr) {
  235. const min = Math.min(...arr);
  236. // 这样处理是为了不让最大值刚好到坐标轴最底部
  237. return Math.floor(min / 12) * 10;
  238. }
  239. // 图表
  240. function echarts1() {
  241. // const min1 = getMinValue(echartsData.q);
  242. // const min2 = getMinValue(echartsData.z);
  243. // const max1 = getMaxValue(echartsData.q);
  244. // const max2 = getMaxValue(echartsData.z);
  245. chart = echarts.init(document.getElementById('charts-box'));
  246. console.log(basicModalTitle)
  247. var option = {
  248. toolbox: {
  249. feature: {
  250. saveAsImage: {
  251. name: basicModalTitle.value
  252. }
  253. }
  254. },
  255. tooltip: {
  256. trigger: 'axis',
  257. axisPointer: {
  258. type: 'shadow',
  259. },
  260. formatter(params) {
  261. var relVal = params[0].name;
  262. for (var i = 0, l = params.length; i < l; i++) {
  263. console.log('tooltip数据值', params[i].value)
  264. //遍历出来的值一般是字符串,需要转换成数字,再进项tiFixed四舍五入
  265. relVal += '<br/>' + params[i].marker + params[i].seriesName + ' : ' + Number(params[i].value)
  266. }
  267. return relVal;
  268. },
  269. // formatter: '{a} <br/>{b}: {c} ({d}%)'
  270. },
  271. dataZoom: [
  272. {
  273. // 这个dataZoom组件,默认控制x轴。
  274. type: 'inside', // 这个 dataZoom 组件是 slider 型 dataZoom 组件
  275. },
  276. {
  277. // 这个dataZoom组件,也控制x轴。
  278. type: 'inside', // 这个 dataZoom 组件是 inside 型 dataZoom 组件
  279. },
  280. ],
  281. grid: {
  282. left: '4%', //默认10%
  283. right: '4%', //默认10%
  284. bottom: '4%', //默认60
  285. containLabel: true,
  286. //grid区域是否包含坐标轴的刻度标签
  287. },
  288. legend: {
  289. top: 20,
  290. data: ['流量', '水位'],
  291. textStyle: {
  292. fontSize: 14, //字体大小
  293. color: '#333', //字体颜色
  294. },
  295. // itemStyle: {
  296. // color: '#fff',
  297. // },
  298. },
  299. xAxis: {
  300. type: 'category',
  301. data: echartsData.time,
  302. axisLabel: {
  303. //x轴文字的配置
  304. show: true,
  305. textStyle: {
  306. color: '#333',
  307. },
  308. formatter: function (val) {
  309. var strs = val.split(''); //字符串数组
  310. var str = '';
  311. for (var i = 0, s; (s = strs[i++]);) {
  312. //遍历字符串数组
  313. if (i > 5 && i < 17) {
  314. str += s;
  315. }
  316. if (!(i % 10)) str += '\n'; //按需要求余
  317. }
  318. return str;
  319. },
  320. },
  321. },
  322. yAxis: [
  323. {
  324. name: '流量:m³/s',
  325. type: 'value',
  326. // min: min1,
  327. // max: max1,
  328. // interval: (max1 - min1) / 2,
  329. // splitNumber: 2,
  330. axisLabel: {
  331. //y轴文字的配置
  332. textStyle: {
  333. color: '#333',
  334. margin: 15,
  335. },
  336. formatter: function (value) {
  337. return value + '';
  338. },
  339. // formatter: '{value} %'//y轴的每一个刻度值后面加上‘%’号
  340. },
  341. splitLine: {
  342. //网格线
  343. lineStyle: {
  344. type: 'dashed', //设置网格线类型 dotted:虚线 solid:实线
  345. width: 1, //y轴线的宽度
  346. color: '#ccc',
  347. },
  348. show: true, //隐藏或显示
  349. },
  350. nameTextStyle: {
  351. color: 'rgba(0, 0, 0, 0.8)', //颜色
  352. },
  353. scale: true,
  354. },
  355. {
  356. type: 'value',
  357. name: '水位:m',
  358. // min: min2,
  359. // interval: (max2 - min2) / 2,
  360. // max: max2,
  361. // splitNumber: 2,
  362. axisLabel: {
  363. //y轴文字的配置
  364. textStyle: {
  365. color: '#333',
  366. margin: 15,
  367. },
  368. formatter: function (value) {
  369. return value + '';
  370. },
  371. // formatter: '{value} %'//y轴的每一个刻度值后面加上‘%’号
  372. },
  373. splitLine: {
  374. //网格线
  375. lineStyle: {
  376. type: 'dashed', //设置网格线类型 dotted:虚线 solid:实线
  377. width: 1, //y轴线的宽度
  378. color: '#ccc',
  379. },
  380. show: true, //隐藏或显示
  381. },
  382. nameTextStyle: {
  383. color: 'rgba(0, 0, 0, 0.8)', //颜色
  384. padding: [0, 0, 0, 30],
  385. },
  386. scale: true,
  387. },
  388. ],
  389. series: [
  390. {
  391. name: '流量',
  392. // data: [820, 932, 901, 934, 1290, 1330, 1320],
  393. data: echartsData.q,
  394. type: 'line',
  395. smooth: true,
  396. },
  397. {
  398. name: '水位',
  399. yAxisIndex: 1,
  400. // data: [82, 92, 901, 934, 1290, 130, 11320],
  401. data: echartsData.z,
  402. type: 'line',
  403. smooth: true,
  404. },
  405. ],
  406. };
  407. option && chart.setOption(option);
  408. }
  409. // 所有雨量站数据
  410. let optionArr = ref([]);
  411. // 重置逻辑
  412. function resetFunc() {
  413. formState.value = '';
  414. formState.senid = [];
  415. }
  416. // 提交事件
  417. function submitFunc() {
  418. screenData();
  419. }
  420. // 筛选数据
  421. function screenData() {
  422. console.log(formState);
  423. console.log(allAll);
  424. let arr = [];
  425. // 都有数据进行两次筛选
  426. if (formState.value != '' && formState.senid.length > 0) {
  427. allAll.forEach((element) => {
  428. formState.senid.forEach((elements) => {
  429. if (
  430. elements.label == element.st_name &&
  431. element.basin_name.indexOf(formState.value) != -1
  432. ) {
  433. arr.push(element);
  434. }
  435. });
  436. });
  437. } else if (formState.value != '') {
  438. allAll.forEach((element) => {
  439. if (element.basin_name.indexOf(formState.value) != -1) {
  440. console.log(element);
  441. arr.push(element);
  442. }
  443. });
  444. } else if (formState.senid.length > 0) {
  445. allAll.forEach((element) => {
  446. formState.senid.forEach((elements) => {
  447. if (elements.label == element.st_name) {
  448. arr.push(element);
  449. }
  450. });
  451. });
  452. } else {
  453. arr = allAll;
  454. }
  455. setTableData(setTableUpDown(arr));
  456. }
  457. //处理数据上升或者下降
  458. function setTableUpDown(arr) {
  459. arr.forEach((element) => {
  460. // if (element.up_down == 0) {
  461. // element.up_down = '落↓';
  462. // }
  463. // if (element.up_down == 1) {
  464. // element.up_down = '涨↑';
  465. // }
  466. // if (element.up_down == 2) {
  467. // element.up_down = '平-';
  468. // }
  469. element.qData = element.q.v;
  470. element.zData = element.z.v;
  471. });
  472. return arr;
  473. }
  474. // 处理表头
  475. function processingData(table_head) {
  476. table_head.forEach((element) => {
  477. for (let key in element) {
  478. if (key == 'q' || key == 'z') {
  479. let item = element[key];
  480. element.title = item;
  481. element.key = key + 'Data';
  482. element.dataIndex = key + 'Data';
  483. } else {
  484. let item = element[key];
  485. element.title = item;
  486. element.key = key;
  487. element.dataIndex = key;
  488. }
  489. element.ellipsis = true;
  490. if (element.title == '时间') {
  491. // element.width = 200;
  492. }
  493. if (element.title == '站码') {
  494. // element.width = 160;
  495. }
  496. }
  497. });
  498. return table_head;
  499. }
  500. let dataCenter = reactive({
  501. exportdataSource: [],
  502. exportColumns: []
  503. })
  504. // 获取请求头
  505. async function getRealRainData() {
  506. await realWsaters().then((res) => {
  507. let { table_head, table_value } = res.data;
  508. dataCenter.exportdataSource = allAll = table_value;
  509. dataCenter.exportColumns = columns = processingData(table_head);
  510. setColumns(columns);
  511. setTableData(setTableUpDown(table_value));
  512. optionArr.value = measuringStation(table_value);
  513. });
  514. }
  515. // 筛选出所有测站
  516. function measuringStation(table_value) {
  517. let measuringStationArr = [];
  518. table_value.forEach((element) => {
  519. measuringStationArr.push({ label: element.st_name, key: element.stcd, value: element.stcd });
  520. });
  521. return measuringStationArr;
  522. }
  523. onMounted(async () => {
  524. await getRealRainData();
  525. });
  526. </script>
  527. <style scoped lang="less">
  528. .form-box {
  529. position: absolute;
  530. z-index: 9;
  531. width: 66.6666%;
  532. .custom-input {
  533. width: calc(100% - 100px);
  534. }
  535. }
  536. .span-label {
  537. width: 90px;
  538. padding-right: 10px;
  539. display: inline-block;
  540. text-align: right;
  541. line-height: 32px;
  542. }
  543. .marg-left {
  544. margin-left: 10px;
  545. }
  546. .ant-table-striped-modal {
  547. margin-top: 20px;
  548. }
  549. .box-basic {
  550. height: calc(100% - 46px);
  551. width: calc(100% - 28px);
  552. position: absolute;
  553. // min-height: 600px;
  554. }
  555. .moddal-box {
  556. display: flex;
  557. height: calc(100% - 32px);
  558. .left-box {
  559. flex: 1;
  560. overflow: hidden;
  561. height: 100%;
  562. }
  563. .right-box {
  564. width: 400px;
  565. height: 100%;
  566. overflow: auto;
  567. margin-left: 20px;
  568. position: relative;
  569. ul {
  570. // position: relative;
  571. li {
  572. display: flex;
  573. line-height: 36px;
  574. &>div {
  575. // flex: 1;
  576. text-align: center;
  577. }
  578. &>div:nth-child(1) {
  579. min-width: 180px;
  580. }
  581. &>div:nth-child(2) {
  582. flex: 1;
  583. }
  584. &>div:nth-child(3) {
  585. flex: 1;
  586. }
  587. }
  588. li:nth-child(1) {
  589. position: absolute;
  590. width: 100%;
  591. }
  592. li:nth-child(2) {
  593. padding-top: 36px;
  594. }
  595. }
  596. }
  597. }
  598. .vben-basic-table-form-container {
  599. padding: 0px;
  600. }
  601. </style>