index.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  1. <template>
  2. <div>
  3. <BasicTable :clickToRowSelect="false" @register="registerTable">
  4. <template #toolbar>
  5. <Authority>
  6. <a-button type="primary" @click="exportData(dataCenter.columns,dataCenter.exportdataSource,'标准气象站.xlsx')">导出</a-button>
  7. </Authority>
  8. </template>
  9. </BasicTable>
  10. <!-- 弹窗1 -->
  11. <BasicModal
  12. :maskClosable="false"
  13. :footer="null"
  14. @cancel="cancel"
  15. :visible="dataCenter.showModal"
  16. :width="1200"
  17. :minHeight="600"
  18. :title="dataCenter.basicModalTitle"
  19. >
  20. <div class="box-basic">
  21. <div class="top-search">
  22. 时间范围:
  23. <a-range-picker
  24. :value="dataCenter.timeData.time"
  25. :show-time="{ format: 'HH:mm:ss' }"
  26. format="YYYY-MM-DD HH:mm:ss"
  27. :placeholder="['开始时间', '结束时间']"
  28. @change="onChange"
  29. :allowClear="true"
  30. />
  31. <a-button @click="getHistoryRain" class="marg-left" type="primary">查询</a-button>
  32. </div>
  33. <div class="moddal-box" id="myElement"> </div>
  34. </div>
  35. </BasicModal>
  36. <!-- 弹窗2 -->
  37. <BasicModal
  38. :maskClosable="false"
  39. :footer="null"
  40. @cancel="cancel1"
  41. :visible="dataCenter.showModal1"
  42. :width="1200"
  43. :minHeight="600"
  44. title="降雨量(多站)"
  45. >
  46. <div class="box-basic">
  47. <div class="top-search"> 时间范围:{{ dataCenter.modalTime }} </div>
  48. <div class="moddal-box" id="myElement2"> </div>
  49. </div>
  50. </BasicModal>
  51. </div>
  52. </template>
  53. <script lang="tsx" setup>
  54. import { defineComponent, ref, watch, onMounted, reactive } from 'vue';
  55. import { BasicTable, useTable, TableAction } from '/@/components/Table';
  56. import { ImpExcel, ExcelData, jsonToSheetXlsx } from '/@/components/Excel';
  57. import elementResizeDetectorMaker from 'element-resize-detector';
  58. let erd = elementResizeDetectorMaker(); //创建实例
  59. import moment from 'moment';
  60. import { BasicModal } from '/@/components/Modal/index';
  61. import {
  62. getHistoryRainList,
  63. getDataHistRainStatios,
  64. getMonitorInfo,
  65. getHistoryTimeInquire,
  66. } from '/@/api/swHome/index';
  67. import { getNowTime } from '/@/utils/fnUtils.ts';
  68. import * as echarts from 'echarts';
  69. let dataCenter = reactive({
  70. oneTitle:'',
  71. showSchemasType: 'H',
  72. nameArr: [],
  73. modalTime: '',
  74. Modal1Sendid: '',
  75. showModal: false,
  76. showModal1: false,
  77. basicModalTitle: '降雨量',
  78. cahrtsList: [],
  79. timeData: {
  80. time: [],
  81. },
  82. columns: [],
  83. cahrtsData: [],
  84. searchFormSchema: [
  85. {
  86. field: 'senid',
  87. label: '监测站点:',
  88. component: 'Select',
  89. colProps: { span: 6 },
  90. componentProps: {
  91. options: [],
  92. mode: 'multiple',
  93. maxTagCount:1
  94. },
  95. },
  96. {
  97. field: 'step_size',
  98. label: '时段类型:',
  99. component: 'RadioGroup',
  100. colProps: { span: 6 },
  101. defaultValue: 'H',
  102. componentProps: {
  103. options: [
  104. { label: '实时', value: 'R' },
  105. { label: '小时', value: 'H' },
  106. { label: '日', value: 'D' },
  107. { label: '月', value: 'M' },
  108. { label: '年', value: 'Y' },
  109. ],
  110. // onChange: handleCustomerChange,
  111. },
  112. },
  113. {
  114. field: 'queryTime',
  115. label: '查询时间:',
  116. colProps: { span: 6 },
  117. component: 'RangePicker',
  118. componentProps: {
  119. showTime: {
  120. format: 'YYYY-MM-DD HH:mm:ss',
  121. },
  122. },
  123. ifShow: () => {
  124. return dataCenter.showSchemasType == 'H';
  125. },
  126. },
  127. {
  128. field: 'dayQueryTime',
  129. label: '查询时间:',
  130. colProps: { span: 6 },
  131. component: 'RangePicker',
  132. componentProps: {
  133. format: 'YYYY-MM-DD',
  134. valueFormat: 'YYYY-MM-DD',
  135. },
  136. ifShow: () => {
  137. return dataCenter.showSchemasType == 'D';
  138. },
  139. },
  140. {
  141. field: 'monthQueryTime',
  142. label: '查询时间:',
  143. colProps: { span: 6 },
  144. component: 'RangePicker',
  145. componentProps: {
  146. format: 'YYYY-MM',
  147. valueFormat: 'YYYY-MM',
  148. mode: ['month', 'month'],
  149. onPanelChange: monthPanelChange,
  150. // open: monthPickShow.value,
  151. },
  152. ifShow: () => {
  153. return dataCenter.showSchemasType == 'M';
  154. },
  155. },
  156. {
  157. field: 'yearQueryTime',
  158. label: '查询时间:',
  159. colProps: { span: 6 },
  160. component: 'RangePicker',
  161. componentProps: {
  162. format: 'YYYY',
  163. valueFormat: 'YYYY',
  164. mode: ['year', 'year'],
  165. onPanelChange: yearPanelChange,
  166. },
  167. ifShow: () => {
  168. return dataCenter.showSchemasType == 'Y';
  169. },
  170. },
  171. ],
  172. });
  173. const [registerTable, { reload, getRawDataSource, getForm, setLoading, setColumns, setTableData }] =
  174. useTable({
  175. title: '雨情历史查询',
  176. api: getHistoryRainList,
  177. columns: dataCenter.columns,
  178. showIndexColumn: false,
  179. clickToRowSelect: false,
  180. pagination: false,
  181. loading: false,
  182. immediate: false,
  183. dataSource: [],
  184. formConfig: {
  185. labelWidth: 120,
  186. schemas: dataCenter.searchFormSchema,
  187. fieldMapToTime: [['queryTime', ['start_time', 'end_time'], 'YYYY-MM-DD HH:mm:ss']],
  188. actionColOptions: {
  189. span: 5,
  190. },
  191. },
  192. beforeFetch: (params: any) => {
  193. let senid;
  194. if (params.senid) {
  195. senid = params.senid;
  196. } else {
  197. senid = [];
  198. }
  199. let start_time = params.start_time;
  200. let end_time = params.end_time;
  201. //判断查询模式
  202. if (dataCenter.showSchemasType == 'D') {
  203. start_time = params.dayQueryTime[0];
  204. end_time = params.dayQueryTime[1];
  205. }
  206. if (dataCenter.showSchemasType == 'M') {
  207. start_time = moment(params.monthQueryTime[0]).format('YYYY-MM');
  208. end_time = moment(params.monthQueryTime[1]).format('YYYY-MM');
  209. }
  210. if (dataCenter.showSchemasType == 'Y') {
  211. start_time = moment(params.yearQueryTime[0]).format('YYYY');
  212. end_time = moment(params.yearQueryTime[1]).format('YYYY');
  213. }
  214. return {
  215. senid: senid,
  216. step_size: params.step_size,
  217. start_time: start_time,
  218. end_time: end_time,
  219. };
  220. },
  221. afterFetch: (data) => {
  222. setTitle(data);
  223. },
  224. useSearchForm: true,
  225. showTableSetting: true,
  226. bordered: true,
  227. rowKey: 'id',
  228. fetchSetting: {
  229. listField: 'data.value',
  230. },
  231. });
  232. // 月份选择
  233. function monthPanelChange(value) {
  234. getForm().setFieldsValue({
  235. monthQueryTime: [moment(value[0]).format('YYYY-MM'), moment(value[1]).format('YYYY-MM')],
  236. });
  237. }
  238. // 年份选择
  239. function yearPanelChange(value) {
  240. getForm().setFieldsValue({
  241. yearQueryTime: [moment(value[0]).format('YYYY'), moment(value[1]).format('YYYY')],
  242. });
  243. }
  244. function handleCustomerChange(e) {
  245. dataCenter.timeData.time = [];
  246. dataCenter.showSchemasType = e.target.value;
  247. }
  248. // 弹窗处理
  249. function cancel(e) {
  250. dataCenter.showModal = false;
  251. }
  252. function cancel1() {
  253. dataCenter.showModal1 = false;
  254. }
  255. // 弹窗点击查询
  256. async function getHistoryRain() {
  257. singleStation();
  258. }
  259. function onChange(value, dateString) {
  260. dataCenter.timeData.time = dateString;
  261. }
  262. // 获取查询树状数据
  263. function getRiveTreeData() {
  264. getDataHistRainStatios().then((res) => {
  265. res.data.forEach((element) => {
  266. element.label = element.sensor_name;
  267. element.value = element.senid;
  268. });
  269. dataCenter.searchFormSchema[0].componentProps.options = res.data;
  270. });
  271. }
  272. // 通过name匹配sinid
  273. function setOptionsNmae(name) {
  274. dataCenter.nameArr = [];
  275. let senid = '';
  276. dataCenter.searchFormSchema[0].componentProps.options.forEach((element) => {
  277. if (element.sensor_name == name) {
  278. senid = element.senid;
  279. }
  280. });
  281. return senid;
  282. }
  283. // 处理头部数据
  284. function setTitle(data) {
  285. let columns = [];
  286. columns.push({
  287. title: '时间',
  288. dataIndex: 'time',
  289. key: 'time',
  290. width: 200,
  291. customRender: ({ record, column, index, text }) => {
  292. // customRender的返回值要遵循vue-jsx语法,要加()和换行
  293. return <a onClick={handleTitle.bind(record, column, text)}>{text}</a>;
  294. },
  295. ellipsis: false,
  296. });
  297. let num = 0;
  298. let tabdata = [];
  299. data.forEach((dataItem, dataIndex) => {
  300. num++;
  301. let partition = {};
  302. const element = dataItem.detail;
  303. // console.log(element);
  304. partition.title = dataItem.name;
  305. partition.dataIndex = dataItem.name;
  306. // partition.width = 200;
  307. partition.key = 'partition' + num;
  308. partition.children = [];
  309. for (const elements in element['最大值']) {
  310. let content = element['最大值'][elements];
  311. partition.children.push({
  312. title: elements,
  313. dataIndex: elements,
  314. key: elements,
  315. width: elements.length*20,
  316. ellipsis: 'auto',
  317. customRender: ({ record, column, index, text }) => {
  318. // customRender的返回值要遵循vue-jsx语法,要加()和换行
  319. return <div onClick={handleTitle.bind(record, column, text)}>{text}</div>;
  320. },
  321. });
  322. }
  323. // console.log(partition);
  324. // 列表数据处理
  325. let index = 0;
  326. for (const elements in element) {
  327. let contentObj = {};
  328. let item = element[elements];
  329. contentObj.time = elements;
  330. for (const key1 in item) {
  331. let item1 = item[key1];
  332. if (tabdata.length != Object.keys(element).length) {
  333. contentObj[key1] = item1;
  334. } else {
  335. tabdata[index][key1] = item1;
  336. }
  337. }
  338. if (tabdata.length != Object.keys(element).length) {
  339. tabdata.push(contentObj);
  340. }
  341. index++;
  342. }
  343. columns.push(partition);
  344. });
  345. setTimeout(() => {
  346. dataCenter.exportColumns = columns
  347. dataCenter.exportdataSource = tabdata
  348. setTableData(tabdata);
  349. setColumns(columns);
  350. }, 100);
  351. }
  352. function handleTitle(record, text, column) {
  353. // console.log(text);
  354. // console.log(column);
  355. console.log(record.key);
  356. // 点击时间
  357. if (record.customTitle == '时间' && text != '最小值' && text != '最大值') {
  358. dataCenter.showModal1 = true;
  359. multistation(text);
  360. }
  361. if (record.customTitle != '时间') {
  362. dataCenter.timeData.time = [getNowTime(2), getNowTime(1)];
  363. dataCenter.oneTitle = `${record.key}`
  364. dataCenter.basicModalTitle = `降雨量(${record.key})`;
  365. dataCenter.showModal = true;
  366. dataCenter.Modal1Sendid = setOptionsNmae(record.key);
  367. singleStation();
  368. }
  369. setTimeout(() => {
  370. erd.listenTo(document.getElementById('myElement'), () => {
  371. if (chart) {
  372. chart.resize();
  373. }
  374. });
  375. erd.listenTo(document.getElementById('myElement2'), () => {
  376. if (chart2) {
  377. chart2.resize();
  378. }
  379. });
  380. }, 300);
  381. }
  382. // 查询多站
  383. function multistation(time) {
  384. let hostData = {
  385. time: time,
  386. senid: [],
  387. step_size:getForm().getFieldsValue().step_size
  388. };
  389. dataCenter.nameArr = getRawDataSource().data.head;
  390. dataCenter.nameArr.forEach((element) => {
  391. dataCenter.searchFormSchema[0].componentProps.options.forEach((elements) => {
  392. if (
  393. elements.sensor_name == element
  394. ) {
  395. console.log(elements.sensor_name);
  396. console.log(element);
  397. hostData.senid.push(elements.senid);
  398. }
  399. });
  400. });
  401. dataCenter.modalTime = time;
  402. getHistoryTimeInquire(hostData).then((res) => {
  403. let echarts2Data = {
  404. name: [],
  405. value: [],
  406. };
  407. res.data.forEach((element) => {
  408. echarts2Data.name.push(element.st_name);
  409. echarts2Data.value.push(element.value);
  410. });
  411. echarts2(echarts2Data);
  412. });
  413. }
  414. // 查询单一测站
  415. async function singleStation() {
  416. let historyFormData = {};
  417. historyFormData.senid = dataCenter.Modal1Sendid;
  418. historyFormData.start_time = dataCenter.timeData.time[0] ? dataCenter.timeData.time[0] : '';
  419. historyFormData.end_time = dataCenter.timeData.time[1] ? dataCenter.timeData.time[1] : '';
  420. let activeInfoData = await getMonitorInfo(historyFormData).then((res) => {
  421. return res.data;
  422. });
  423. dataCenter.cahrtsData = activeInfoData;
  424. setTimeout(() => {
  425. setCharts();
  426. }, 0);
  427. }
  428. // 处理charts数据
  429. function setCharts() {
  430. dataCenter.cahrtsList.time = [];
  431. dataCenter.cahrtsList.data = [];
  432. dataCenter.cahrtsData.forEach((element) => {
  433. dataCenter.cahrtsList.time.push(element.time);
  434. dataCenter.cahrtsList.data.push(element.factv);
  435. });
  436. echarts1();
  437. }
  438. // 图表
  439. let chart;
  440. let chart2;
  441. function echarts1() {
  442. chart = echarts.init(document.getElementById('myElement'));
  443. var option = {
  444. toolbox: {
  445. feature: {
  446. saveAsImage: {
  447. name:dataCenter.basicModalTitle
  448. }
  449. }
  450. },
  451. tooltip: {
  452. trigger: 'axis',
  453. axisPointer: {
  454. type: 'shadow',
  455. },
  456. formatter(params) {
  457. var relVal = params[0].name;
  458. for (var i = 0, l = params.length; i < l; i++) {
  459. console.log('tooltip数据值', params[i].value);
  460. //遍历出来的值一般是字符串,需要转换成数字,再进项tiFixed四舍五入
  461. relVal +=
  462. '<br/>' + params[i].marker + dataCenter.oneTitle +' : ' + Number(params[i].value);
  463. }
  464. return relVal;
  465. },
  466. },
  467. xAxis: {
  468. type: 'category',
  469. data: dataCenter.cahrtsList.time,
  470. axisLabel: {
  471. //x轴文字的配置
  472. show: true,
  473. textStyle: {
  474. color: '#333',
  475. },
  476. formatter: function (val) {
  477. var strs = val.split(''); //字符串数组
  478. var str = '';
  479. for (var i = 0, s; (s = strs[i++]); ) {
  480. //遍历字符串数组
  481. if (i > 5 && i < 17) {
  482. str += s;
  483. }
  484. if (!(i % 10)) str += '\n'; //按需要求余
  485. }
  486. return str;
  487. },
  488. },
  489. },
  490. yAxis: {
  491. type: 'value',
  492. name: '单位:mm',
  493. scale: true,
  494. axisLabel: {
  495. //y轴文字的配置
  496. textStyle: {
  497. color: '#333',
  498. margin: 15,
  499. },
  500. formatter: function (value) {
  501. return value + '';
  502. },
  503. // formatter: '{value} %'//y轴的每一个刻度值后面加上‘%’号
  504. },
  505. splitLine: {
  506. //网格线
  507. lineStyle: {
  508. type: 'dashed', //设置网格线类型 dotted:虚线 solid:实线
  509. width: 1, //y轴线的宽度
  510. color: '#ccc',
  511. },
  512. show: true, //隐藏或显示
  513. },
  514. },
  515. series: [
  516. {
  517. data: dataCenter.cahrtsList.data,
  518. type: 'bar',
  519. smooth: true,
  520. },
  521. ],
  522. };
  523. option && chart.setOption(option);
  524. }
  525. function echarts2(echarts2Data) {
  526. chart2 = echarts.init(document.getElementById('myElement2'));
  527. var option = {
  528. toolbox: {
  529. feature: {
  530. saveAsImage: {
  531. name: `降雨量(多站)`
  532. }
  533. }
  534. },
  535. tooltip: {
  536. trigger: 'axis',
  537. axisPointer: {
  538. type: 'shadow',
  539. },
  540. formatter(params) {
  541. var relVal = params[0].name;
  542. for (var i = 0, l = params.length; i < l; i++) {
  543. console.log('tooltip数据值', params[i].value);
  544. //遍历出来的值一般是字符串,需要转换成数字,再进项tiFixed四舍五入
  545. relVal +=
  546. '<br/>' + params[i].marker + Number(params[i].value);
  547. }
  548. return relVal;
  549. },
  550. },
  551. xAxis: {
  552. type: 'category',
  553. data: echarts2Data.name,
  554. axisLabel: {
  555. //x轴文字的配置
  556. show: true,
  557. textStyle: {
  558. color: '#333',
  559. },
  560. // formatter: function (val) {
  561. // var strs = val.split(''); //字符串数组
  562. // var str = '';
  563. // for (var i = 0, s; (s = strs[i++]); ) {
  564. // //遍历字符串数组
  565. // if (i > 5 && i < 17) {
  566. // str += s;
  567. // }
  568. // if (!(i % 10)) str += '\n'; //按需要求余
  569. // }
  570. // return str;
  571. // },
  572. },
  573. },
  574. yAxis: {
  575. type: 'value',
  576. name: '单位:mm',
  577. scale: true,
  578. axisLabel: {
  579. //y轴文字的配置
  580. textStyle: {
  581. color: '#333',
  582. margin: 15,
  583. },
  584. formatter: function (value) {
  585. return value + '';
  586. },
  587. // formatter: '{value} %'//y轴的每一个刻度值后面加上‘%’号
  588. },
  589. splitLine: {
  590. //网格线
  591. lineStyle: {
  592. type: 'dashed', //设置网格线类型 dotted:虚线 solid:实线
  593. width: 1, //y轴线的宽度
  594. color: '#ccc',
  595. },
  596. show: true, //隐藏或显示
  597. },
  598. },
  599. series: [
  600. {
  601. data: echarts2Data.value,
  602. type: 'bar',
  603. smooth: true,
  604. },
  605. ],
  606. };
  607. option && chart2.setOption(option);
  608. }
  609. const exportData = () => {
  610. let header = {};
  611. dataCenter.exportColumns.forEach((element) => {
  612. if(element.title == '时间'){
  613. header[element.key] = element.title ? element.title : 'time';
  614. }else{
  615. element.children.forEach(elements => {
  616. header[elements.key] = elements.title ? elements.title : 'time';
  617. });
  618. }
  619. });
  620. jsonToSheetXlsx({
  621. data:dataCenter.exportdataSource,
  622. header: header,
  623. filename: '雨情历史查询.xlsx',
  624. });
  625. }
  626. onMounted(async () => {
  627. getRiveTreeData();
  628. // setTimeout(() => {
  629. // dataCenter.searchFormSchema[2].defaultValue = [getNowTime(2), getNowTime(1)];
  630. // }, 1000);
  631. getForm().setFieldsValue({
  632. queryTime: [getNowTime(2), getNowTime(1)],
  633. });
  634. setTimeout(() => {
  635. reload();
  636. }, 0);
  637. });
  638. </script>
  639. <style scoped lang="less">
  640. .form-box {
  641. position: absolute;
  642. z-index: 9;
  643. width: 66.6666%;
  644. .custom-input {
  645. width: calc(100% - 100px);
  646. }
  647. }
  648. .span-label {
  649. width: 90px;
  650. padding-right: 10px;
  651. display: inline-block;
  652. text-align: right;
  653. line-height: 32px;
  654. }
  655. .marg-left {
  656. margin-left: 10px;
  657. }
  658. .ant-table-striped-modal {
  659. margin-top: 20px;
  660. }
  661. .box-basic {
  662. height: calc(100% - 46px);
  663. width: calc(100% - 28px);
  664. position: absolute;
  665. // min-height: 600px;
  666. }
  667. .moddal-box {
  668. display: flex;
  669. height: calc(100% - 32px);
  670. .left-box {
  671. width: 140px;
  672. overflow: hidden;
  673. height: 100%;
  674. background-color: #f4f4f4;
  675. ul {
  676. padding: 10px;
  677. li {
  678. line-height: 40px;
  679. padding-left: 10px;
  680. cursor: pointer;
  681. }
  682. }
  683. }
  684. .center-box {
  685. flex: 1;
  686. overflow: hidden;
  687. height: 100%;
  688. margin-left: 20px;
  689. }
  690. .right-box {
  691. width: 400px;
  692. height: 100%;
  693. overflow: auto;
  694. margin-left: 20px;
  695. position: relative;
  696. ul {
  697. // position: relative;
  698. li {
  699. display: flex;
  700. line-height: 36px;
  701. & > div {
  702. // flex: 1;
  703. text-align: center;
  704. }
  705. & > div:nth-child(1) {
  706. min-width: 180px;
  707. }
  708. & > div:nth-child(2) {
  709. flex: 1;
  710. }
  711. & > div:nth-child(3) {
  712. flex: 1;
  713. }
  714. }
  715. li:nth-child(1) {
  716. position: absolute;
  717. width: 100%;
  718. }
  719. li:nth-child(2) {
  720. padding-top: 36px;
  721. }
  722. }
  723. }
  724. }
  725. .top-search {
  726. padding-bottom: 10px;
  727. }
  728. .active-tab {
  729. background-color: #ccc;
  730. }
  731. </style>