Răsfoiți Sursa

feat(dashboard): list switching

common list and following list
Casper Dai 2 ani în urmă
părinte
comite
8479c13558

+ 118 - 52
src/views/dashboard/Dashboard.vue

@@ -5,7 +5,7 @@
   >
     <div class="l-flex__none l-flex--row c-sibling-item--v c-count">
       <div
-        class="l-flex__none u-color--black u-width--sm u-bold u-ellipsis has-active"
+        class="l-flex__none u-width--sm u-color--blue u-bold u-ellipsis has-active"
         @click="onChooseDepartment"
       >
         <i
@@ -14,24 +14,51 @@
         />
         {{ group.name }}
       </div>
-      <div class="l-flex__none c-count__item u-color--black u-bold u-text--center">
-        <div>总数</div>
+      <div
+        class="l-flex__none c-count__item u-color--black u-bold u-text--center u-pointer"
+        @click="onChange('all')"
+      >
+        <div class="u-relative">
+          总数
+          <i
+            v-if="active === 'all'"
+            class="c-count__current el-icon-caret-left"
+          />
+        </div>
         <i
           v-if="monitor.loading"
           class="el-icon-loading"
         />
         <div v-else>{{ monitor.total }}</div>
       </div>
-      <div class="l-flex__none c-count__item u-color--success dark u-bold u-text--center">
-        <div>● 在线</div>
+      <div
+        class="l-flex__none c-count__item u-color--success dark u-bold u-text--center u-pointer"
+        @click="onChange('online')"
+      >
+        <div class="u-relative">
+          ● 在线
+          <i
+            v-if="active === 'online'"
+            class="c-count__current el-icon-caret-left"
+          />
+        </div>
         <i
           v-if="monitor.loading"
           class="el-icon-loading"
         />
         <div v-else>{{ monitor.online }}</div>
       </div>
-      <div class="l-flex__none c-count__item u-color--error dark u-bold u-text--center">
-        <div>● 离线</div>
+      <div
+        class="l-flex__none c-count__item u-color--error dark u-bold u-text--center u-pointer"
+        @click="onChange('offline')"
+      >
+        <div class="u-relative">
+          ● 离线
+          <i
+            v-if="active === 'offline'"
+            class="c-count__current el-icon-caret-left"
+          />
+        </div>
         <i
           v-if="monitor.loading"
           class="el-icon-loading"
@@ -39,7 +66,7 @@
         <div v-else>{{ monitor.offline }}</div>
       </div>
       <div class="l-flex__none c-count__item u-color--info u-bold u-text--center">
-        <div>● 未启用</div>
+        <div>● 未接入</div>
         <i
           v-if="monitor.loading"
           class="el-icon-loading"
@@ -51,9 +78,24 @@
         @click="onRefresh"
       />
     </div>
+    <div
+      v-if="deviceOptions.loaded && !deviceOptions.list.length"
+      class="c-sibling-item--v"
+    >
+      <el-empty
+        class="l-flex__auto l-flex--row center"
+        description="暂无设备"
+      />
+    </div>
+    <div
+      v-if="!deviceOptions.loaded"
+      class="c-sibling-item--v far u-text--center"
+    >
+      <i class="el-icon-loading" />
+    </div>
     <div
       ref="deviceContainer"
-      class="l-flex__auto l-grid--info c-sibling-item--v far u-overflow-y--auto"
+      class="l-flex__auto l-grid--info c-sibling-item--v u-overflow-y--auto"
     >
       <device
         v-for="item in deviceOptions.list"
@@ -63,12 +105,6 @@
         :flag="item.flag"
       />
     </div>
-    <div
-      v-if="!deviceOptions.loaded"
-      class="c-sibling-item--v far u-text--center"
-    >
-      <i class="el-icon-loading" />
-    </div>
     <department-drawer
       ref="departmentDrawer"
       remember
@@ -103,6 +139,7 @@ export default {
         loaded: false
       },
       loading: false,
+      active: 'all',
       group: {}
     }
   },
@@ -116,19 +153,26 @@ export default {
   },
   beforeDestroy () {
     ScreenshotCache.clear()
-    clearTimeout(this.$timer)
+    this.onResetOptions()
     this.monitor = { loading: true }
     unsubscribe([
       '+/+/online',
       '+/+/offline',
       '+/+/calendar/update'
     ], this.onMessage)
-    if (this.$observer) {
-      this.$observer.disconnect()
-      this.$observer = null
-    }
   },
   methods: {
+    onResetOptions () {
+      clearTimeout(this.$timer)
+      this.$observer?.disconnect()
+      this.deviceOptions.ignore = true
+    },
+    onChange (type) {
+      if (this.active !== type) {
+        this.active = type
+        this.getDeviesByMonitor()
+      }
+    },
     observerDom (el) {
       if (!this.$observer) {
         this.$observer = new IntersectionObserver(entries => {
@@ -160,7 +204,11 @@ export default {
       this.$observer.observe(el)
     },
     onMessage (topic) {
-      if (!this.deviceOptions.loaded) {
+      if (this.monitor.loading || !this.deviceOptions.loaded) {
+        return
+      }
+      if (!this.deviceOptions.list.length) {
+        this.refreshDevices()
         return
       }
       const result = /^\d+\/(\d+)\/(online|offline|calendar\/update)$/.exec(topic)
@@ -176,10 +224,9 @@ export default {
             device.flag = -Date.now()
             break
           default:
-            if (topicKey === (device.onlineStatus === 1 ? 'online' : 'offline')) {
-              return
+            if (topicKey !== (device.onlineStatus === 1 ? 'online' : 'offline')) {
+              this.refreshDevices()
             }
-            this.refreshDevices()
             break
         }
       }
@@ -213,20 +260,17 @@ export default {
         inactive: '-'
       }
       this.monitor = monitor
-      clearTimeout(this.$timer)
-      this.deviceOptions = { loaded: false }
-      this.$observer?.disconnect()
+      this.onResetOptions()
+      this.deviceOptions = { list: [], loaded: false }
       getDeviceStatisticsByPath(this.group.path).then(({ data }) => {
         const { deactivatedTotal, notConnectedTotal, offLineTotal, onLineTotal, total } = data
         monitor.total = total
         monitor.online = onLineTotal
-        monitor.offline = offLineTotal + notConnectedTotal
-        monitor.inactive = deactivatedTotal
+        monitor.offline = offLineTotal
+        monitor.inactive = deactivatedTotal + notConnectedTotal
       }).finally(() => {
         monitor.loading = false
-        if (!this.monitor.loading) {
-          this.getDevices(this.monitor.total - this.monitor.inactive)
-        }
+        this.getDeviesByMonitor()
       })
     },
     sort (a, b) {
@@ -235,34 +279,48 @@ export default {
       }
       return a.onlineStatus === 1 ? -1 : 1
     },
-    getDevices (total) {
-      if (!total || total === '-') {
-        this.deviceOptions = { list: [], loaded: true }
+    getDeviesByMonitor () {
+      this.onResetOptions()
+      if (this.monitor.loading) {
         return
       }
-      const options = { list: [], loaded: false, power: [] }
-      this.deviceOptions = options
-      getDevicesByQuery({
+      const query = {
         pageNum: 1,
-        pageSize: total,
         activate: 1,
         org: this.group.path
-      }, { custom: true }).then(
+      }
+      const { total, online, offline, inactive } = this.monitor
+      if (this.active === 'online') {
+        query.pageSize = online
+        query.onlineStatus = 1
+      } else if (this.active === 'offline') {
+        query.pageSize = offline
+        query.onlineStatus = 2
+      } else {
+        query.pageSize = total - inactive
+      }
+      if (query.pageSize === 0) {
+        this.deviceOptions = { list: [], loaded: true }
+        return
+      }
+      const options = { list: [], loaded: false }
+      this.deviceOptions = options
+      getDevicesByQuery(query, { custom: true }).then(
         ({ data }) => {
-          const map = {}
-          options.list = data.sort(this.sort).map(device => {
-            device.flag = 0
-            map[device.id] = device
-            return device
-          })
-          options.map = map
-          options.loaded = true
+          if (!options.ignore) {
+            const map = {}
+            options.list = data.sort(this.sort).map(device => {
+              device.flag = 0
+              map[device.id] = device
+              return device
+            })
+            options.map = map
+            options.loaded = true
+          }
         },
         ({ isCancel }) => {
-          if (!isCancel && !this.monitor.loading) {
-            this.$timer = setTimeout(total => {
-              this.getDevices(total)
-            }, 2000, total)
+          if (!isCancel && !options.ignore && !this.monitor.loading) {
+            this.$timer = setTimeout(this.getDeviesByMonitor, 2000)
           }
         }
       )
@@ -281,5 +339,13 @@ export default {
   &__item > div:first-child {
     margin-bottom: 10px;
   }
+
+  &__current {
+    position: absolute;
+    top: 50%;
+    left: 100%;
+    font-size: $font-size--md;
+    transform: translate(0, -50%);
+  }
 }
 </style>

+ 211 - 48
src/views/dashboard/TenantDashboard.vue

@@ -5,7 +5,7 @@
   >
     <div class="l-flex__none l-flex--row c-sibling-item--v c-count">
       <div
-        class="l-flex__none u-color--black u-width--sm u-bold u-ellipsis has-active"
+        class="l-flex__none u-width--sm u-color--blue u-bold u-ellipsis has-active"
         @click="onChooseDepartment"
       >
         <i
@@ -14,24 +14,51 @@
         />
         {{ group.name }}
       </div>
-      <div class="l-flex__none c-count__item u-color--black u-bold u-text--center">
-        <div>总数</div>
+      <div
+        class="l-flex__none c-count__item u-color--black u-bold u-text--center u-pointer"
+        @click="onChange('all')"
+      >
+        <div class="u-relative">
+          总数
+          <i
+            v-if="isAllDevice && active === 'all'"
+            class="c-count__current el-icon-caret-left"
+          />
+        </div>
         <i
           v-if="monitor.loading"
           class="el-icon-loading"
         />
         <div v-else>{{ monitor.total }}</div>
       </div>
-      <div class="l-flex__none c-count__item u-color--success dark u-bold u-text--center">
-        <div>● 在线</div>
+      <div
+        class="l-flex__none c-count__item u-color--success dark u-bold u-text--center u-pointer"
+        @click="onChange('online')"
+      >
+        <div class="u-relative">
+          ● 在线
+          <i
+            v-if="isAllDevice && active === 'online'"
+            class="c-count__current el-icon-caret-left"
+          />
+        </div>
         <i
           v-if="monitor.loading"
           class="el-icon-loading"
         />
         <div v-else>{{ monitor.online }}</div>
       </div>
-      <div class="l-flex__none c-count__item u-color--error dark u-bold u-text--center">
-        <div>● 离线</div>
+      <div
+        class="l-flex__none c-count__item u-color--error dark u-bold u-text--center u-pointer"
+        @click="onChange('offline')"
+      >
+        <div class="u-relative">
+          ● 离线
+          <i
+            v-if="isAllDevice && active === 'offline'"
+            class="c-count__current el-icon-caret-left"
+          />
+        </div>
         <i
           v-if="monitor.loading"
           class="el-icon-loading"
@@ -39,7 +66,7 @@
         <div v-else>{{ monitor.offline }}</div>
       </div>
       <div class="l-flex__none c-count__item u-color--info u-bold u-text--center">
-        <div>● 未启用</div>
+        <div>● 未接入</div>
         <i
           v-if="monitor.loading"
           class="el-icon-loading"
@@ -51,12 +78,29 @@
         @click="onRefresh"
       />
     </div>
-    <div
-      class="l-flex__none l-flex--row inline c-sibling-item--v far u-font-size--sm u-bold has-active"
-      @click="onAttention"
-    >
-      <span class="c-sibling-item">我的关注</span>
-      <i class="c-sibling-item near el-icon-circle-plus-outline" />
+    <div class="l-flex__none l-flex--row c-sibling-item--v far u-font-size--sm u-bold">
+      <div v-if="isAllDevice">设备列表</div>
+      <div
+        v-else
+        class="l-flex--row inline has-active"
+        @click="onAttention"
+      >
+        <span class="c-sibling-item">我的关注</span>
+        <i class="c-sibling-item near el-icon-circle-plus-outline" />
+      </div>
+      <div class="l-flex__fill" />
+      <el-dropdown
+        v-if="isTenantAdmin"
+        class="l-flex__none has-active"
+        trigger="click"
+        @command="onCommand"
+      >
+        <i class="el-icon-s-operation u-font-size--md" />
+        <el-dropdown-menu slot="dropdown">
+          <el-dropdown-item command="all">设备列表</el-dropdown-item>
+          <el-dropdown-item command="attention">我的关注</el-dropdown-item>
+        </el-dropdown-menu>
+      </el-dropdown>
     </div>
     <div
       v-if="deviceOptions.loaded && !deviceOptions.list.length"
@@ -64,9 +108,15 @@
     >
       <el-empty
         class="l-flex__auto l-flex--row center"
-        description="暂无关注设备"
+        description="暂无设备"
       />
     </div>
+    <div
+      v-if="!deviceOptions.loaded"
+      class="c-sibling-item--v far u-text--center"
+    >
+      <i class="el-icon-loading" />
+    </div>
     <div
       ref="deviceContainer"
       class="l-flex__auto l-grid--info c-sibling-item--v u-overflow-y--auto"
@@ -77,15 +127,8 @@
         :device="item"
         :observer="observerDom"
         :flag="item.flag"
-        :status="item.status"
       />
     </div>
-    <div
-      v-if="!deviceOptions.loaded"
-      class="c-sibling-item--v far u-text--center"
-    >
-      <i class="el-icon-loading" />
-    </div>
     <department-drawer
       ref="departmentDrawer"
       remember
@@ -96,12 +139,14 @@
 </template>
 
 <script>
+import { mapGetters } from 'vuex'
 import {
   subscribe,
   unsubscribe
 } from '@/utils/mqtt'
 import { ScreenshotCache } from '@/utils/cache'
 import {
+  getDevicesByQuery,
   getDeviceAttentionList,
   getDeviceStatisticsByPath
 } from '@/api/device'
@@ -120,9 +165,17 @@ export default {
         loaded: false
       },
       loading: false,
+      command: 'all',
+      active: 'all',
       group: {}
     }
   },
+  computed: {
+    ...mapGetters(['isTenantAdmin']),
+    isAllDevice () {
+      return this.command === 'all'
+    }
+  },
   created () {
     this.$timer = -1
     subscribe([
@@ -130,23 +183,49 @@ export default {
       '+/+/offline',
       '+/+/calendar/update'
     ], this.onMessage)
-    this.getDevices()
   },
   beforeDestroy () {
     ScreenshotCache.clear()
-    clearTimeout(this.$timer)
+    this.onResetOptions()
     this.monitor = { loading: true }
     unsubscribe([
       '+/+/online',
       '+/+/offline',
       '+/+/calendar/update'
     ], this.onMessage)
-    if (this.$observer) {
-      this.$observer.disconnect()
-      this.$observer = null
-    }
   },
   methods: {
+    onResetOptions () {
+      clearTimeout(this.$timer)
+      this.$observer?.disconnect()
+      this.deviceOptions.ignore = true
+    },
+    onCommand (command) {
+      if (this.command !== command) {
+        this.command = command
+        if (this.isAllDevice) {
+          if (this.monitor.loading) {
+            this.onResetOptions()
+            this.deviceOptions = { list: [], loaded: false }
+          } else {
+            this.getDeviesByMonitor()
+          }
+        } else {
+          this.getDevicesByAttention()
+        }
+      }
+    },
+    onChange (type) {
+      if (this.active !== type) {
+        this.active = type
+        if (this.isAllDevice) {
+          this.getDeviesByMonitor()
+        }
+      }
+      if (!this.isAllDevice) {
+        this.onCommand('all')
+      }
+    },
     observerDom (el) {
       if (!this.$observer) {
         this.$observer = new IntersectionObserver(entries => {
@@ -178,13 +257,22 @@ export default {
       this.$observer.observe(el)
     },
     onMessage (topic) {
+      if (this.isAllDevice) {
+        if (this.monitor.loading || !this.deviceOptions.loaded) {
+          return
+        }
+        if (!this.deviceOptions.list.length) {
+          this.refreshDevices()
+          return
+        }
+      }
       const result = /^\d+\/(\d+)\/(online|offline|calendar\/update)$/.exec(topic)
       if (!result) {
         return
       }
       const deviceId = result[1]
-      const status = result[2]
-      if (status === 'online' || status === 'offline') {
+      const topicKey = result[2]
+      if (!this.isAllDevice && (topicKey === 'online' || topicKey === 'offline')) {
         this.refreshDevices()
       }
       if (!this.deviceOptions.loaded) {
@@ -192,12 +280,18 @@ export default {
       }
       const device = this.deviceOptions.map?.[deviceId]
       if (device) {
-        switch (status) {
+        switch (topicKey) {
           case 'calendar/update':
             device.flag = -Date.now()
             break
           default:
-            device.onlineStatus = status === 'online' ? 1 : 2
+            if (topicKey !== (device.onlineStatus === 1 ? 'online' : 'offline')) {
+              if (this.isAllDevice) {
+                this.refreshDevices()
+              } else {
+                device.onlineStatus = topicKey === 'online' ? 1 : 2
+              }
+            }
             break
         }
       }
@@ -231,34 +325,95 @@ export default {
         inactive: '-'
       }
       this.monitor = monitor
+      if (this.isAllDevice) {
+        this.onResetOptions()
+        this.deviceOptions = { list: [], loaded: false }
+      }
       getDeviceStatisticsByPath(this.group.path).then(({ data }) => {
         const { deactivatedTotal, notConnectedTotal, offLineTotal, onLineTotal, total } = data
         monitor.total = total
         monitor.online = onLineTotal
-        monitor.offline = offLineTotal + notConnectedTotal
-        monitor.inactive = deactivatedTotal
+        monitor.offline = offLineTotal
+        monitor.inactive = deactivatedTotal + notConnectedTotal
       }).finally(() => {
         monitor.loading = false
+        if (this.isAllDevice) {
+          this.getDeviesByMonitor()
+        }
       })
     },
-    getDevices () {
-      this.$observer?.disconnect()
-      const options = { list: [], loaded: false, power: [] }
+    sort (a, b) {
+      if (a.onlineStatus === b.onlineStatus) {
+        return a.createTime <= b.createTime ? 1 : -1
+      }
+      return a.onlineStatus === 1 ? -1 : 1
+    },
+    getDeviesByMonitor () {
+      this.onResetOptions()
+      if (this.monitor.loading) {
+        return
+      }
+      const query = {
+        pageNum: 1,
+        activate: 1,
+        org: this.group.path
+      }
+      const { total, online, offline, inactive } = this.monitor
+      if (this.active === 'online') {
+        query.pageSize = online
+        query.onlineStatus = 1
+      } else if (this.active === 'offline') {
+        query.pageSize = offline
+        query.onlineStatus = 2
+      } else {
+        query.pageSize = total - inactive
+      }
+      if (query.pageSize === 0) {
+        this.deviceOptions = { list: [], loaded: true }
+        return
+      }
+      const options = { list: [], loaded: false }
       this.deviceOptions = options
-      getDeviceAttentionList().then(
+      getDevicesByQuery(query, { custom: true }).then(
         ({ data }) => {
-          const map = {}
-          options.list = data.map(device => {
-            device.flag = 0
-            map[device.id] = device
-            return device
-          })
-          options.map = map
-          options.loaded = true
+          if (!options.ignore) {
+            const map = {}
+            options.list = data.sort(this.sort).map(device => {
+              device.flag = 0
+              map[device.id] = device
+              return device
+            })
+            options.map = map
+            options.loaded = true
+          }
+        },
+        ({ isCancel }) => {
+          if (!isCancel && !options.ignore && this.isAllDevice && !this.monitor.loading) {
+            this.$timer = setTimeout(this.getDeviesByMonitor, 2000)
+          }
+        }
+      )
+    },
+    getDevicesByAttention () {
+      this.onResetOptions()
+      const options = { list: [], loaded: false }
+      this.deviceOptions = options
+      getDeviceAttentionList({ custom: true }).then(
+        ({ data }) => {
+          if (!options.ignore) {
+            const map = {}
+            options.list = data.map(device => {
+              device.flag = 0
+              map[device.id] = device
+              return device
+            })
+            options.map = map
+            options.loaded = true
+          }
         },
         ({ isCancel }) => {
-          if (!isCancel) {
-            this.$timer = setTimeout(this.getDevices, 2000)
+          if (!isCancel && !options.ignore && !this.isAllDevice) {
+            this.$timer = setTimeout(this.getDevicesByAttention, 2000)
           }
         }
       )
@@ -282,5 +437,13 @@ export default {
   &__item > div:first-child {
     margin-bottom: 10px;
   }
+
+  &__current {
+    position: absolute;
+    top: 50%;
+    left: 100%;
+    font-size: $font-size--md;
+    transform: translate(0, -50%);
+  }
 }
 </style>

+ 7 - 17
src/views/dashboard/map/index.vue

@@ -7,7 +7,7 @@
     <div class="l-flex__fill l-flex--col c-sibling-item c-device-map">
       <div class="l-flex__none l-flex--row c-count">
         <div
-          class="l-flex__none c-count__title u-color--black u-bold has-active u-ellipsis"
+          class="l-flex__none c-count__title u-color--blue u-bold u-ellipsis has-active"
           @click="onChooseDepartment"
         >
           <i
@@ -41,7 +41,7 @@
           <div v-else>{{ monitor.offline }}</div>
         </div>
         <div class="l-flex__none c-count__item u-color--info u-bold u-text--center">
-          <div>● 未启用</div>
+          <div>● 未接入</div>
           <i
             v-if="monitor.loading"
             class="el-icon-loading"
@@ -73,18 +73,6 @@
         />
       </div>
     </div>
-    <!-- <div
-      ref="devicelist"
-      v-loading="!deviceOptions.loaded"
-      class="l-flex__none l-flex--col c-sibling-item u-width--lg u-overflow-y--auto"
-    >
-      <device
-        v-for="item in deviceOptions.list"
-        :key="item.id"
-        class="c-sibling-item--v"
-        :device="item"
-      />
-    </div> -->
     <department-drawer
       ref="departmentDrawer"
       remember
@@ -143,6 +131,7 @@ export default {
   beforeDestroy () {
     ScreenshotCache.clear()
     clearTimeout(this.$timer)
+    this.deviceOptions.ignore = true
     this.monitor = { loading: true }
     unsubscribe([
       '+/+/online',
@@ -210,13 +199,14 @@ export default {
       this.map = null
       this.monitor = monitor
       clearTimeout(this.$timer)
+      this.deviceOptions.ignore = true
       this.deviceOptions = { loaded: false }
       getDeviceStatisticsByPath(this.group.path).then(({ data }) => {
         const { deactivatedTotal, notConnectedTotal, offLineTotal, onLineTotal, total } = data
         monitor.total = total
         monitor.online = onLineTotal
-        monitor.offline = offLineTotal + notConnectedTotal
-        monitor.inactive = deactivatedTotal
+        monitor.offline = offLineTotal
+        monitor.inactive = deactivatedTotal + notConnectedTotal
       }).finally(() => {
         monitor.loading = false
         if (!this.monitor.loading) {
@@ -255,7 +245,7 @@ export default {
           this.initMap()
         },
         ({ isCancel }) => {
-          if (!isCancel && !this.monitor.loading) {
+          if (!isCancel && !options.ignore && !this.monitor.loading) {
             this.$timer = setTimeout(total => {
               this.getDevices(total)
             }, 2000, total)