Kaynağa Gözat

refactor: linkState

Casper Dai 3 yıl önce
ebeveyn
işleme
ac1005f053

+ 0 - 9
src/api/device.js

@@ -410,12 +410,3 @@ export function deactivateTask ({ taskId }) {
     data: [taskId]
   })
 }
-export function getDeviceBind ({ id }) {
-  return request({
-    url: `/device/bind/${id}`,
-    method: 'GET',
-    params: {
-      chain: true
-    }
-  })
-}

+ 3 - 2
src/api/external.js

@@ -45,10 +45,11 @@ export function getThirdPartyDevices (query) {
   })
 }
 
-export function getBoundThirdPartyDevices (deviceId) {
+export function getBoundThirdPartyDevices (deviceId, chain = false) {
   return request({
     url: `/device/bind/${deviceId}`,
-    method: 'GET'
+    method: 'GET',
+    params: { chain }
   })
 }
 

BIN
src/assets/linkState/led_default.jpg


+ 5 - 0
src/scss/bem/_utility.scss

@@ -17,6 +17,11 @@
   text-overflow: ellipsis;
 }
 
+.u-overflow-x--auto {
+  overflow-x: auto;
+  overflow-y: hidden;
+}
+
 .u-overflow-y--auto {
   overflow-x: hidden;
   overflow-y: auto;

+ 2 - 1
src/utils/cache/screenshot.js

@@ -49,6 +49,7 @@ export function screenshot (deviceId, silence) {
   const inst = cache.get(deviceId)
   if (inst) {
     inst.waiting = true
+    inst.timestamp = Date.now()
     inst.base64 = null
     publish(`${inst.productId}/${inst.deviceId}/screenshot/ask`, JSON.stringify({ timestamp: inst.timestamp })).then(
       () => {
@@ -100,8 +101,8 @@ function onMessage (topic, message) {
     if (inst) {
       clearTimeout(inst.timer)
       inst.waiting = false
-      inst.base64 = `data:image/jpeg;base64,${message.replace(/\s/g, '')}`
       inst.timestamp = Date.now()
+      inst.base64 = `data:image/jpeg;base64,${message.replace(/\s/g, '')}`
       emit(inst)
     }
   }

+ 2 - 0
src/views/device/detail/components/DeviceRuntime/Running.vue

@@ -47,6 +47,8 @@ export default {
   },
   created () {
     addListener('status', this.onUpdate)
+  },
+  activated () {
     if (this.online && !this.asking) {
       this.ask()
     }

+ 2 - 2
src/views/device/detail/components/DeviceRuntime/ScreenShot.vue

@@ -37,10 +37,10 @@ export default {
       styles: null
     }
   },
-  activated () {
+  created () {
     ScreenshotCache.watch(this.device, this.onScreenshotUpdate, 10000)
   },
-  created () {
+  activated () {
     ScreenshotCache.watch(this.device, this.onScreenshotUpdate, 10000)
   },
   beforeDestroy () {

+ 11 - 2
src/views/device/detail/components/DeviceRuntime/index.vue

@@ -1,7 +1,10 @@
 <template>
   <div class="l-grid--info medium">
-    <running v-bind="$attrs" />
-    <template v-if="$attrs.online">
+    <running
+      :online="online"
+      v-bind="$attrs"
+    />
+    <template v-if="online">
       <screen-shot v-bind="$attrs" />
       <download />
     </template>
@@ -19,6 +22,12 @@ export default {
     Running,
     ScreenShot,
     Download
+  },
+  props: {
+    online: {
+      type: [Boolean, String],
+      default: false
+    }
   }
 }
 </script>

+ 293 - 173
src/views/device/detail/components/LinkState.vue

@@ -1,53 +1,59 @@
 <template>
-  <div class="l-flex--row center c-info">
-    <div
-      v-if="loaded"
-      class="linkState"
-    >
+  <div v-loading="!loaded && loading">
+    <template v-if="loaded || !loading">
+      <warning
+        v-if="!loaded && !loading"
+        @click="getBoundThirdPartyDevices"
+      />
       <div
-        v-for="item in items"
-        :key="item.key"
-        :class="['co', item.key]"
-        :style="getImg(item.key)"
+        v-else
+        class="l-flex__auto u-overflow-x--auto"
       >
-        <div
-          v-if="Array.isArray(item.label)"
-          class="ctext"
-        >
-          {{ item.label[0] }}<br>{{ item.label[1] }}
-        </div>
-        <div
-          v-else
-          class="ctext"
-        >
-          {{ item.label }}
+        <div class="c-link-state">
+          <div
+            v-for="item in items"
+            :key="item.key"
+            class="o-link-device has-bg"
+            v-bind="getAttrs(item.key)"
+          >
+            <div class="o-link-device__name u-bold">{{ item.label }}</div>
+          </div>
+          <div
+            v-for="line in lines"
+            :key="line.key"
+            class="o-line"
+            :class="line.className"
+          />
         </div>
       </div>
-      <div
-        v-for="line in lines"
-        :key="line.key"
-        :class="[
-          'line',
-          line.class,
-          {
-            closed: lineToItem[line.key] && linkStateForm[lineToItem[line.key]] !== 0,
-            trafficCameraUnbound: line.key === 5 && linkStateForm.trafficCamera === 2,
-          }
-        ]"
-      />
-    </div>
+    </template>
   </div>
 </template>
 
 <script>
-import { getDeviceBind } from '@/api/device'
+import { getBoundThirdPartyDevices } from '@/api/external'
+import { ThirdPartyDevice } from '@/constant'
 import { ScreenshotCache } from '@/utils/cache'
+
+const KeyMap = {
+  [ThirdPartyDevice.GATEWAY]: 'gateway',
+  [ThirdPartyDevice.RECEIVING_CARD]: 'receive_card',
+  [ThirdPartyDevice.SENDING_CARD]: 'sending_device',
+  [ThirdPartyDevice.SCREEN]: 'led',
+  [ThirdPartyDevice.LED_CAMERA]: 'led_camera',
+  [ThirdPartyDevice.TRAFFIC_CAMERA]: 'traffic_camera'
+}
+
 export default {
   name: 'LinkState',
   props: {
     device: {
       type: Object,
       required: true
+    },
+    online: {
+      type: [Boolean, String],
+      default: false
     }
   },
   data () {
@@ -70,8 +76,12 @@ export default {
           key: 'sending_device'
         },
         {
-          label: ['人流量监测', '摄像头'],
-          key: 'trafficCamera'
+          label: '人流量监测摄像头',
+          key: 'traffic_camera'
+        },
+        {
+          label: 'LED屏监测摄像头',
+          key: 'led_camera'
         },
         {
           label: '接收卡',
@@ -82,116 +92,125 @@ export default {
           key: 'led'
         }
       ],
-      lines: Array.from({ length: 7 }, (v, index) => {
-        return {
-          key: index + 1,
-          class: `l${index + 1}`
-        }
-      }),
-      lineToItem: {
-        1: 'msr',
-        2: 'device',
-        3: 'sending_device',
-        4: 'receive_card',
-        5: 'msr',
-        6: 'msr',
-        7: 'gateway'
+      lineFromeTo: {
+        1: ['msr', 'device'],
+        2: ['device', 'sending_device'],
+        3: ['device', 'receive_card'],
+        4: ['receive_card', 'led'],
+        5: ['msr', 'gateway'],
+        6: ['msr', 'led_camera', 'traffic_camera'],
+        7: ['msr', 'traffic_camera'],
+        8: ['msr', 'led_camera'],
+        9: ['msr', 'led_camera'],
+        10: ['gateway', 'led']
       },
-      linkStateForm: {
-        // 0 开启 1 关闭 2未绑定
+      linkState: {
         msr: 0,
-        device: 2,
+        device: this.online ? 0 : 1,
+        led: this.online ? 0 : 1,
         gateway: 2,
         sending_device: 2,
-        trafficCamera: 2,
-        receive_card: 2,
-        led: 2
+        traffic_camera: 2,
+        led_camera: 2,
+        receive_card: 2
       },
+      loading: true,
       loaded: false,
       base64: null
     }
   },
-  // created () {
-  //   ScreenshotCache.watch(this.device, this.onScreenshotUpdate, 10000)
-  // },
-  activated () {
-    this.getDeviceBind()
-    ScreenshotCache.watch(this.device, this.onScreenshotUpdate, 60 * 60 * 1000)
+  computed: {
+    lines () {
+      const lineFromeTo = this.lineFromeTo
+      const state = this.linkState
+      return Object.keys(lineFromeTo).map(key => {
+        const from = lineFromeTo[key][0]
+        const to = lineFromeTo[key].slice(1)
+        return {
+          key: `line${key}`,
+          className: [`l${key}`, state[from] === 0 && to.some(key => state[key] === 0) ? 'linked' : ''].join(' ')
+        }
+      })
+    }
+  },
+  watch: {
+    online () {
+      this.init()
+    }
+  },
+  created () {
+    this.init()
+    this.$timer = setInterval(this.init, 10000)
   },
   beforeDestroy () {
-    ScreenshotCache.unwatch(this.device.id)
+    if (this.online) {
+      ScreenshotCache.unwatch(this.device.id)
+    }
+    clearInterval(this.$timer)
   },
   methods: {
+    init () {
+      if (this.online) {
+        ScreenshotCache.watch(this.device, this.onScreenshotUpdate, 10000)
+      } else {
+        this.base64 = null
+      }
+      this.getBoundThirdPartyDevices()
+    },
     onScreenshotUpdate ({ waiting, base64 }) {
-      // console.log('waiting', waiting)
-      // console.log('base64', base64)
-      this.base64 = !waiting && base64 ? base64 : null
+      if (!waiting) {
+        this.base64 = base64
+      }
     },
-    getDeviceBind () {
-      getDeviceBind(this.device)
-        .then(({ data, success }) => {
-          if (!success) { return }
-          const map = {
-            0: 'gateway',
-            1: 'receive_card',
-            2: 'sending_device',
-            // 3: 'led'
-            4: 'ledCamera',
-            5: 'trafficCamera'
-
-          }
+    getBoundThirdPartyDevices () {
+      this.loading = true
+      getBoundThirdPartyDevices(this.device.id, true)
+        .then(({ data }) => {
           const form = {
-            device: this.device.onlineStatus === 1 && this.device.activate === 2 ? 0 : 1,
+            msr: 0,
+            device: this.online ? 0 : 1,
+            led: this.online ? 0 : 1,
             gateway: 2,
             sending_device: 2,
-            trafficCamera: 2,
             receive_card: 2,
-            led: this.device.onlineStatus === 1 && this.device.activate === 2 ? 0 : 1,
-            msr: 0
+            traffic_camera: 2,
+            led_camera: 2
           }
           for (const item of data) {
-            form[map[item.deviceType]] = item.status === 1 ? 0 : 1
+            form[KeyMap[item.deviceType]] = item.status === 1 ? 0 : 1
           }
-          // const form = {
-          //   device: this.device.onlineStatus === 1 && this.device.activate === 2 ? 0 : 1,
-          //   gateway: 0,
-          //   sending_device: 2,
-          //   trafficCamera: 2,
-          //   receive_card: 0,
-          //   led: 0,
-          //   msr: 0
-          // }
-          this.linkStateForm = form
-        })
-        .catch(err => {
-          console.log('err', err)
+          this.linkState = form
+          this.loaded = true
         })
         .finally(() => {
-          this.loaded = true
+          this.loading = false
         })
     },
-    getImg (key) {
-      const value = this.linkStateForm[key]
-      let background = ''
-      let params = {}
+    getAttrs (key) {
+      const value = this.linkState[key]
+      let style = null
       switch (key) {
-        case 'msr':
-          background = `url("${require('@/assets/linkState/icon_msr.svg')}")`
-          break
         case 'led':
-          value === 0
-            ? (background = `url("${this.base64 ? this.base64 : require('@/assets/linkState/led_default.jpg')}")`)
-            : (params = { backgroundColor: '#333333' })
+          if (value === 0 && this.base64) {
+            style = {
+              backgroundImage: `url("${this.base64}")`
+            }
+          }
           break
         default:
-          if (value === 2) {
-            background = `url("${require('@/assets/linkState/icon_unbound.svg')}")`
-          } else {
-            background = `url("${require(`@/assets/linkState/icon_${key === 'trafficCamera' || key === 'ledCamera' ? 'camera' : key}_${value === 0 ? 'online' : 'offline'}.svg`)}")`
-          }
           break
       }
-      return { backgroundImage: background, ...params }
+      return {
+        'class': [
+          key,
+          value === 0
+            ? 'online'
+            : value === 1
+              ? 'offline'
+              : 'unbind'
+        ].join(' '),
+        style
+      }
     }
   }
 }
@@ -199,88 +218,189 @@ export default {
 
 <style lang="scss" scoped>
 @mixin getPosition($left, $top, $width, $height) {
-  left: $left;
   top: $top;
+  left: $left;
   width: $width;
   height: $height;
 }
 
-.linkState {
-  width: 1072px;
-  height: 452px;
+.c-link-state {
   position: relative;
-  .co {
-    z-index: 1;
-    position: absolute;
-    background-position: center;
-    background-size: cover;
-    background-repeat: no-repeat;
+  min-width: 1024px;
+  min-height: 490px;
+  overflow-x: auto;
+}
+
+.o-line {
+  position: absolute;
+  background-color: $border;
+
+  &.linked {
+    background-color: #026af2;
   }
-  .line {
-    position: absolute;
-    background: #a1c9ff;
-    &.closed {
-      background: #d5d9e4;
-    }
+
+  &.l1 {
+    transform: skewY(-30deg);
+    transform-origin: left;
+    @include getPosition(180px, 178px, 122px, 1px);
   }
-  .ctext {
-    height: 20px;
-    line-height: 20px;
-    white-space: nowrap;
-    text-align: center;
-    width: 100%;
-    bottom: -30px;
-    position: absolute;
-    color: #333333;
+
+  &.l2 {
+    @include getPosition(402px, 92px, 107px, 1px);
+  }
+
+  &.l3 {
+    @include getPosition(638px, 92px, 107px, 1px);
+  }
+
+  &.l4 {
+    @include getPosition(808px, 129px, 1px, 80px);
+  }
+
+  &.l5 {
+    transform: skewY(30deg);
+    transform-origin: left;
+    @include getPosition(170px, 244px, 122px, 1px);
   }
-  .msr {
-    @include getPosition(11px, 80px, 242px, 236px);
+
+  &.l6 {
+    @include getPosition(234px, 209px, 258px, 1px);
   }
-  .device {
-    @include getPosition(280px, 38px, 138px, 138px);
+
+  &.l7 {
+    @include getPosition(490px, 209px, 1px, 105px);
   }
-  .sending_device {
-    @include getPosition(515px, 38px, 138px, 138px);
+
+  &.l8 {
+    @include getPosition(490px, 314px, 52px, 1px);
   }
-  .receive_card {
-    @include getPosition(750px, 38px, 138px, 138px);
+
+  &.l9 {
+    @include getPosition(490px, 209px, 52px, 1px);
   }
-  .trafficCamera {
-    @include getPosition(599px, 225px, 79px, 79px);
+
+  &.l10 {
+    @include getPosition(402px, 369px, 268px, 1px);
   }
-  .gateway {
-    @include getPosition(280px, 279px, 138px, 138px);
+}
+
+.o-link-device {
+  position: absolute;
+  z-index: 1;
+
+  &__name {
+    position: absolute;
+    top: 100%;
+    left: 50%;
+    color: $black;
+    font-size: 16px;
+    line-height: 1;
+    white-space: nowrap;
+    transform: translateX(-50%);
   }
-  .led {
-    @include getPosition(704px, 233px, 349px, 197px);
+
+  &.unbind {
+    background-image: url("~@/assets/linkState/icon_unbound.svg");
   }
-  .l1 {
-    transform: skewY(-30deg);
-    transform-origin: left;
-    @include getPosition(192px, 216px, 122px, 1px);
+
+  &.msr {
+    @include getPosition(0, 42px, 242px, 236px);
+    background-image: url("~@/assets/linkState/icon_msr.svg");
   }
-  .l2 {
-    @include getPosition(413px, 130px, 107px, 1px);
+
+  &.device {
+    @include getPosition(270px, 0, 138px, 138px);
+
+    &.online {
+      background-image: url("~@/assets/linkState/icon_device_online.svg");
+    }
+
+    &.offline {
+      background-image: url("~@/assets/linkState/icon_device_offline.svg");
+    }
   }
-  .l3 {
-    @include getPosition(648px, 130px, 107px, 1px);
+
+  &.sending_device {
+    @include getPosition(504px, 0, 138px, 138px);
+
+    &.online {
+      background-image: url("~@/assets/linkState/icon_sending_device_online.svg");
+    }
+
+    &.offline {
+      background-image: url("~@/assets/linkState/icon_sending_device_offline.svg");
+    }
   }
-  .l4 {
-    @include getPosition(819px, 167px, 1px, 66px);
+
+  &.receive_card {
+    @include getPosition(740px, 0, 138px, 138px);
+
+    &.online {
+      background-image: url("~@/assets/linkState/icon_receive_card_online.svg");
+    }
+
+    &.offline {
+      background-image: url("~@/assets/linkState/icon_receive_card_offline.svg");
+    }
+
+    .o-link-device__name {
+      transform: translateX(8px);
+    }
+  }
+
+  &.traffic_camera {
+    @include getPosition(528px, 162px, 79px, 79px);
   }
-  .l5 {
-    @include getPosition(247px, 248px, 366px, 1px);
-    &.trafficCameraUnbound {
-      width: 364px;
+
+  &.led_camera {
+    @include getPosition(528px, 262px, 79px, 79px);
+  }
+
+  &.traffic_camera,
+  &.led_camera {
+    &.online {
+      background-image: url("~@/assets/linkState/icon_camera_online.svg");
+    }
+
+    &.offline {
+      background-image: url("~@/assets/linkState/icon_camera_offline.svg");
     }
   }
-  .l6 {
-    transform: skewY(30deg);
-    transform-origin: left;
-    @include getPosition(192px, 280px, 110px, 1px);
+
+  &.gateway {
+    @include getPosition(270px, 278px, 138px, 138px);
+
+    &.online {
+      background-image: url("~@/assets/linkState/icon_gateway_online.svg");
+    }
+
+    &.offline {
+      background-image: url("~@/assets/linkState/icon_gateway_offline.svg");
+    }
   }
-  .l7 {
-    @include getPosition(413px, 370px, 291px, 1px);
+
+  &.led {
+    @include getPosition(670px, 209px, 352px, 198px);
+    background-color: rgba(#000, 0.8);
+    background-position: center center;
+    background-size: contain;
+    background-repeat: no-repeat;
+
+    &.online {
+      background-image: url("~@/assets/image_no_program.svg");
+    }
+
+    &.offline {
+      background-image: url("~@/assets/image_offline.svg");
+    }
+
+    .o-link-device__name {
+      top: -8px;
+      left: auto;
+      right: 0;
+      bottom: auto;
+      transform: translateY(-100%);
+    }
   }
 }
 </style>

+ 0 - 1
src/views/device/detail/components/external/ReceivingCard/ReceivingCardTopology.vue

@@ -68,7 +68,6 @@ export default {
       if (screenList) {
         const cards = []
         const status = this.info.status
-        // /* eslint
         screenList.forEach(({ outCardList }) => {
           outCardList.forEach(({ sendCardList }) => {
             sendCardList.forEach(({ rxcList }) => {

+ 0 - 9
src/views/device/detail/components/external/ReceivingCard/index.vue

@@ -55,10 +55,6 @@ export default {
     device: {
       type: Object,
       required: true
-    },
-    online: {
-      type: [Boolean, String],
-      default: false
     }
   },
   data () {
@@ -86,11 +82,6 @@ export default {
       }
     }
   },
-  watch: {
-    online () {
-      this.getDefaults()
-    }
-  },
   activated () {
     this.getDefaults()
   },

+ 1 - 1
src/views/device/detail/index.vue

@@ -39,7 +39,7 @@
       v-if="device"
       class="l-flex--col l-flex__fill has-padding"
     >
-      <keep-alive exclude="DeviceCamera">
+      <keep-alive exclude="DeviceCamera,LinkState">
         <component
           :is="active"
           :key="active"