Przeglądaj źródła

feat(dashboard): simple device card

Casper Dai 2 lat temu
rodzic
commit
4b06f7f769

+ 2 - 3
src/views/dashboard/components/DeviceCard.vue

@@ -174,8 +174,7 @@ export default {
       switchStatus: Power.LOADING,
       hasPower: true,
       hasPowerRealStatus: false,
-      volume: -1,
-      editVolume: 0
+      volume: -1
     }
   },
   computed: {
@@ -559,7 +558,7 @@ export default {
     position: relative;
     left: $padding--lg;
     padding: $padding--2xs $padding--sm $padding--2xs $padding;
-    margin-left: -$spacing--3xs;
+    margin-left: -$spacing--xs;
     border-radius: $radius--sm 0 0 $radius--sm;
     background-color: currentColor;
   }

+ 252 - 0
src/views/dashboard/components/DeviceCardSimple.vue

@@ -0,0 +1,252 @@
+<template>
+  <div
+    class="o-device u-pointer"
+    :data-id="device.id"
+    @click="onClick"
+  >
+    <div class="l-flex__none l-flex--row c-sibling-item--v o-device__block u-font-size u-bold">
+      <auto-text
+        class="l-flex__fill c-sibling-item"
+        :text="name"
+      />
+      <template v-if="hasStatus">
+        <el-tooltip
+          v-if="isOnline && hasPower"
+          placement="top"
+        >
+          <template #content>{{ powerStatusTip }}</template>
+          <i
+            class="l-flex__none c-sibling-item near o-device__status"
+            :class="switchStatusClass"
+            @click.stop
+          />
+        </el-tooltip>
+        <el-tooltip placement="top">
+          <template #content>{{ statusInfoTip }}</template>
+          <div
+            class="l-flex__none o-device__tip u-font-size--xs"
+            :class="statusClass"
+          >
+            <span class="u-color--white">{{ statusTip }}</span>
+          </div>
+        </el-tooltip>
+      </template>
+      <i
+        v-else
+        class="l-flex__none c-sibling-item near el-icon-loading"
+      />
+    </div>
+    <div class="l-flex__none l-flex--row c-sibling-item--v nearer o-device__block u-relative u-color--blue">
+      <i class="l-flex__none c-sibling-item el-icon-location-outline u-font-size" />
+      <auto-text
+        class="l-flex__auto c-sibling-item nearest u-font-size--xs u-bold"
+        :text="address"
+      />
+      <div
+        v-if="isOnline && volume > -1"
+        class="l-flex__none o-device__volume u-color--white u-font-size--sm has-active"
+        @click.stop="onVolume"
+      >
+        <template v-if="volume === 0">
+          <svg-icon icon-class="mute" />
+        </template>
+        <template v-else>
+          <svg-icon
+            class="c-sibling-item"
+            icon-class="volume"
+          />
+          <span class="c-sibling-item nearest">{{ volume }}%</span>
+        </template>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { ThirdPartyDevice } from '@/constant'
+import { parseTime } from '@/utils'
+import {
+  Status,
+  Power,
+  addListener,
+  removeListener
+} from '@/utils/adapter'
+
+export default {
+  name: 'DeviceCardSimple',
+  props: {
+    device: {
+      type: Object,
+      required: true
+    }
+  },
+  data () {
+    return {
+      timestamp: '',
+      powerStatus: Status.LOADING,
+      switchStatus: Power.LOADING,
+      hasPower: true,
+      hasPowerRealStatus: false,
+      volume: -1
+    }
+  },
+  computed: {
+    name () {
+      return this.device.name
+    },
+    address () {
+      return this.device.address
+    },
+    powerStatusTip () {
+      return this.hasPower
+        ? this.powerStatus === Status.WARNING
+          ? `电源状态异常,${this.switchStatus === Power.LOADING ? '检测' : '最后上报'}时间 ${this.timestamp}`
+          : this.isPowerOpened
+            ? '屏幕已开启'
+            : '屏幕未开启'
+        : ''
+    },
+    isOnline () {
+      return this.device.onlineStatus === 1
+    },
+    hasStatus () {
+      return !this.isOnline || !this.hasPower || this.hasPowerRealStatus
+    },
+    isPowerOpened () {
+      return !this.hasPower || this.hasPowerRealStatus && (this.powerStatus === Status.OK && this.switchStatus !== Power.OFF)
+    },
+    isRealOnline () {
+      return this.hasStatus && this.isOnline && this.isPowerOpened
+    },
+    isRealOffline () {
+      return this.hasStatus && !this.isRealOnline
+    },
+    switchStatusClass () {
+      if (this.powerStatus === Status.WARNING) {
+        return 'el-icon-warning u-color--warning u-font-size--2xl'
+      }
+      return this.switchStatus === Power.ON ? 'on' : this.switchStatus === Power.OFF ? 'off' : 'other'
+    },
+    statusClass () {
+      return this.isOnline ? 'u-color--success dark' : 'u-color--error dark'
+    },
+    statusTip () {
+      return this.isOnline ? '在线' : '离线'
+    },
+    statusInfoTip () {
+      return this.device.lastOnline
+        ? this.isOnline
+          ? `${this.device.lastOnline} 上线`
+          : `${this.device.lastOnline} 离线`
+        : this.isOnline
+          ? '播控器正常运行中'
+          : '当前播控器离线了'
+    }
+  },
+  watch: {
+    isOnline: {
+      handler (val, old) {
+        if (val) {
+          addListener(this.device.id, this.onMessage)
+        } else {
+          if (old == null) {
+            return
+          }
+          removeListener(this.device.id, this.onMessage)
+        }
+      },
+      immediate: true
+    }
+  },
+  beforeDestroy () {
+    if (this.isOnline) {
+      removeListener(this.device.id, this.onMessage)
+    }
+  },
+  methods: {
+    onMessage (value) {
+      if (value.screen) {
+        this.volume = value.screen.volume
+      }
+      const multiCard = value[ThirdPartyDevice.MULTI_FUNCTION_CARD]
+      const powerStatus = multiCard.status
+      this.powerStatus = powerStatus
+      this.timestamp = multiCard.timestamp ? parseTime(multiCard.timestamp, '{y}-{m}-{d} {h}:{i}:{s}') : ''
+      this.hasPower = powerStatus > Status.NONE
+      this.hasPowerRealStatus = powerStatus !== Status.LOADING
+      this.switchStatus = multiCard.switchStatus
+    },
+    onClick () {
+      this.$router.push({
+        name: 'device-detail',
+        params: { id: this.device.id }
+      })
+    },
+    onVolume () {
+      const { id, productId, name } = this.device
+      this.$emit('volume', {
+        value: this.volume,
+        device: { id, productId, name }
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.o-device {
+  display: inline-flex;
+  flex-direction: column;
+  padding: $padding--md $padding--lg;
+  color: $black;
+  line-height: 1;
+  border-radius: $radius;
+  background-color: #fff;
+  box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.1), 0 2px 6px 0 rgba(0, 0, 0, 0.1);
+
+  &__block {
+    height: 24px;
+  }
+
+  &__status {
+    display: inline-flex;
+    justify-content: center;
+    align-items: center;
+    width: 24px;
+    height: 24px;
+
+    &.on {
+      background: url("~@/assets/icon_on.svg") 0 0 / 100% 100% no-repeat;
+    }
+
+    &.off {
+      background: url("~@/assets/icon_off.svg") 0 0 / 100% 100% no-repeat;
+    }
+
+    &.other {
+      width: 54px;
+      background: url("~@/assets/icon_on_2.svg") 0 0 / 100% 100% no-repeat;
+    }
+  }
+
+  &__tip {
+    display: inline-block;
+    position: relative;
+    left: $padding--lg;
+    padding: $padding--2xs $padding--sm $padding--2xs $padding;
+    margin-left: -$spacing--xs;
+    border-radius: $radius--sm 0 0 $radius--sm;
+    background-color: currentColor;
+  }
+
+  &__volume {
+    display: inline-block;
+    position: relative;
+    left: $padding--lg;
+    padding: $padding--2xs;
+    margin-left: -$spacing--xs;
+    border-radius: $radius--sm 0 0 $radius--sm;
+    background-color: $gray--dark;
+  }
+}
+</style>

+ 2 - 1
src/views/dashboard/components/DeviceGroupAttention.vue

@@ -4,7 +4,8 @@
     :class="{ 'l-grid--info': hasData }"
   >
     <template v-if="hasData">
-      <device-card
+      <component
+        :is="cardComponent"
         v-for="item in filterList"
         :key="item.id"
         :device="item"

+ 2 - 1
src/views/dashboard/components/DeviceGroupLevelItem.vue

@@ -2,7 +2,8 @@
   <div v-if="hasData">
     <div class="c-sibling-item--v u-color--black u-font-size--sm u-bold">{{ group.name }}</div>
     <div class="c-sibling-item--v near l-grid--info">
-      <device-card
+      <component
+        :is="cardComponent"
         v-for="device in filterList"
         :key="device.id"
         :device="device"

+ 2 - 1
src/views/dashboard/components/DeviceGroupTile.vue

@@ -4,7 +4,8 @@
     :class="{ 'l-grid--info': hasData }"
   >
     <template v-if="hasData">
-      <device-card
+      <component
+        :is="cardComponent"
         v-for="item in filterList"
         :key="item.id"
         :device="item"

+ 0 - 6
src/views/dashboard/components/DeviceGroupTree.vue

@@ -14,11 +14,6 @@ export default {
       required: true
     }
   },
-  data () {
-    return {
-      defaultExpand: false
-    }
-  },
   watch: {
     groups: {
       handler () {
@@ -31,7 +26,6 @@ export default {
     init () {
       const rootOption = this.createNode()
       this.setNodes(rootOption, this.groups.map(item => this.transfromGroup(item, rootOption)))
-      this.defaultExpand = rootOption.children.length <= 1
       this.rootOption = rootOption
     },
     transfromGroup ({ id, name, children }, parent) {

+ 19 - 1
src/views/dashboard/components/DeviceGroups.vue

@@ -46,10 +46,18 @@
         />
       </div>
       <slot />
+      <div class="l-flex__fill" />
+      <div
+        class="l-flex__none l-flex--row u-color--blue u-font-size--sm has-active"
+        @click="onSwitchCardStyle"
+      >
+        {{ tip }}
+      </div>
     </div>
     <component
       :is="activeComponent"
       class="l-flex__self has-padding--v u-overflow-y--auto"
+      :card-style="cardStyle"
       v-bind="$attrs"
       @change="onChange"
     />
@@ -75,7 +83,8 @@ export default {
   data () {
     return {
       active: 'tile',
-      groups: []
+      groups: [],
+      cardStyle: 'big'
     }
   },
   computed: {
@@ -110,6 +119,12 @@ export default {
     },
     hasData () {
       return this.groups.some(({ children }) => children.some(({ onlineStatus }) => onlineStatus === 1))
+    },
+    tip () {
+      if (this.cardStyle === 'big') {
+        return '切换至简洁模式'
+      }
+      return '切换至详情模式'
     }
   },
   methods: {
@@ -121,6 +136,9 @@ export default {
     },
     onChange (groups) {
       this.groups = groups
+    },
+    onSwitchCardStyle () {
+      this.cardStyle = this.cardStyle === 'big' ? 'medium' : 'big'
     }
   }
 }

+ 1 - 0
src/views/dashboard/components/DrawerVolumeSettings.vue

@@ -39,6 +39,7 @@
         :groups="groups"
         checkbox
         check-on-click-node
+        default-expand
         @change="onChange"
       />
     </div>

+ 14 - 0
src/views/dashboard/components/mixins/group-list.js

@@ -1,4 +1,5 @@
 import DeviceCard from '../DeviceCard.vue'
+import DeviceCardSimple from '../DeviceCardSimple.vue'
 import VolumeDialog from '../VolumeDialog.vue'
 
 export default {
@@ -6,13 +7,26 @@ export default {
     status: {
       type: String,
       default: ''
+    },
+    cardStyle: {
+      type: String,
+      default: 'big'
     }
   },
   components: {
     DeviceCard,
+    DeviceCardSimple,
     VolumeDialog
   },
   computed: {
+    cardComponent () {
+      switch (this.cardStyle) {
+        case 'medium':
+          return 'DeviceCardSimple'
+        default:
+          return 'DeviceCard'
+      }
+    },
     groupItems () {
       return []
     },

+ 3 - 0
src/views/device/detail/components/DeviceRuntime/OnlineDuration.vue

@@ -121,6 +121,9 @@ export default {
   },
   computed: {
     amountList () {
+      if (!this.amounts) {
+        return []
+      }
       if (this.power) {
         return this.amounts
       }