Dashboard.vue 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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. }
  166. this.refreshDevices()
  167. },
  168. onRefresh () {
  169. this.refreshDevices()
  170. },
  171. refreshDevices (force) {
  172. if (!force && this.monitor.loading) {
  173. return
  174. }
  175. const monitor = {
  176. loading: true,
  177. total: '-',
  178. online: '-',
  179. offline: '-',
  180. inactive: '-'
  181. }
  182. this.monitor = monitor
  183. clearTimeout(this.$timer)
  184. this.deviceOptions = { loaded: false }
  185. getDeviceStatistics().then(({ data }) => {
  186. const { deactivatedTotal, notConnectedTotal, offLineTotal, onLineTotal, total } = data
  187. monitor.total = total
  188. monitor.online = onLineTotal
  189. monitor.offline = offLineTotal + notConnectedTotal
  190. monitor.inactive = deactivatedTotal
  191. }).finally(() => {
  192. monitor.loading = false
  193. if (!this.monitor.loading) {
  194. this.getDevices(this.monitor.total - this.monitor.inactive)
  195. }
  196. })
  197. },
  198. sort (a, b) {
  199. if (a.onlineStatus === b.onlineStatus) {
  200. return a.createTime <= b.createTime ? 1 : -1
  201. }
  202. return a.onlineStatus === 1 ? -1 : 1
  203. },
  204. getDevices (total) {
  205. if (!total || total === '-') {
  206. this.deviceOptions = { list: [], loaded: true }
  207. return
  208. }
  209. const options = { list: [], loaded: false }
  210. this.deviceOptions = options
  211. getDevices({
  212. pageNum: 1,
  213. pageSize: total,
  214. activate: 1
  215. }, { custom: true }).then(
  216. ({ data }) => {
  217. options.list = data.sort(this.sort)
  218. options.loaded = true
  219. },
  220. ({ isCancel }) => {
  221. if (!isCancel && !this.monitor.loading) {
  222. this.$timer = setTimeout(total => {
  223. this.getDevices(total)
  224. }, 2000, total)
  225. }
  226. }
  227. )
  228. },
  229. onClickMineDevices () {
  230. this.$router.push({
  231. name: 'device-list'
  232. })
  233. }
  234. }
  235. }
  236. </script>
  237. <style lang="scss" scoped>
  238. .c-count {
  239. justify-content: space-between;
  240. padding: 8px $spacing;
  241. border-radius: $radius;
  242. background-color: #fff;
  243. &__item > div:first-child {
  244. margin-bottom: 10px;
  245. }
  246. &__refresh {
  247. color: $blue;
  248. font-size: 28px;
  249. }
  250. }
  251. .c-cards {
  252. display: grid;
  253. grid-template-columns: repeat(5, 1fr);
  254. grid-column-gap: $spacing;
  255. &__item {
  256. min-width: 0;
  257. }
  258. }
  259. </style>