CurveRetentivity.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. <template>
  2. <div class="curve_statistical_box">
  3. <div v-show="show_org" class="station_tree">
  4. <div style="padding:5px;">
  5. <el-input
  6. size="small"
  7. v-model="search_data"
  8. prefix-icon="el-icon-search"
  9. placeholder="请输入关键字搜索"
  10. >
  11. </el-input>
  12. </div>
  13. <el-tree
  14. node-key="id"
  15. ref="zzj_tree"
  16. :data="station_tree"
  17. :default-expanded-keys="defaultShowNodes"
  18. :props="defaultProps"
  19. :highlight-current="isHighlight"
  20. :expand-on-click-node="true"
  21. :filter-node-method="filterNode"
  22. >
  23. <span slot-scope="{ node, data }">
  24. <span
  25. :class="{
  26. is_disabled: computed_is_disabled(data),
  27. }"
  28. :style="{ backgroundColor: data.id == click_id ? '#304156' : '' }"
  29. @click="handle_node_click(data, node)"
  30. >{{ data.name }}</span
  31. >
  32. </span>
  33. </el-tree>
  34. </div>
  35. <div class="charts">
  36. <div class="times">
  37. <i
  38. :class="[show_org ? 'el-icon-s-fold' : 'el-icon-s-unfold', 'show_org']"
  39. @click="show_org = !show_org"
  40. ></i>
  41. <el-date-picker
  42. v-model="times"
  43. size="small"
  44. :clearable="false"
  45. type="datetimerange"
  46. style="width:280px;margin:0px 5px;"
  47. value-format="timestamp"
  48. format="yyyy-MM-dd"
  49. @change="get_has_records"
  50. range-separator="至"
  51. start-placeholder="开始日期"
  52. end-placeholder="结束日期"
  53. >
  54. </el-date-picker>
  55. <el-button
  56. style="margin-left:8px;"
  57. icon="el-icon-search"
  58. type="primary"
  59. size="small"
  60. @click="get_has_records"
  61. >查询</el-button>
  62. <el-button
  63. style="margin-left:8px;"
  64. type="primary"
  65. size="small"
  66. @click="alarm_warn_setting('dw_alarm_low_drop')"
  67. >保持力报警设置</el-button
  68. >
  69. <el-button
  70. style="margin-left:8px;"
  71. icon="el-icon-download"
  72. type="primary"
  73. size="small"
  74. v-debounce="export_img"
  75. >导出图片</el-button
  76. >
  77. <el-button style="margin-left: 5px;" type="primary" size="mini" @click="localtion_history">历史数据</el-button>
  78. </div>
  79. <div
  80. v-loading="loading"
  81. element-loading-text="拼命加载中"
  82. element-loading-spinner="el-icon-loading"
  83. element-loading-background="rgba(31, 31, 31, 0.6)"
  84. class="charts_box"
  85. id="export_img"
  86. >
  87. <div ref="one" id="one" class="curve"></div>
  88. </div>
  89. </div>
  90. <!-- 转换阻力设置 -->
  91. <div class="dw_alarm_low_drop">
  92. <el-dialog
  93. width="400px"
  94. title="保持力报警配置"
  95. :lock-scroll="true"
  96. :show-close="true"
  97. @close="val => cancel_setting(val, 'dw_alarm_low_drop')"
  98. :close-on-click-modal="false"
  99. :close-on-press-escape="false"
  100. :visible.sync="dialogVisible"
  101. >
  102. <div class=" position_left" style="text-align: left;">
  103. <span class="mark"></span>状态&nbsp;&nbsp;&nbsp;
  104. <el-radio-group v-model="retension_enable">
  105. <el-radio :label=true>启用</el-radio>
  106. <el-radio :label=false>未启用</el-radio>
  107. </el-radio-group>
  108. </div>
  109. <div class="position_top_20 position_left" style="text-align: left;">
  110. <span class="mark"></span>位置&nbsp;&nbsp;&nbsp;
  111. <el-radio-group v-model="retension_posi" @change="posi_change()">
  112. <el-radio :label="100">定位</el-radio>
  113. <el-radio :label="101">反位</el-radio>
  114. </el-radio-group>
  115. </div>
  116. <div class="position_top_20 position_left" style="text-align: left;">
  117. <span class="mark">*</span>最低报警值:
  118. <!-- <el-input style="width:200px;margin-left: 58px;" v-model="dw_alarm_low_drop" oninput="value=value.replace(/^0|[^0-9]/g,'')" size="small" maxlength="5" placeholder="请输入0~40000之间的数字" ></el-input> -->
  119. <el-input style="width:180px;" v-model="dw_alarm_low_drop" size="small" maxlength="7" placeholder="请输入-100000~100000之间的数字" ></el-input>
  120. </div>
  121. <!-- <div class="position_top_20">
  122. <span class="mark">*</span>下降超限百分比(%):
  123. <el-input style="width:200px" v-model="alarm_low_percent" oninput="value=value.replace(/^0|[^0-9]/g,'')" size="small" maxlength="2" placeholder="请输入5~95之间的数字"></el-input>
  124. </div>
  125. <div class="position_top_20">
  126. <span class="mark">*</span>上升超限百分比(%):
  127. <el-input style="width:200px" v-model="alarm_high_percent" oninput="value=value.replace(/^0|[^0-9]/g,'')" size="small" maxlength="2" placeholder="请输入5~95之间的数字"></el-input>
  128. </div> -->
  129. <span slot="footer" class="dialog-footer">
  130. <el-button size="small" @click="cancel_setting('convert_resist')">关 闭</el-button>
  131. <el-button
  132. v-if="$store.state.admin && $store.state.backend_type == 1"
  133. size="small"
  134. type="primary"
  135. @click="save_settting()"
  136. >保 存</el-button
  137. >
  138. </span>
  139. </el-dialog>
  140. </div>
  141. </div>
  142. </template>
  143. <script>
  144. /**
  145. * 增加温度
  146. */
  147. import { retension_curve, commit_record } from '../api'
  148. import curveRetentivityOption from '../chart/curve-retentivity'
  149. import { today } from '../utils/time'
  150. import { exportImage } from '../plugin/html2canvas' // 引入
  151. import { treeCorrelation } from '../mixins/treeCorrelation'
  152. import {get_retension_force,set_retension_force} from '../api'
  153. export default {
  154. name: 'CurveRetentivity',
  155. mixins: [treeCorrelation],
  156. data() {
  157. return {
  158. send_data: {
  159. type: 1,
  160. mo: '',
  161. mp: '',
  162. name: '',
  163. time: '',
  164. end_time: '',
  165. }, //获取阻力曲线图
  166. dialogVisible:false,
  167. retension_enable: true, // 保持力是否启用
  168. retension_posi: 100,
  169. dw_alarm_low_drop: '', // 最低报警值
  170. alarm_low_percent: '', // 下降超限百分比
  171. alarm_high_percent: '', // 上升超限百分比
  172. times: [],
  173. click_id: '', //确认是否激活
  174. curve_data: new Object(), // 曲线数据
  175. loading: false,
  176. myCharts: null,
  177. show_org: true, //是否显示机构
  178. /**曲线数据*/
  179. one_curve: {},
  180. has_data: false, // 当天是否有数据
  181. // 浏览记录
  182. commit_data: {
  183. module: 9,
  184. dura: '', // 必传
  185. analyze_type: 1, // 必传
  186. station: '', // 必传
  187. station_name: '', // 必传
  188. mo: '', // 必传
  189. mo_name: '', // 必传
  190. mp: '', // 必传
  191. mp_name: '', // 必传
  192. start_time: '', // 必传
  193. end_time: '',
  194. time: '', // 必传
  195. name: this.$store.state.name, // 必传
  196. username: this.$store.state.user_name, // 必传
  197. },
  198. res_time: null,
  199. }
  200. },
  201. methods: {
  202. // 位置变化
  203. posi_change() {
  204. if (!this.click_id) return this.$message.warning('请先选择设备...')
  205. let [mo, mp] = this.click_id.split('.')
  206. let send_data = { mo, mp, posi: this.retension_posi }
  207. get_retension_force(send_data)
  208. .then(res => {
  209. this.retension_enable = res.enable;
  210. this.dw_alarm_low_drop = res.dw_alarm_low_drop;
  211. this.alarm_high_percent = res.alarm_high_percent;
  212. this.alarm_low_percent = res.alarm_low_percent;
  213. })
  214. .catch(e => {
  215. console.log(e)
  216. })
  217. },
  218. // 导出Image
  219. export_img() {
  220. if (!this.send_data.mo || !this.send_data.mp)
  221. return this.$message({
  222. type: 'warning',
  223. showClose: true,
  224. duration: 1500,
  225. message: '请选择重要信息',
  226. })
  227. if (!this.has_data)
  228. return this.$message({
  229. type: 'warning',
  230. showClose: true,
  231. duration: 1500,
  232. message: '无数据,无法导出...',
  233. })
  234. let self_node = this.$refs.zzj_tree.getNode(`${this.send_data.mo}.${this.send_data.mp}`) // 自身所在的node
  235. let parent_name = self_node.parent.data.name || self_node.parent.data.id // 上级node的name或id
  236. let file_name = `${parent_name}_${this.send_data.name.replace('.', '')}-${this.$dayjs(
  237. this.one_curve.time * 1000
  238. ).format('YYYY_MM_DD')}` // 文件名
  239. let target_dom = document.getElementById('export_img') // 需要导出的dom元素
  240. exportImage(file_name, target_dom) // 调用导出Image方法
  241. return this.$message({
  242. type: 'success',
  243. showClose: true,
  244. duration: 1500,
  245. message: '导出成功!',
  246. })
  247. },
  248. // 前往历史数据
  249. localtion_history() {
  250. if (!this.send_data.mo || !this.send_data.mp)
  251. return this.$message({
  252. type: 'warning',
  253. showClose: true,
  254. duration: 1500,
  255. message: '请选择重要信息',
  256. })
  257. let route_data = {
  258. name: 'force',
  259. query: {
  260. tag: this.click_id,
  261. time: this.times[0] / 1000,
  262. endtime: this.times[1] / 1000 + 24 * 60 * 60 - 1,
  263. title: this.send_data.name,
  264. },
  265. }
  266. this.$router.push(route_data)
  267. this.$store.state.defaultActive = '/layout/force'
  268. this.$store.commit('handle_save_defaultActive', '/layout/force')
  269. },
  270. // 点击树结构
  271. handle_node_click(data, node) {
  272. if (data.type != 'mo.mp') return
  273. if (!data['IMEI'] && this.$store.state.backend_type == 1)
  274. return this.$message({
  275. type: 'warning',
  276. showClose: true,
  277. duration: 1500,
  278. message: '未绑定设备...',
  279. })
  280. /**浏览记录*/
  281. if (this.res_time) {
  282. this.commit_data.dura = +new Date() - this.res_time
  283. let copy_data = _.cloneDeep(this.commit_data)
  284. this.send_record(copy_data)
  285. }
  286. this.res_time = +new Date()
  287. this.commit_data.station = node.parent.data.id
  288. this.commit_data.station_name = node.parent.data.name
  289. let mo_mp = data.id.split('.')
  290. let mo_mp_name = data.name.split('.')
  291. this.commit_data.mo = mo_mp[0]
  292. this.commit_data.mp = mo_mp[1]
  293. this.commit_data.mo_name = mo_mp_name[0]
  294. this.commit_data.mp_name = mo_mp_name[1]
  295. this.commit_data.time = +new Date()
  296. this.commit_data.start_time = this.times[0]
  297. this.commit_data.end_time = this.times[1]
  298. /**结束*/
  299. this.click_id = data.id
  300. this.send_data.mo = mo_mp[0]
  301. this.send_data.mp = mo_mp[1]
  302. this.send_data.name = data.name
  303. if (this.myCharts) {
  304. this.myCharts.dispose()
  305. this.myCharts = null
  306. }
  307. // this.loading = true
  308. setTimeout(() => {
  309. return this.get_curve_data()
  310. }, 16)
  311. },
  312. // 获取曲线前先看看有没有浏览记录
  313. get_has_records() {
  314. if (this.res_time) {
  315. this.commit_data.dura = +new Date() - this.res_time
  316. let copy_data = _.cloneDeep(this.commit_data)
  317. this.send_record(copy_data)
  318. }
  319. return this.get_curve_data()
  320. },
  321. // 获取曲线数据
  322. get_curve_data() {
  323. if (!this.send_data.mo || !this.send_data.mp)
  324. return this.$message({
  325. type: 'warning',
  326. showClose: true,
  327. duration: 1500,
  328. message: '请选择重要信息',
  329. })
  330. if (this.times[1] - this.times[0] > 7 * 24 * 60 * 60 * 1000)
  331. return this.$message.warning('最多不超过7天,请重新选择范围')
  332. this.send_data.time = this.times[0] / 1000
  333. this.send_data.end_time = this.times[1] / 1000 + 24 * 60 * 60 - 1
  334. this.loading = true
  335. let send_data = _.cloneDeep(this.send_data)
  336. retension_curve(send_data)
  337. .then(res => {
  338. if (send_data.name != res.name) return
  339. this.loading = false
  340. this.one_curve = {}
  341. let one_has_data = res.data.curve_data.every(item => item.data.length == 0)
  342. if (one_has_data) {
  343. this.has_data = false
  344. this.$message({
  345. type: 'warning',
  346. showClose: true,
  347. duration: 1500,
  348. message: '无数据...',
  349. })
  350. } else {
  351. this.has_data = true
  352. res.data.name = res.name
  353. res.data.unit = res.unit
  354. res.data.time = send_data.time
  355. res.data.endtime = send_data.end_time
  356. this.one_curve = _.cloneDeep(res.data)
  357. }
  358. this.draw_position_curve()
  359. })
  360. .catch(e => {
  361. console.log(e)
  362. this.loading = false
  363. this.has_data = false
  364. this.one_curve = {}
  365. this.draw_position_curve()
  366. })
  367. },
  368. // 第一个图
  369. draw_position_curve() {
  370. let myCharts = this.$echarts.getInstanceByDom(document.getElementById('one'))
  371. if (myCharts == null) {
  372. myCharts = this.$echarts.init(document.getElementById('one'))
  373. }
  374. let option = curveRetentivityOption(this.one_curve)
  375. myCharts.setOption(option, true)
  376. window.addEventListener('resize', () => {
  377. myCharts.resize()
  378. })
  379. const resizeOb = new ResizeObserver(entries => {
  380. for (const entry of entries) {
  381. this.$echarts.getInstanceByDom(entry.target).resize()
  382. }
  383. })
  384. resizeOb.observe(this.$refs.one)
  385. },
  386. // 点击获取预报警值
  387. alarm_warn_setting(type) {
  388. let send_data = {};
  389. if (!this.click_id) return this.$message.warning('请先选择设备...')
  390. let [mo, mp] = this.click_id.split('.')
  391. send_data = { mo, mp, posi: this.retension_posi }
  392. get_retension_force(send_data)
  393. .then(res => {
  394. this.retension_enable = res.enable;
  395. this.dw_alarm_low_drop = res.dw_alarm_low_drop;
  396. this.alarm_high_percent = res.alarm_high_percent;
  397. this.alarm_low_percent = res.alarm_low_percent;
  398. this.dialogVisible = true;
  399. })
  400. .catch(e => {
  401. console.log(e)
  402. })
  403. return
  404. },// 关闭预告警设置
  405. cancel_setting(type) {
  406. this.dialogVisible= false;
  407. this.retension_enable= true;
  408. this.retension_posi=100;
  409. this.dw_alarm_low_drop= '';
  410. this.alarm_low_percent= '';
  411. this.alarm_high_percent= '';
  412. },// 保存预告警设置
  413. save_settting() {
  414. if (!this.click_id) return this.$message.warning('请先选择设备...')
  415. let dw_alarm_low_drop = '';
  416. let alarm_low_percent = '';
  417. let alarm_high_percent= '';
  418. let regex = /^-?\d+$/;
  419. if (this.dw_alarm_low_drop) {
  420. if(!regex.test(this.dw_alarm_low_drop) || Math.abs(this.dw_alarm_low_drop) > 100000){
  421. return this.$message.warning('最低报警值要求:-100000~100000之间的数字');
  422. }else{
  423. dw_alarm_low_drop = Number(this.dw_alarm_low_drop);
  424. }
  425. }
  426. if (this.alarm_low_percent ){
  427. if(this.alarm_low_percent < 5 || this.alarm_low_percent > 95){
  428. return this.$message.warning('下降超限百分比要求:5~95之间的数字');
  429. }else{
  430. alarm_low_percent= Number(this.alarm_low_percent);
  431. }
  432. }
  433. if (this.alarm_high_percent ){
  434. if(this.alarm_high_percent < 5 || this.alarm_high_percent > 95){
  435. return this.$message.warning('上升超限百分比要求:5~95之间的数字');
  436. }else{
  437. alarm_high_percent= Number(this.alarm_high_percent);
  438. }
  439. }
  440. let [mo, mp] = this.click_id.split('.')
  441. let send_data = {
  442. mo,
  443. mp,
  444. posi: this.retension_posi,
  445. conf: {
  446. enable: this.retension_enable,
  447. dw_alarm_low_drop:dw_alarm_low_drop,
  448. alarm_low_percent:alarm_low_percent,
  449. alarm_high_percent:alarm_high_percent,
  450. },
  451. }
  452. set_retension_force(send_data)
  453. .then(res => {
  454. return this.$message.success('设置成功...')
  455. })
  456. .catch(e => {
  457. console.log(e)
  458. })
  459. },
  460. // 发送浏览记录
  461. send_record(commit_data) {
  462. if (commit_data.dura <= 500) return
  463. if (!commit_data.station || !commit_data.station_name) return
  464. if (!commit_data.mo || !commit_data.mo_name) return
  465. if (!commit_data.mp || !commit_data.mp_name) return
  466. commit_record([commit_data])
  467. .then(res => {})
  468. .catch(e => {})
  469. },
  470. // 离开界面时
  471. leave_page() {
  472. if (!this.res_time) return
  473. this.commit_data.dura = +new Date() - this.res_time
  474. let copy_data = _.cloneDeep(this.commit_data)
  475. return this.send_record(copy_data)
  476. },
  477. // 获取默认时间
  478. get_time() {
  479. let times = this.$dayjs().format('YYYY-MM-DD 00:00:00')
  480. let unix_time = this.$dayjs(times).unix() * 1000
  481. this.times = [unix_time - 24 * 60 * 60 * 1000, unix_time]
  482. this.draw_position_curve()
  483. },
  484. },
  485. mounted() {
  486. this.get_time()
  487. },
  488. activated() {
  489. if (this.click_id) {
  490. this.res_time = +new Date()
  491. } else {
  492. this.res_time = null
  493. }
  494. },
  495. deactivated() {
  496. this.leave_page()
  497. },
  498. beforeDestroy() {
  499. this.leave_page()
  500. },
  501. }
  502. </script>
  503. <style lang="scss">
  504. .station_tree {
  505. .el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
  506. background-color: transparent;
  507. }
  508. }
  509. </style>
  510. <style lang="scss" scoped>
  511. @import '../../static/css/curve-retentivity.scss';
  512. </style>