Dashboard.vue 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. <template>
  2. <wrapper margin>
  3. <div
  4. class="l-flex--row c-sibling-item--v c-count u-pointer"
  5. @click="onClickMineDevices"
  6. >
  7. <div class="l-flex__none u-color--black u-bold">我的设备</div>
  8. <div class="l-flex__none c-count__item u-color--black u-bold u-text-center">
  9. <div>总数</div>
  10. <i
  11. v-if="monitor.loading"
  12. class="el-icon-loading"
  13. />
  14. <div v-else>{{ monitor.total }}</div>
  15. </div>
  16. <div class="l-flex__none c-count__item u-color--success dark u-bold u-text-center">
  17. <div>● 在线</div>
  18. <i
  19. v-if="monitor.loading"
  20. class="el-icon-loading"
  21. />
  22. <div v-else>{{ monitor.online }}</div>
  23. </div>
  24. <div class="l-flex__none c-count__item u-color--error dark u-bold u-text-center">
  25. <div>● 离线</div>
  26. <i
  27. v-if="monitor.loading"
  28. class="el-icon-loading"
  29. />
  30. <div v-else>{{ monitor.offline }}</div>
  31. </div>
  32. <div class="l-flex__none c-count__item u-color--info u-bold u-text-center">
  33. <div>● 未启用</div>
  34. <i
  35. v-if="monitor.loading"
  36. class="el-icon-loading"
  37. />
  38. <div v-else>{{ monitor.inactive }}</div>
  39. </div>
  40. <i
  41. class="c-count__refresh el-icon-refresh has-active u-pointer"
  42. @click.stop="onRefresh"
  43. />
  44. </div>
  45. <div
  46. v-if="__PLACEHOLDER__"
  47. class="c-sibling-item--v far c-cards"
  48. >
  49. <card
  50. class="c-cards__item"
  51. type="info"
  52. title="总次数"
  53. tip="100"
  54. />
  55. <card
  56. class="c-cards__item"
  57. type="safety"
  58. title="安全异常"
  59. desc="累计异常数:30"
  60. />
  61. <card
  62. class="c-cards__item"
  63. type="performance"
  64. title="性能异常"
  65. desc="累计异常数:30"
  66. count="3"
  67. />
  68. <card
  69. class="c-cards__item"
  70. type="log"
  71. title="日志异常"
  72. desc="累计异常数:30"
  73. count="10"
  74. />
  75. <card
  76. class="c-cards__item"
  77. type="date"
  78. title="即将空闲排期"
  79. count="100"
  80. />
  81. </div>
  82. <div class="l-grid--info c-sibling-item--v far">
  83. <device
  84. v-for="item in deviceOptions.list"
  85. :key="item.id"
  86. :device="item"
  87. />
  88. </div>
  89. <div
  90. v-if="!deviceOptions.loaded"
  91. class="c-sibling-item--v far u-text-center"
  92. >
  93. <i class="el-icon-loading" />
  94. </div>
  95. <iframe
  96. v-if="elk"
  97. class="c-sibling-item--v far"
  98. style="height: 850px; border: none;"
  99. :src="elk"
  100. />
  101. </wrapper>
  102. </template>
  103. <script>
  104. import {
  105. subscribe,
  106. unsubscribe
  107. } from '@/utils/mqtt'
  108. import {
  109. getDevices,
  110. getDeviceStatistics
  111. } from '@/api/device'
  112. import Card from './components/Card'
  113. import Device from './components/Device'
  114. export default {
  115. name: 'Dashboard',
  116. components: {
  117. Card,
  118. Device
  119. },
  120. data () {
  121. return {
  122. monitor: { loading: true },
  123. deviceOptions: {
  124. list: [],
  125. loaded: false
  126. },
  127. elk: process.env.VUE_APP_SENSOR_ELK
  128. }
  129. },
  130. created () {
  131. this.$timer = -1
  132. this.refreshDevices(true)
  133. subscribe([
  134. '+/+/online',
  135. '+/+/offline',
  136. '+/+/calendar/update'
  137. ], this.onMessage)
  138. },
  139. beforeDestroy () {
  140. clearTimeout(this.$timer)
  141. this.monitor = { loading: true }
  142. unsubscribe([
  143. '+/+/online',
  144. '+/+/offline',
  145. '+/+/calendar/update'
  146. ], this.onMessage)
  147. },
  148. methods: {
  149. onMessage (topic) {
  150. if (this.deviceOptions.loaded) {
  151. return
  152. }
  153. const result = /^\d+\/(\d+)\/(online|offline)$/.exec(topic)
  154. if (!result) {
  155. return
  156. }
  157. const deviceId = result[1]
  158. const status = result[2]
  159. const device = this.deviceOptions.list.find(({ id }) => id === deviceId)
  160. if (device) {
  161. const onlineStatus = device.onlineStatus === 1 ? 'online' : 'offline'
  162. if (status === onlineStatus) {
  163. return
  164. }
  165. } else if (status === 'offline') {
  166. return
  167. }
  168. this.refreshDevices()
  169. },
  170. onRefresh () {
  171. this.refreshDevices()
  172. },
  173. refreshDevices (force) {
  174. if (!force && this.monitor.loading) {
  175. return
  176. }
  177. const monitor = {
  178. loading: true,
  179. total: '-',
  180. online: '-',
  181. offline: '-',
  182. inactive: '-'
  183. }
  184. this.monitor = monitor
  185. clearTimeout(this.$timer)
  186. this.deviceOptions = { loaded: false }
  187. getDeviceStatistics().then(({ data }) => {
  188. const { notEnabledTotal, offLineTotal, onLineTotal, total } = data
  189. monitor.total = total || 0
  190. monitor.online = onLineTotal || 0
  191. monitor.offline = offLineTotal || 0
  192. monitor.inactive = notEnabledTotal || 0
  193. }).finally(() => {
  194. monitor.loading = false
  195. if (!this.monitor.loading) {
  196. this.getDevices(this.monitor.total)
  197. }
  198. })
  199. },
  200. sort (a, b) {
  201. if (a.onlineStatus === 1) {
  202. return -1
  203. }
  204. return b.onlineStatus === 1 ? 1 : -1
  205. },
  206. getDevices (total) {
  207. if (!total || total === '-') {
  208. this.deviceOptions = { list: [], loaded: true }
  209. return
  210. }
  211. const options = { list: [], loaded: false }
  212. this.deviceOptions = options
  213. getDevices({
  214. pageNum: 1,
  215. pageSize: total,
  216. activate: 2
  217. }, { custom: true }).then(
  218. ({ data }) => {
  219. options.list = data.sort(this.sort)
  220. options.loaded = true
  221. },
  222. ({ isCancel }) => {
  223. if (!isCancel && !this.monitor.loading) {
  224. this.$timer = setTimeout(total => {
  225. this.getDevices(total)
  226. }, 2000, total)
  227. }
  228. }
  229. )
  230. },
  231. onClickMineDevices () {
  232. this.$router.push({
  233. name: 'device-list'
  234. })
  235. }
  236. }
  237. }
  238. </script>
  239. <style lang="scss" scoped>
  240. .c-count {
  241. justify-content: space-between;
  242. padding: 8px $spacing;
  243. border-radius: $radius;
  244. background-color: #fff;
  245. &__item > div:first-child {
  246. margin-bottom: 10px;
  247. }
  248. &__refresh {
  249. color: $blue;
  250. font-size: 28px;
  251. }
  252. }
  253. .c-cards {
  254. display: grid;
  255. grid-template-columns: repeat(5, 1fr);
  256. grid-column-gap: $spacing;
  257. &__item {
  258. min-width: 0;
  259. }
  260. }
  261. </style>