index.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. <template>
  2. <div class="main">
  3. <div class="business-box">
  4. <div>
  5. <div class="tree-box">
  6. <a-input-search v-model:value="searchValue" style="margin-bottom: 8px" placeholder="遥测站搜索" />
  7. <div class="tree-top-box">
  8. <a-collapse v-model:activeKey="activeKey3" :bordered="false">
  9. <template #expandIcon="{ isActive }">
  10. <caret-right-outlined :rotate="isActive ? 90 : 0" />
  11. </template>
  12. <a-collapse-panel @click="rootNode(treeData.allComData)" key="2" header="信道" :style="{ ...customStyle }">
  13. <ul class="tree-ul">
  14. <li :style="activeTree == item.com_name ? activeStyleObj : {}" @click="communication(item)"
  15. v-for="(item, index) in treeData.allComData.table_value" :key="index">
  16. {{ item.com_name }}({{ item.port }})
  17. </li>
  18. </ul>
  19. </a-collapse-panel>
  20. </a-collapse>
  21. </div>
  22. <div class="tree-bottom">
  23. <a-collapse v-model:activeKey="activeKey2" :bordered="false">
  24. <template #expandIcon="{ isActive }">
  25. <caret-right-outlined :rotate="isActive ? 90 : 0" />
  26. </template>
  27. <!-- treeData.treeNum -->
  28. <a-collapse-panel key="2" :header="'遥测站'" :style="{ ...customStyle }">
  29. <a-collapse v-model:activeKey="activeKey" :bordered="false">
  30. <template #expandIcon="{ isActive }">
  31. <caret-right-outlined :rotate="isActive ? 90 : 0" />
  32. </template>
  33. <a-collapse-panel v-for="(item, index, i) in treeData.riverTreeData.data_value.station" :key="index"
  34. :header="setSiteName(index)" :style="{ ...customStyle }">
  35. <a-collapse v-model:activeKey="activeKey1" :bordered="false">
  36. <template #expandIcon="{ isActive }">
  37. <caret-right-outlined :rotate="isActive ? 90 : 0" />
  38. </template>
  39. <a-collapse-panel @click="tabCjData(items, index)" v-for="(items, indexs) in item"
  40. :key="items.st_name" :header="`${items.st_name}(${items.stcd})`" :style="{ ...customStyle }"
  41. :class="{
  42. 'active-style': activeTree == items.stcd,
  43. }">
  44. <ul class="tree-ul">
  45. <li :style="activeTree == element.senid ? activeStyleObj : {}"
  46. @click.stop="tabCjData(element)" v-for="(element, indexss) in items.sensor" :key="indexss">
  47. {{ element.sensor_name }}({{ element.senid }})
  48. </li>
  49. </ul>
  50. </a-collapse-panel>
  51. </a-collapse>
  52. </a-collapse-panel>
  53. </a-collapse>
  54. </a-collapse-panel>
  55. </a-collapse>
  56. </div>
  57. </div>
  58. </div>
  59. <div>
  60. <div>
  61. <div class="message-title">
  62. {{ messageTitle }}
  63. <span v-show="activeType == 1" @click="showModalFn" class="more-box">更多》</span>
  64. </div>
  65. <a-table class="ant-table-striped" :dataSource="tableData.table_value"
  66. :rowClassName="(record, index) => (index % 2 === 1 ? 'table-striped' : null)" bordered size="middle"
  67. :columns="tableData.table_head" :pagination="false" :scroll="{ y: 'calc(50vh - 140px)' }" />
  68. </div>
  69. <div class="message-box">
  70. <div class="message-title"> 报文解析日志 </div>
  71. <ul>
  72. <li v-for="(item, index) in treeData.logData" :key="index">
  73. <div>{{ item.in_time }} {{ item.st_name }}({{ item.stcd }})</div>
  74. <div>
  75. <div>{{ item.msg_type }}</div>
  76. <!-- <div>雨量:<span>121.20</span></div> -->
  77. <div>{{ item.content }}</div>
  78. <!-- <div>电压:<span>121.20</span></div>
  79. <div>发信包数:<span>2000</span></div> -->
  80. </div>
  81. <div>
  82. {{ item.msg }}
  83. </div>
  84. </li>
  85. </ul>
  86. </div>
  87. </div>
  88. </div>
  89. <BasicModal :maskClosable="false" :footer="null" @cancel="cancel" :visible="showModal" :width="1200"
  90. :title="basicModalTitle">
  91. <div>
  92. <div class="top-search">
  93. 时间范围:
  94. <a-range-picker :value="timeData.time" :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss"
  95. :placeholder="['开始时间', '结束时间']" @change="onChange" :allowClear="true" />
  96. <a-button @click="communicationHistory" class="marg-left" type="primary">查询</a-button>
  97. </div>
  98. <div class="modal-table">
  99. <a-table class="ant-table-striped ant-table-striped-modal" :dataSource="tableDataModal.table_value"
  100. :rowClassName="(record, index) => (index % 2 === 1 ? 'table-striped' : null)" bordered size="middle"
  101. :pagination="true" :columns="tableDataModal.table_head" :scroll="{ y: '60vh' }" />
  102. </div>
  103. </div>
  104. </BasicModal>
  105. </div>
  106. </template>
  107. <script lang="ts" setup>
  108. import { defineComponent, ref, watch, onMounted, reactive, onUnmounted } from 'vue';
  109. import {
  110. getAllCom,
  111. getRiverTree,
  112. getAllComData,
  113. getParseLog,
  114. getCjData,
  115. } from '/@/api/swHome/index';
  116. import { debounce } from 'lodash';
  117. import { CaretRightOutlined } from '@ant-design/icons-vue';
  118. import { BasicModal } from '/@/components/Modal/index';
  119. const searchValue = ref<string>('');
  120. const activeKey = ref([]);
  121. const activeKey1 = ref([]);
  122. const activeKey2 = ref([]);
  123. const activeKey3 = ref('2');
  124. const customStyle = {
  125. background: '#fff',
  126. 'border-radius': '4px',
  127. padding: '0px',
  128. border: '0',
  129. overflow: 'hidden',
  130. };
  131. const activeStyleObj = {
  132. background: 'rgba(6, 113, 221, 0.1)',
  133. };
  134. let messageTitle = ref('信道列表');
  135. let treeData = reactive({
  136. allComData: [],
  137. riverTreeData: [],
  138. treeNum: 0,
  139. logData: [],
  140. });
  141. let tableData = reactive({
  142. table_head: [],
  143. table_value: [],
  144. });
  145. let tableDataModal = reactive({
  146. table_head: [],
  147. table_value: [],
  148. });
  149. let activeTree = ref('');
  150. let activeType = ref('1');
  151. let showModal = ref(false);
  152. let basicModalTitle = ref();
  153. let timeData = reactive({
  154. time: [],
  155. });
  156. function rootNode(table) {
  157. messageTitle.value = '信道列表';
  158. let table_head = [];
  159. table.table_head.forEach((item, index) => {
  160. for (const key in item) {
  161. if (Object.prototype.hasOwnProperty.call(item, key)) {
  162. const element = item[key];
  163. table_head.push({
  164. title: element,
  165. key: key,
  166. dataIndex: key,
  167. });
  168. }
  169. }
  170. });
  171. tableData.table_head = table_head;
  172. tableData.table_value = table.table_value;
  173. }
  174. function onChange(value, dateString) {
  175. timeData.time = dateString;
  176. }
  177. // 弹窗
  178. function showModalFn() {
  179. timeData.time = [];
  180. showModal.value = true;
  181. // 查询默认数据
  182. communicationHistory();
  183. }
  184. let historyFormData = reactive({
  185. com_name: '',
  186. start_time: '',
  187. end_time: '',
  188. });
  189. // 查询历史数据
  190. function communicationHistory() {
  191. historyFormData.start_time = timeData.time[0] ? timeData.time[0] : '';
  192. historyFormData.end_time = timeData.time[1] ? timeData.time[1] : '';
  193. getAllComData(historyFormData).then((res) => {
  194. let { table_head, table_value } = res.data;
  195. tableDataModal.table_head = table_head;
  196. tableDataModal.table_value = table_value;
  197. // 处理数据
  198. processingData(tableDataModal.table_head);
  199. });
  200. }
  201. function cancel(e) {
  202. showModal.value = false;
  203. }
  204. //数据拍平
  205. function dataFlattening() {
  206. treeData.treeNum = 0;
  207. treeData.riverTreeData.data_value.forEach((element) => {
  208. element.stationArr = [];
  209. for (let key in element.station) {
  210. let elements = element.station[key];
  211. element.stationArr = [...element.stationArr, ...elements];
  212. }
  213. element.stationArr.forEach((elements) => {
  214. treeData.treeNum += elements.sensor.length;
  215. });
  216. });
  217. }
  218. function setSiteName(value) {
  219. let name = '';
  220. switch (value) {
  221. case 'st_hydro':
  222. name = '水文站';
  223. break;
  224. case 'st_waterz':
  225. name = '水位站';
  226. break;
  227. case 'st_rain':
  228. name = '雨量站';
  229. break;
  230. case 'st_wea_general':
  231. name = '一般气象站';
  232. break;
  233. case 'st_ts':
  234. name = '碳水通量站';
  235. break;
  236. case 'st_wea_standard':
  237. name = '标准气象站';
  238. break;
  239. default:
  240. name = value;
  241. break;
  242. }
  243. return name;
  244. }
  245. function processingData(table_head) {
  246. table_head.forEach((element) => {
  247. for (let key in element) {
  248. let item = element[key];
  249. element.title = item;
  250. element.key = key;
  251. element.dataIndex = key;
  252. if (element.title == '时间') {
  253. element.width = 200;
  254. }
  255. }
  256. });
  257. }
  258. // 点击信道获取通信子节点
  259. function communication(item) {
  260. historyFormData.com_name = item.com_name;
  261. messageTitle.value = `信道列表(${item.com_name})`;
  262. basicModalTitle.value = `信道报文历史查询(${item.com_name})`;
  263. activeType.value = '1';
  264. activeTree.value = item.com_name;
  265. getAllComData({ com_name: item.com_name }).then((res) => {
  266. let { table_head, table_value } = res.data;
  267. tableData.table_head = table_head;
  268. tableData.table_value = table_value;
  269. // 处理数据
  270. processingData(tableData.table_head);
  271. });
  272. }
  273. // 点击获取测站节点/传感器节点
  274. function tabCjData(item, indexType) {
  275. activeTree.value = item.senid ? item.senid : item.stcd;
  276. activeType.value = '2';
  277. let formData = {
  278. stcd: '',
  279. type: '',
  280. };
  281. if (item.senid) {
  282. // 获取sensor传感器
  283. formData.stcd = item.senid;
  284. formData.type = 'sensor';
  285. messageTitle.value = `传感器列表(${item.sensor_name})`;
  286. } else {
  287. // 获取测站
  288. formData.stcd = item.stcd;
  289. formData.type = 'station';
  290. messageTitle.value = `测站列表(${item.st_name})`;
  291. }
  292. getCjData(formData).then((res) => {
  293. let { table_head, table_value } = res.data;
  294. tableData.table_head = table_head;
  295. tableData.table_value = table_value;
  296. processingData(tableData.table_head);
  297. });
  298. }
  299. let treeDataList = null
  300. //获取左侧树桩数据
  301. async function getInitData() {
  302. // 信道数据
  303. getAllCom().then((res) => {
  304. treeData.allComData = res.data;
  305. treeData.allComData.table_value;
  306. communication(treeData.allComData.table_value[0]);
  307. });
  308. // 遥测站数据
  309. getRiverTree().then((res) => {
  310. treeDataList = res.data
  311. for (const key in treeDataList.data_value.station) {
  312. if (Object.prototype.hasOwnProperty.call(treeDataList.data_value.station, key)) {
  313. const element = treeDataList.data_value.station[key];
  314. element.forEach(elements => {
  315. elements.isValue = 1
  316. elements.sensor.forEach(elementss => {
  317. elementss.isValue = 1
  318. });
  319. });
  320. }
  321. }
  322. treeData.riverTreeData = treeDataList;
  323. dataFlattening();
  324. });
  325. // 获取报文解析
  326. }
  327. const getParseLogData = () => {
  328. getParseLog().then((res) => {
  329. treeData.logData = res.data;
  330. });
  331. }
  332. let myInterval = null
  333. onUnmounted(() => {
  334. clearInterval(myInterval)
  335. })
  336. /**
  337. * 处理搜索页面
  338. */
  339. watch(searchValue, debounce((value) => {
  340. console.log(9900)
  341. // 将搜索能够搜索到的先打上标签
  342. let activeKeyArr = []
  343. let st_nameArr = []
  344. for (const key in treeDataList.data_value.station) {
  345. if (Object.prototype.hasOwnProperty.call(treeDataList.data_value.station, key)) {
  346. const element = treeDataList.data_value.station[key];
  347. // activeKeyArr.push(key)
  348. element.forEach(elements => {
  349. elements.isValue = 0
  350. if (elements.st_name.indexOf(value) > -1 || (elements.stcd + '').indexOf(value) > -1) {
  351. elements.isValue = 1
  352. st_nameArr.push(elements.st_name)
  353. activeKeyArr.push(key)
  354. }
  355. elements.sensor.forEach(elementss => {
  356. elementss.isValue = 0
  357. if (elementss.sensor_name.indexOf(value) > -1 || (elementss.senid + '').indexOf(value) > -1) {
  358. elementss.isValue = 1
  359. }
  360. });
  361. // 判断下级是否有选中,如果有选中将上级默认设置为1
  362. elements.sensor.forEach(elementss => {
  363. if (elementss.isValue == 1) {
  364. elements.isValue = 1
  365. st_nameArr.push(elements.st_name)
  366. activeKeyArr.push(key)
  367. }
  368. });
  369. });
  370. }
  371. }
  372. treeData.riverTreeData = treeDataList;
  373. if (value == '') {
  374. activeKey2.value = ['2']
  375. activeKey.value = []
  376. activeKey1.value = []
  377. return
  378. }
  379. activeKey2.value = ['2']
  380. activeKey.value = activeKeyArr
  381. activeKey1.value = st_nameArr
  382. }, 0));
  383. onMounted(() => {
  384. getInitData();
  385. getParseLogData()
  386. myInterval = setInterval(() => {
  387. getParseLogData()
  388. }, 15000)
  389. });
  390. </script>
  391. <style lang="scss" scoped>
  392. .business-box {
  393. display: flex;
  394. &>div:nth-child(1) {
  395. min-width: 300px;
  396. width: 300px;
  397. background-color: #fff;
  398. height: calc(100vh - 80px);
  399. border-radius: 5px;
  400. padding: 10px;
  401. overflow: auto;
  402. }
  403. &>div:nth-child(2) {
  404. margin-left: 10px;
  405. flex: 1;
  406. &>div:nth-child(1) {
  407. background-color: #fff;
  408. height: calc(50vh - 45px);
  409. padding: 10px;
  410. border-radius: 5px;
  411. }
  412. &>div:nth-child(2) {
  413. margin-top: 10px;
  414. background-color: #fff;
  415. height: calc(50vh - 45px);
  416. padding: 10px;
  417. border-radius: 5px;
  418. }
  419. }
  420. }
  421. .message-title {
  422. font-size: 16px;
  423. position: relative;
  424. }
  425. .message-box {
  426. ul {
  427. width: 100%;
  428. height: calc(100% - 30px);
  429. overflow: auto;
  430. li {
  431. padding: 5px;
  432. border-radius: 4px;
  433. background-color: #f8f8f8;
  434. line-height: 30px;
  435. margin-bottom: 10px;
  436. &>div:nth-child(1) {
  437. color: #0671dd;
  438. font-size: 14px;
  439. }
  440. &>div:nth-child(2) {
  441. display: flex;
  442. flex-wrap: wrap;
  443. &>div {
  444. margin-right: 40px;
  445. }
  446. &>div:last-child {
  447. // margin-left: auto;
  448. margin-right: 0;
  449. }
  450. span {
  451. color: #0671dd;
  452. }
  453. }
  454. }
  455. }
  456. }
  457. ::v-deep .ant-collapse-header {
  458. padding: 0px !important;
  459. padding-left: 40px !important;
  460. }
  461. ::v-deep .ant-collapse-content>.ant-collapse-content-box {
  462. padding-bottom: 0 !important;
  463. padding-right: 0px !important;
  464. }
  465. .tree-ul {
  466. padding-left: 26px;
  467. margin-bottom: 0px;
  468. li {
  469. line-height: 28px;
  470. cursor: pointer;
  471. }
  472. }
  473. .active-style {
  474. background: rgba(6, 113, 221, 0.1) !important;
  475. }
  476. .ant-table-striped :deep(.table-striped) td {
  477. background-color: #fafafa;
  478. }
  479. .more-box {
  480. position: absolute;
  481. right: 0px;
  482. font-size: 14px;
  483. color: #0671dd;
  484. cursor: pointer;
  485. }
  486. .marg-left {
  487. margin-left: 10px;
  488. }
  489. .ant-table-striped-modal {
  490. margin-top: 20px;
  491. }
  492. </style>