Quellcode durchsuchen

fix: 设备分析

lvkun vor 2 Jahren
Ursprung
Commit
07b6fa58ca

+ 217 - 0
src/pages/Iot/device/analysis.vue

@@ -0,0 +1,217 @@
+<template>
+<a-card
+  title="设备分析"
+  :tab-list="tabListNoTitle"
+  :active-tab-key="activeTabKey"
+  @tabChange="key => onTabChange(key)"
+>
+  <a-row :gutter="[8, 8]" style="margin-top: 20px;" >
+      <a-col :span="24" >
+        <a-space>
+          <a-select
+            style="width: 170px;"
+            v-model:value="state.deviceId"
+          >
+            <a-select-option
+              v-for="item in deviceState.dataSource"
+              :key="item.id"
+              :value="item.id"
+            >
+              {{item.deviceLabel}}
+            </a-select-option>
+          </a-select>
+          <a-range-picker @change="changeRangePicker" format="YYYY/MM/DD"  />
+        </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>
+        <span v-else>
+          <a-col :span="24" v-if="activeTabKey === 'session'">
+            <a-row>
+              <a-col :xs="24" :md="24" :xl="12" >
+                <div id="device-session" style="width: 600px;height: 400px;" ></div>
+              </a-col>
+              <a-col :xs="24" :md="24" :xl="12">
+                <div id="device-session-scatter" style="width: 600px;height: 400px;" ></div>
+              </a-col>
+            </a-row>
+          </a-col>
+          <a-col :span="24" v-else>
+            <div
+              :id="`device-attr-` + key"
+              style="width: 1000px; height: 400px;"
+              v-for="key in attrKeys"
+              :key="key"
+            >
+            </div>
+          </a-col>
+        </span>
+      </a-spin>
+      </a-col>
+
+    </a-row>
+</a-card>
+</template>
+<script lang='ts' setup >
+import { DeviceContriller } from '@/controller'
+import { reactive, watch, computed, ref, onMounted, watchEffect, nextTick } from 'vue'
+import * as echarts from 'echarts'
+import { useRoute } from 'vue-router'
+import { sessionEchartsJson, attrEchartsJson, scatterOption, barOption, calculateAverage } from './json/echartsJson'
+import dayjs from 'dayjs'
+import { useSchedulerOnce } from '@/hooks'
+
+const tabListNoTitle = [{
+  key: 'session',
+  tab: '上下线分析'
+},
+{
+  key: 'attr',
+  tab: '属性分析'
+}]
+
+const route = useRoute()
+
+const activeTabKey = ref<'session' | 'attr'>('session')
+
+const attrKeys = computed(() => Object.keys(state.attrSource))
+
+const deviceState = reactive<{
+  dataSource: IOT.API.DEVICE.Device[]
+}>({
+  dataSource: []
+})
+
+const state = reactive<{
+  attrSource: IOT.API.DEVICE.Attr[]
+  [key: string]: any
+}>({
+  deviceId: '',
+  start: 0,
+  end: '',
+  dataSource: [],
+  attrSource: [],
+  loading: false,
+  analysisType: ''
+})
+
+state.deviceId = route.query.id as string
+
+const onTabChange = (key: 'session' | 'attr') => activeTabKey.value = key
+
+watch(
+  () => activeTabKey.value,
+  () => activeTabKey.value === 'session' ? getDeviceSession() : getDeviceAttr()
+)
+
+watch(
+  () => state.attrSource,
+  () => {
+    nextTick(() => {
+      Object.keys(state.attrSource).forEach(key => {
+        const chartDom = document.getElementById('device-attr-' + key)
+
+        const myChart = echarts.init(chartDom!)
+        const attrItem = state.attrSource[key]
+
+        attrEchartsJson.xAxis.data = (attrItem.map(item => dayjs(item.ts).format('HH:MM:ss')) || []) as never[]
+
+        attrEchartsJson.series[0].data = attrItem.map(item => item.longValue)
+
+        attrEchartsJson.title.text = key
+
+        myChart.setOption(attrEchartsJson)
+      })
+      state.loading = false
+    })
+  }
+)
+
+watch(
+  () => state.dataSource,
+  () => {
+    if (activeTabKey.value === 'session') {
+      const chartDom = document.getElementById('device-session')
+      const chartDomScatter = document.getElementById('device-session-scatter')
+      const myChart = echarts.init(chartDom!)
+      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' ? '上线' : '下线')
+
+      const connectCount = state.dataSource.filter(item => item.sessionType === 'CONNECT').length
+      const disconnectCount = state.dataSource.length - connectCount
+
+      barOption.series[0].data = [
+        {
+          value: calculateAverage(connectCount),
+          groupId: 'male'
+        },
+        {
+          value: calculateAverage(disconnectCount),
+          groupId: 'female'
+        }
+      ]
+
+      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
+
+      setInterval(function () {
+        currentOption = currentOption === scatterOption ? barOption : scatterOption
+        chartDomScatterChart.setOption(currentOption, true)
+      }, 2000)
+
+      chartDomScatterChart.setOption(currentOption)
+      myChart.setOption(sessionEchartsJson)
+
+      state.loading = false
+    }
+  }
+)
+
+watch(
+  () => state.deviceId,
+  () => activeTabKey.value === 'session' ? getDeviceSession() : getDeviceAttr()
+)
+
+const changeRangePicker = (time) => {
+  const [startTime, endTime] = time
+  console.log(startTime, endTime)
+
+  state.start = new Date(startTime).getTime()
+  state.end = new Date(endTime).getTime()
+
+  activeTabKey.value === 'session' ? getDeviceSession() : getDeviceAttr()
+}
+
+const getDeviceSession = async () => {
+  if (!state.deviceId) return
+  state.loading = true
+  const { data } = await DeviceContriller.getSession({ deviceId: state.deviceId, start: state.start, end: state.end })
+  state.dataSource = data
+}
+
+const getDeviceAttr = async () => {
+  if (!state.deviceId) return
+  state.loading = true
+  const { data } = await DeviceContriller.getAttr({ deviceId: state.deviceId, start: state.start, end: state.end })
+  state.attrSource = data
+}
+
+const getDeviceList = async () => {
+  const { data } = await DeviceContriller.list()
+  deviceState.dataSource = data
+}
+
+onMounted(() => {
+  getDeviceList()
+  if (state.deviceId) {
+    getDeviceSession()
+  }
+})
+</script>
+<style lang='less' scoped >
+</style>

+ 5 - 112
src/pages/Iot/device/index.vue

@@ -70,6 +70,7 @@
             <a-space>
               <a @click="goDetailPage(record.id)">查看</a>
               <a @click="goDebugPage(record.id)" >调试</a>
+              <a @click="goAnalysisPage(record.id)">分析</a>
               <a-popconfirm
                   title="确实要删除吗?"
                   ok-text="确定"
@@ -78,20 +79,6 @@
                 >
                   <a href="#">删除</a>
               </a-popconfirm>
-              <a-dropdown>
-                <a class="ant-dropdown-link" @click.prevent>分析 <DownOutlined /> </a>
-                <template #overlay>
-                  <a-menu>
-                    <a-menu-item
-                      v-for="item in analysisList"
-                      :key="item.key"
-                      @click="openAnalysisModal(item.key, record.id)"
-                    >
-                      <a href="javascript:;">{{item.label}}</a>
-                    </a-menu-item>
-                  </a-menu>
-                </template>
-              </a-dropdown>
             </a-space>
         </template>
       </template>
@@ -137,29 +124,6 @@
     </a-form>
   </a-modal>
 
-  <modal-pro
-    :label="analysisTitle"
-    :open="state.analysisVisible"
-    @cancel="state.analysisVisible = false"
-    @ok="state.analysisVisible = false"
-    style="width: 700px;"
-  >
-    <a-row :gutter="[8, 8]" style="margin-top: 20px;" >
-      <a-col :span="24" >
-        <a-range-picker @change="changeRangePicker" format="YYYY/MM/DD"  />
-      </a-col>
-      <a-spin :spinning="analysisState.loading" >
-      <a-col :span="24" v-if="state.analysisType === 'session'">
-        <div id="device-session" style="width: 600px;height: 400px;" ></div>
-        <div id="device-session-scatter" style="width: 600px;height: 400px;" ></div>
-      </a-col>
-      <a-col :span="24" v-else>
-        <div id="device-attr" style="width: 600px;height: 400px;" ></div>
-      </a-col>
-    </a-spin>
-    </a-row>
-  </modal-pro>
-
 </template>
 
 <script lang="ts" setup >
@@ -170,8 +134,6 @@ import { Form, message } from 'ant-design-vue'
 import { DeviceAuthTypeEnum } from '@/enum/common'
 import { useRouter } from 'vue-router'
 import { DownOutlined } from '@ant-design/icons-vue'
-import * as echarts from 'echarts'
-import { sessionEchartsJson, attrEchartsJson, scatterOption, barOption } from './json/echartsJson'
 
 const useForm = Form.useForm
 const router = useRouter()
@@ -225,8 +187,6 @@ const analysisList = [
   { label: '属性分析', key: 'attr' }
 ]
 
-const analysisTitle = computed(() => state.analysisType === 'session' ? '上下线分析' : '属性分析')
-
 const state = reactive<{
   modelId: string,
   deviceCount: any,
@@ -271,49 +231,6 @@ const deviceState = reactive({
   confirmSecret: ''
 })
 
-const analysisState = reactive({
-  deviceId: '',
-  start: 0,
-  end: '',
-  dataSource: [],
-  loading: false
-})
-
-watch(
-  () => analysisState.dataSource,
-  () => {
-    if (state.analysisType === 'session') {
-      const chartDom = document.getElementById('device-session')
-      const chartDomScatter = document.getElementById('device-session-scatter')
-      const myChart = echarts.init(chartDom!)
-      const chartDomScatterChart = echarts.init(chartDomScatter!)
-      sessionEchartsJson.xAxis.data = analysisState.dataSource.map(item => item.createAt) as never[]
-      sessionEchartsJson.series[0].data = analysisState.dataSource.map(item => item.sessionType === 'CONNECT' ? '上线' : '下线')
-
-      let currentOption = scatterOption
-
-      setInterval(function () {
-        currentOption = currentOption === scatterOption ? barOption : scatterOption
-        chartDomScatterChart.setOption(currentOption, true)
-      }, 2000)
-
-      chartDomScatterChart.setOption(currentOption)
-      myChart.setOption(sessionEchartsJson)
-
-      analysisState.loading = false
-    } else {
-      const chartDom = document.getElementById('device-attr')
-      const myChart = echarts.init(chartDom!)
-
-      attrEchartsJson.xAxis.data = analysisState.dataSource.map(item => item.keyLabel) || []
-      attrEchartsJson.series[0].data = analysisState.dataSource.map(item => item.longValue) || []
-
-      myChart.setOption(attrEchartsJson)
-      analysisState.loading = false
-    }
-  }
-)
-
 const { resetFields, validate, validateInfos } = useForm(searchState, {})
 
 const { resetFields: resetFieldsDevice, validate: validateDevice, validateInfos: validateInfosDeviceState } = useForm(deviceState, reactive({
@@ -321,22 +238,6 @@ const { resetFields: resetFieldsDevice, validate: validateDevice, validateInfos:
   deviceCode: [{ required: true, message: '请填写设备码' }]
 }))
 
-const changeRangePicker = (time) => {
-  const [startTime, endTime] = time
-  console.log(startTime, endTime)
-
-  analysisState.start = new Date(startTime).getTime()
-  analysisState.end = new Date(endTime).getTime()
-  state.analysisType === 'session' ? getDeviceSession() : getDeviceAttr()
-}
-
-const openAnalysisModal = (key: 'session' | 'attr', id: string) => {
-  state.analysisVisible = true
-  state.analysisType = key
-  analysisState.deviceId = id
-  key === 'session' ? getDeviceSession() : getDeviceAttr()
-}
-
 const changePage = ({ current }) => {
   searchState.page = current
   getDevicePage()
@@ -350,23 +251,15 @@ const goDetailPage = (id: string) => {
   router.push({ path: '/device/detail', query: { id } })
 }
 
-const getDeviceSession = async () => {
-  analysisState.loading = true
-  const { data } = await DeviceContriller.getSession({ deviceId: analysisState.deviceId, start: analysisState.start, end: analysisState.end })
-  analysisState.dataSource = data
-}
-
-const getDeviceAttr = async () => {
-  analysisState.loading = true
-  const { data } = await DeviceContriller.getAttr({ deviceId: analysisState.deviceId, start: analysisState.start, end: analysisState.end })
-  analysisState.dataSource = data.hum
-}
-
 const delDevice = async (id: string) => {
   await DeviceContriller.del(id)
   getDevicePage()
 }
 
+const goAnalysisPage = (id: string) => {
+  router.push({ path: '/device/analysis', query: { id } })
+}
+
 const ok = () => {
   if (deviceState.deviceAuthType === DeviceAuthTypeEnum.SECRET && deviceState.deviceSecret !== deviceState.confirmSecret) {
     message.warn('两次密匙输入不同')

+ 25 - 25
src/pages/Iot/device/json/echartsJson.ts

@@ -38,22 +38,6 @@ export const sessionEchartsJson = {
   ]
 }
 
-export const attrEchartsJson = {
-  xAxis: {
-    type: 'category',
-    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
-  },
-  yAxis: {
-    type: 'value'
-  },
-  series: [
-    {
-      data: [150, 230, 224, 218, 135, 147, 260],
-      type: 'line'
-    }
-  ]
-}
-
 // prettier-ignore
 const femaleData = [[161.2, 51.6], [167.5, 59.0], [159.5, 49.2], [157.0, 63.0], [155.8, 53.6],
   [170.0, 59.0], [159.1, 47.6], [166.0, 69.8], [176.2, 66.8], [160.2, 75.2],
@@ -160,12 +144,9 @@ const maleDeta = [[174.0, 65.6], [175.3, 71.8], [193.5, 80.7], [186.5, 72.6], [1
   [170.2, 62.3], [177.8, 82.7], [179.1, 79.1], [190.5, 98.2], [177.8, 84.1],
   [180.3, 83.2], [180.3, 83.2]
 ]
-function calculateAverage (data: number[][], dim: number) {
-  let total = 0
-  for (let i = 0; i < data.length; i++) {
-    total += data[i][dim]
-  }
-  return (total /= data.length)
+
+export function calculateAverage (length: number) {
+  return length
 }
 
 export const scatterOption = {
@@ -206,7 +187,7 @@ export const scatterOption = {
 export const barOption = {
   xAxis: {
     type: 'category',
-    data: ['Female', 'Male']
+    data: ['上线', '下线']
   },
   yAxis: {},
   series: [
@@ -215,11 +196,11 @@ export const barOption = {
       id: 'total',
       data: [
         {
-          value: calculateAverage(maleDeta, 0),
+          value: 0,
           groupId: 'male'
         },
         {
-          value: calculateAverage(femaleData, 0),
+          value: 0,
           groupId: 'female'
         }
       ],
@@ -233,3 +214,22 @@ export const barOption = {
     }
   ]
 }
+
+export const attrEchartsJson = {
+  title: {
+    text: 'Stacked Line'
+  },
+  xAxis: {
+    type: 'category',
+    data: []
+  },
+  yAxis: {
+    type: 'value'
+  },
+  series: [
+    {
+      data: [150, 230, 224, 218, 135, 147, 260],
+      type: 'line'
+    }
+  ]
+}

+ 6 - 1
src/router/index.ts

@@ -63,8 +63,13 @@ const iot = {
         },
         {
           path: '/device/topology',
-          name: '设备拓扑 ',
+          name: '设备拓扑',
           component: () => import('@/pages/iot/device/topology.vue')
+        },
+        {
+          path: '/device/analysis',
+          name: '设备分析',
+          component: () => import('@/pages/iot/device/analysis.vue')
         }
       ]
     },