Explorar el Código

fix: 设备分析动画

lvkun hace 2 años
padre
commit
de6f099f3d

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 15454 - 1
package-lock.json


+ 1 - 1
src/api/iot/device.ts

@@ -249,7 +249,7 @@ export const getDeviceByGroup = (params: IOT.API.DEVICE.GroupQueryParams) => {
   })
 }
 
-/** 实时数据 */
+/** 获取设备属性 */
 export const getDeviceAttribute = (deviceId: string) => {
   return request<IOT.API.DEVICE.Device[]>({
     url: `/deviceAttribute/latest?deviceId=${deviceId}`,

+ 2 - 0
src/components/StatisticsTemplate/index.vue

@@ -14,10 +14,12 @@
           {{item.label}}
         </div>
       </a-col>
+      <!-- <vueCountTo :startVal='2' :endVal='2023' :duration='3000'  /> -->
     </a-row>
 </a-card>
 </template>
 <script lang='ts' setup >
+import vueCountTo from 'vue-count-to'
 
 interface IProps {
   title: string,

+ 7 - 2
src/controller/iot/device.ts

@@ -239,6 +239,11 @@ export class DeviceContriller {
     return await getDeviceAttribute(deviceId)
   }
 
+  /** 获取设备属性 */
+  static async getDeviceAttribute (deviceId: string) {
+    return await getDeviceAttribute(deviceId)
+  }
+
   static async getDevicShadow (deviceId: string) {
     return await getDevicShadow(deviceId)
   }
@@ -255,7 +260,7 @@ export class DeviceContriller {
         sessionEntities: data.sessionEntities.map(item => {
           return {
             ...item,
-            createAt: dayjs(item.createAt).format('YYYY/MM/DD')
+            createAt: dayjs(item.createAt).format('YYYY/MM/DD HH:mm:ss')
           }
         }),
         offlineNum: data.offlineNum,
@@ -265,7 +270,7 @@ export class DeviceContriller {
     }
   }
 
-  static async getAttr (params: {deviceId: string, start: number, end: number}) {
+  static async getAttr (params: {deviceId: string, start: number, end: number, attributeKey: string}) {
     return await getDeviceAttributes(params)
   }
 

+ 74 - 48
src/pages/Iot/device/analysis.vue

@@ -10,7 +10,7 @@
     :active-tab-key="activeTabKey"
     @tabChange="key => onTabChange(key)"
   >
-    <a-row :gutter="[8, 8]" style="margin-top: 20px;" >
+    <a-row :gutter="[8, 8]" style="margin: 0 20px;" >
 
         <a-col :span="24" >
           <a-space>
@@ -35,12 +35,26 @@
                 </template>
               </a-select>
             </a-spin>
-            <a-range-picker  v-model:value="times" @change="changeRangePicker"  />
+            <a-select
+                v-if="activeTabKey === 'attr'"
+                v-model:value="state.attributeKey"
+                placeholder="请选择属性"
+                style="width: 170px"
+                :show-arrow="false"
+                @change="selectAttr"
+              >
+                <a-select-option
+                  v-for="item in deviceState.attrList"
+                  :key="item.key"
+                  :value="item.key"
+                >{{item.keyLabel}}</a-select-option>
+              </a-select>
+            <a-range-picker :show-time="{ format: 'HH:mm' }" v-model:value="times" @change="changeRangePicker"  />
           </a-space>
         </a-col>
         <a-col :span="24">
           <a-spin :spinning="state.loading" >
-          <a-empty style="margin: 0 auto;" v-if="!state.deviceId" description="请选择设备" ></a-empty>
+          <a-empty style="margin: 0 auto;" v-if="emptyCondition" :description="emptyDesc" ></a-empty>
           <span v-else>
             <a-col :span="24" v-if="activeTabKey === 'session'">
               <a-row>
@@ -54,10 +68,8 @@
             </a-col>
             <a-col :span="24" v-else>
               <div
-                :id="`device-attr-` + key"
+                id="device-attr"
                 style="width: 1000px; height: 400px;"
-                v-for="key in attrKeys"
-                :key="key"
               >
               </div>
             </a-col>
@@ -90,12 +102,16 @@ const route = useRoute()
 
 const activeTabKey = ref<'session' | 'attr'>('session')
 
-const attrKeys = computed(() => Object.keys(state.attrSource))
+const emptyCondition = computed(() => activeTabKey.value === 'session' ? state.dataSource.length === 0 : state.attrSource.length === 0)
+
+const emptyDesc = computed(() => !state.deviceId ? '请选择设备' : '该设备下暂无数据')
 
 const deviceState = reactive<{
   dataSource: IOT.API.DEVICE.Device[]
+  attrList: IOT.API.DEVICE.Attr[]
 }>({
-  dataSource: []
+  dataSource: [],
+  attrList: []
 })
 
 const state = reactive<{
@@ -112,18 +128,24 @@ const state = reactive<{
   analysisType: '',
   spinning: false,
   onlineNum: 0,
-  offlineNum: 0
+  offlineNum: 0,
+  attributeKey: null
 })
 
-const times = ref([dayjs(), dayjs()])
+const times = ref([dayjs().subtract(30, 'minute'), dayjs()])
 
 state.deviceId = route.query.id as string
 
 const onTabChange = (key: 'session' | 'attr') => activeTabKey.value = key
 
+// 切换上下线分析
 watch(
   () => activeTabKey.value,
-  () => activeTabKey.value === 'session' ? getDeviceSession() : getDeviceAttr()
+  () => {
+    state.deviceId = null
+    state.searchDeviceLabel = null
+    state.attributeKey = null
+  }
 )
 
 // 获取设备属性分析数据
@@ -131,20 +153,22 @@ watch(
   () => state.attrSource,
   () => {
     nextTick(() => {
-      Object.keys(state.attrSource).forEach(key => {
-        const chartDom = document.getElementById('device-attr-' + key)
+      if (state.attrSource.length === 0) {
+        state.loading = false
+        return
+      }
+      const chartDom = document.getElementById('device-attr')
 
-        const myChart = echarts.init(chartDom!)
-        const attrItem = state.attrSource[key]
+      const myChart = echarts.init(chartDom!)
+
+      attrEchartsJson.xAxis.data = (state.attrSource.map(item => dayjs(item.ts).format('HH:MM:ss')) || []) as never[]
 
-        attrEchartsJson.xAxis.data = (attrItem.map(item => dayjs(item.ts).format('HH:MM:ss')) || []) as never[]
+      attrEchartsJson.series[0].data = state.attrSource.map(item => item.value)
 
-        attrEchartsJson.series[0].data = attrItem.map(item => item.longValue)
+      attrEchartsJson.title.text = state.attrSource[0].keyLabel
 
-        attrEchartsJson.title.text = key
+      myChart.setOption(attrEchartsJson)
 
-        myChart.setOption(attrEchartsJson)
-      })
       state.loading = false
     })
   }
@@ -153,9 +177,13 @@ watch(
 // 获取上下线分析图表数据
 // state.dataSource
 watch(
-  () => state.deviceId,
+  () => state.dataSource,
   () => {
     setTimeout(() => {
+      if (state.dataSource.length === 0) {
+        state.loading = false
+        return
+      }
       if (activeTabKey.value === 'session') {
         const chartDom = document.getElementById('device-session')
         const chartDomScatter = document.getElementById('device-session-scatter')
@@ -165,6 +193,7 @@ watch(
         const chartDomScatterChart = echarts.init(chartDomScatter!)
         sessionEchartsJson.xAxis.data = state.dataSource.map(item => item.createAt) as never[]
         sessionEchartsJson.series[0].data = state.dataSource.map(item => item.sessionType === 'CONNECT' ? '上线' : '下线')
+        sessionEchartsJson.series[1].data = state.dataSource.map(item => item.sessionType !== 'CONNECT' ? '上线' : '下线')
 
         const connectCount = state.dataSource.filter(item => item.sessionType === 'CONNECT').length
         const disconnectCount = state.dataSource.length - connectCount
@@ -180,20 +209,10 @@ watch(
           }
         ]
 
-        sessionEchartsJson.legend.data = [`上线数量 ${state.onlineNum}`, `下线数量 ${state.offlineNum}`]
-
-        scatterOption.series[0].data = state.dataSource.filter(item => item.sessionType === 'CONNECT').map(item => [0, connectCount])
-
-        scatterOption.series[1].data = state.dataSource.filter(item => item.sessionType !== 'CONNECT').map(item => [1, disconnectCount])
-
-        let currentOption = scatterOption
+        sessionEchartsJson.series[0].name = `上线数量 ${state.onlineNum}`
+        sessionEchartsJson.series[1].name = `下线数量 ${state.offlineNum}`
 
-        setInterval(function () {
-          currentOption = currentOption === scatterOption ? barOption : scatterOption
-          chartDomScatterChart.setOption(currentOption, true)
-        }, 2000)
-
-        chartDomScatterChart.setOption(currentOption)
+        chartDomScatterChart.setOption(barOption)
         myChart.setOption(sessionEchartsJson)
 
         state.loading = false
@@ -202,19 +221,24 @@ watch(
   }
 )
 
-watch(
-  () => state.deviceId,
-  () => activeTabKey.value === 'session' ? getDeviceSession() : getDeviceAttr()
-)
+const selectAttr = (value: string) => {
+  state.attributeKey = value
+  getDeviceAttr()
+}
 
 const changeRangePicker = (time) => {
   activeTabKey.value === 'session' ? getDeviceSession() : getDeviceAttr()
 }
 
-const selectDevice = async (value: records) => {
+const selectDevice = async (value: string) => {
   const device = await DeviceContriller.byId(value)
   state.deviceId = device.id
   console.log('device:', state.deviceId)
+  if (activeTabKey.value === 'attr') {
+    getDeviceAttribute()
+  } else {
+    getDeviceSession()
+  }
 }
 
 const getDeviceLabel = async (val: string) => {
@@ -229,7 +253,7 @@ const getDeviceLabel = async (val: string) => {
 const getDeviceSession = async () => {
   if (!state.deviceId) return
   state.loading = true
-  const { data } = await DeviceContriller.getSession({ deviceId: state.deviceId, start: state.start, end: state.end })
+  const { data } = await DeviceContriller.getSession({ deviceId: state.deviceId, start: dayjs(times.value[0]).unix() * 1000, end: dayjs(times.value[1]).unix() * 1000 })
   state.dataSource = data.sessionEntities
   state.offlineNum = data.offlineNum
   state.onlineNum = data.onlineNum
@@ -238,20 +262,22 @@ const getDeviceSession = async () => {
 const getDeviceAttr = async () => {
   if (!state.deviceId) return
   state.loading = true
-
-  const { data } = await DeviceContriller.getAttr({ deviceId: state.deviceId, start: 1, end: state.end })
+  // .format('YYYY/MM/DD HH:mm:ss')
+  const { data } = await DeviceContriller.getAttr({
+    deviceId: state.deviceId,
+    start: 1,
+    end: new Date().getTime(),
+    attributeKey: state.attributeKey
+  })
   state.attrSource = data
 }
 
-const getDeviceList = async () => {
-  state.spinning = true
-  const { data } = await DeviceContriller.list()
-  state.spinning = false
-  deviceState.dataSource = data
+const getDeviceAttribute = async () => {
+  const { data } = await DeviceContriller.getDeviceAttribute(state.deviceId)
+  deviceState.attrList = data
 }
 
 onMounted(() => {
-  // getDeviceList()
   if (state.deviceId) {
     getDeviceSession()
   }

+ 16 - 3
src/pages/Iot/device/json/echartsJson.ts

@@ -3,10 +3,15 @@ export const sessionEchartsJson = {
     text: ''
   },
   tooltip: {
-    trigger: 'axis'
+    trigger: 'axis',
+    formatter: function (params, ticket, callback) {
+      console.log('params:', params)
+
+      // return params.name.split(' ')[1]
+      return ''
+    }
   },
   legend: {
-    data: ['上线数量', '下线数量']
   },
   grid: {
     left: '3%',
@@ -33,7 +38,15 @@ export const sessionEchartsJson = {
       name: 'offlineNum',
       type: 'line',
       stack: 'Total',
-      data: ['上线', '下线', '下线', '上线']
+      data: [],
+      timeStamp: 7788
+    },
+    {
+      name: 'onlineNum',
+      type: 'line',
+      stack: 'Total',
+      data: [],
+      timeStamp: 7788
     }
   ]
 }

+ 15 - 15
yarn.lock

@@ -1207,7 +1207,7 @@
 
 "@discoveryjs/json-ext@0.5.7":
   "integrity" "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw=="
-  "resolved" "https://registry.npmmirror.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz"
+  "resolved" "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz"
   "version" "0.5.7"
 
 "@electron/get@^2.0.0":
@@ -1412,7 +1412,7 @@
 
 "@polka/url@^1.0.0-next.20":
   "integrity" "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g=="
-  "resolved" "https://registry.npmmirror.com/@polka/url/-/url-1.0.0-next.21.tgz"
+  "resolved" "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz"
   "version" "1.0.0-next.21"
 
 "@sideway/address@^4.1.3":
@@ -2521,7 +2521,7 @@
 
 "ansi-styles@^4.1.0":
   "integrity" "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="
-  "resolved" "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz"
+  "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz"
   "version" "4.3.0"
   dependencies:
     "color-convert" "^2.0.1"
@@ -2991,7 +2991,7 @@
 
 "chalk@^4.1.0":
   "integrity" "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="
-  "resolved" "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz"
+  "resolved" "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
   "version" "4.1.2"
   dependencies:
     "ansi-styles" "^4.1.0"
@@ -3986,7 +3986,7 @@
 
 "duplexer@^0.1.2":
   "integrity" "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg=="
-  "resolved" "https://registry.npmmirror.com/duplexer/-/duplexer-0.1.2.tgz"
+  "resolved" "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz"
   "version" "0.1.2"
 
 "easy-stack@1.0.1":
@@ -5004,7 +5004,7 @@
 
 "gzip-size@^6.0.0":
   "integrity" "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q=="
-  "resolved" "https://registry.npmmirror.com/gzip-size/-/gzip-size-6.0.0.tgz"
+  "resolved" "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz"
   "version" "6.0.0"
   dependencies:
     "duplexer" "^0.1.2"
@@ -5026,7 +5026,7 @@
 
 "has-flag@^4.0.0":
   "integrity" "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
-  "resolved" "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz"
+  "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz"
   "version" "4.0.0"
 
 "has-property-descriptors@^1.0.0":
@@ -6164,7 +6164,7 @@
 
 "mrmime@^1.0.0":
   "integrity" "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw=="
-  "resolved" "https://registry.npmmirror.com/mrmime/-/mrmime-1.0.1.tgz"
+  "resolved" "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz"
   "version" "1.0.1"
 
 "ms@^2.1.1", "ms@2.1.2":
@@ -6412,7 +6412,7 @@
 
 "opener@^1.5.2":
   "integrity" "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A=="
-  "resolved" "https://registry.npmmirror.com/opener/-/opener-1.5.2.tgz"
+  "resolved" "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz"
   "version" "1.5.2"
 
 "optionator@^0.9.1":
@@ -7576,7 +7576,7 @@
 
 "sirv@^1.0.7":
   "integrity" "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ=="
-  "resolved" "https://registry.npmmirror.com/sirv/-/sirv-1.0.19.tgz"
+  "resolved" "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz"
   "version" "1.0.19"
   dependencies:
     "@polka/url" "^1.0.0-next.20"
@@ -7889,7 +7889,7 @@
 
 "supports-color@^7.1.0":
   "integrity" "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="
-  "resolved" "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz"
+  "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz"
   "version" "7.2.0"
   dependencies:
     "has-flag" "^4.0.0"
@@ -8049,7 +8049,7 @@
 
 "totalist@^1.0.0":
   "integrity" "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g=="
-  "resolved" "https://registry.npmmirror.com/totalist/-/totalist-1.1.0.tgz"
+  "resolved" "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz"
   "version" "1.1.0"
 
 "tr46@~0.0.3":
@@ -8389,9 +8389,9 @@
   "resolved" "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz"
   "version" "3.0.1"
 
-"webpack-bundle-analyzer@^4.4.0":
+"webpack-bundle-analyzer@^4.4.0", "webpack-bundle-analyzer@^4.9.0":
   "integrity" "sha512-+bXGmO1LyiNx0i9enBu3H8mv42sj/BJWhZNFwjz92tVnBa9J3JMGo2an2IXlEleoDOPn/Hofl5hr/xCpObUDtw=="
-  "resolved" "https://registry.npmmirror.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.9.0.tgz"
+  "resolved" "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.9.0.tgz"
   "version" "4.9.0"
   dependencies:
     "@discoveryjs/json-ext" "0.5.7"
@@ -8615,7 +8615,7 @@
 
 "ws@^7.3.1":
   "integrity" "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q=="
-  "resolved" "https://registry.npmmirror.com/ws/-/ws-7.5.9.tgz"
+  "resolved" "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz"
   "version" "7.5.9"
 
 "ws@^8.13.0":

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio