lvkun 2 лет назад
Родитель
Сommit
fc45af5899

+ 9 - 0
src/api/iot/device.ts

@@ -343,3 +343,12 @@ export const liveCustomRtsUrl = (data: {id: string, rtsUrl: string}) => {
     data
   })
 }
+
+// /device/deviceLabel?deviceLabel=xxxx
+/** 模糊查询:根据设备名称来查询全部的符合条件的设备名 */
+export const getDeviceLabelsByLabel = (deviceLabel: string) => {
+  return request<string[]>({
+    url: `/device/deviceLabel?deviceLabel=${deviceLabel}`,
+    method: 'GET'
+  })
+}

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

@@ -82,7 +82,7 @@ export const getModelAttribute = (params: any) => {
   })
 }
 
-export const getModelAttributeList = (params: {modelId: string}) => {
+export const getModelAttributeList = (params: {modelId: string, excludeRts: boolean}) => {
   return request<IOT.API.MODELATTR.ModelAttr[]>({
     url: '/modelAttribute/list',
     method: 'GET',

+ 4 - 0
src/components/MicroComponents/index.tsx

@@ -160,3 +160,7 @@ export const CopyTsx = defineComponent({
     )
   }
 })
+
+/**
+ *
+ */

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

@@ -2,7 +2,7 @@ import {
   addDevice, addSubDevice, delDevice, delDeviceMul, delDeviceTag,
   getDeviceById, getDeviceCount, getDeviceList, getDeviceMsgList, addDeviceMsg, getDeviceTag,
   getSubDeviceList, updateDeviceLabel, addDeviceCmd, getDeviceCmdList, addDeviceTag, addDeviceGroup,
-  listDeviceGroup, postGroupBindDevice, delGroupBindDevice, getDeviceByGroup, getDevicePage, delSubDevice, getDeviceAttribute, getDevicShadow, getDeviceTopology, getDeviceSession, getDeviceAttributes, getDeviceSecret, getOtaByDeviceId, otaUpgradationRecordByDeviceId, upgradationOtaByDeviceId, liveById, liveControlRts, liveCustomRtsUrl
+  listDeviceGroup, postGroupBindDevice, delGroupBindDevice, getDeviceByGroup, getDevicePage, delSubDevice, getDeviceAttribute, getDevicShadow, getDeviceTopology, getDeviceSession, getDeviceAttributes, getDeviceSecret, getOtaByDeviceId, otaUpgradationRecordByDeviceId, upgradationOtaByDeviceId, liveById, liveControlRts, liveCustomRtsUrl, getDeviceLabelsByLabel
 } from '@/api/iot/device'
 import { DeviceMsgEnum, OtaStatusEnum } from '@/enum/common'
 import { message } from 'ant-design-vue'
@@ -85,7 +85,7 @@ export class DeviceContriller {
   static async list (params: {modelId: string, deviceLabel: string, limit: number, lastId: string, deviceStatus: 'INIT' | 'CONNECT' | 'DISCONNECT' | 'DISABLED' | ''} = {
     modelId: '',
     deviceLabel: '',
-    limit: 10000,
+    limit: 20,
     lastId: '',
     deviceStatus: ''
   }) {
@@ -302,4 +302,11 @@ export class DeviceContriller {
   static async liveCustomRtsUrl (data: {id: string, rtsUrl: string}) {
     return liveCustomRtsUrl(data)
   }
+
+  /**
+   * @description 模糊查询:根据设备名称来查询全部的符合条件的设备名
+   */
+  static async labelsByLabel (deviceLabel: string) {
+    return await getDeviceLabelsByLabel(deviceLabel)
+  }
 }

+ 1 - 1
src/controller/iot/model.ts

@@ -11,7 +11,7 @@ export class ModelController {
 
   static async list (params: {modelLabel?: string, limit?: number, lastId?: string} = {
     modelLabel: '',
-    limit: 10000,
+    limit: 20000,
     lastId: ''
   }) {
     return await getModelList(params)

+ 1 - 1
src/controller/iot/modelAttr.ts

@@ -22,7 +22,7 @@ export class ModelAttrController {
     message.success('删除成功')
   }
 
-  static async list (params: {modelId: string}) {
+  static async list (params: {modelId: string, excludeRts: boolean} = { modelId: '', excludeRts: false }) {
     return await getModelAttributeList(params)
   }
 }

+ 139 - 115
src/pages/Iot/device/analysis.vue

@@ -1,57 +1,66 @@
 <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"
+
+  <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-spin
+              :spinning="state.spinning"
             >
-            </div>
-          </a-col>
-        </span>
-      </a-spin>
-      </a-col>
-
-    </a-row>
-</a-card>
+              <a-select
+                v-model:value="state.searchDeviceLabel"
+                show-search
+                placeholder="请输入设备名"
+                :default-active-first-option="false"
+                style="width: 170px"
+                :show-arrow="false"
+                :filter-option="false"
+                :not-found-content="null"
+                :options="state.dataSource"
+                @search="getDeviceLabel"
+              >
+                <template v-if="state.fetching" #notFoundContent>
+                  <a-spin size="small" />
+                </template>
+              </a-select>
+            </a-spin>
+            <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'
@@ -60,7 +69,6 @@ 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',
@@ -88,12 +96,14 @@ const state = reactive<{
   [key: string]: any
 }>({
   deviceId: '',
+  searchDeviceLabel: '',
   start: 0,
   end: '',
   dataSource: [],
   attrSource: [],
   loading: false,
-  analysisType: ''
+  analysisType: '',
+  spinning: false
 })
 
 state.deviceId = route.query.id as string
@@ -105,72 +115,75 @@ watch(
   () => activeTabKey.value === 'session' ? getDeviceSession() : getDeviceAttr()
 )
 
-watch(
-  () => state.attrSource,
-  () => {
-    nextTick(() => {
-      Object.keys(state.attrSource).forEach(key => {
-        const chartDom = document.getElementById('device-attr-' + key)
+// 获取当前时间到半小时之前
+// const get
 
-        const myChart = echarts.init(chartDom!)
-        const attrItem = state.attrSource[key]
+// watch(
+//   () => state.attrSource,
+//   () => {
+//     nextTick(() => {
+//       Object.keys(state.attrSource).forEach(key => {
+//         const chartDom = document.getElementById('device-attr-' + key)
 
-        attrEchartsJson.xAxis.data = (attrItem.map(item => dayjs(item.ts).format('HH:MM:ss')) || []) as never[]
+//         const myChart = echarts.init(chartDom!)
+//         const attrItem = state.attrSource[key]
 
-        attrEchartsJson.series[0].data = attrItem.map(item => item.longValue)
+//         attrEchartsJson.xAxis.data = (attrItem.map(item => dayjs(item.ts).format('HH:MM:ss')) || []) as never[]
 
-        attrEchartsJson.title.text = key
+//         attrEchartsJson.series[0].data = attrItem.map(item => item.longValue)
 
-        myChart.setOption(attrEchartsJson)
-      })
-      state.loading = false
-    })
-  }
-)
+//         attrEchartsJson.title.text = key
 
-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
-    }
-  }
-)
+//         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,
@@ -179,7 +192,6 @@ watch(
 
 const changeRangePicker = (time) => {
   const [startTime, endTime] = time
-  console.log(startTime, endTime)
 
   state.start = new Date(startTime).getTime()
   state.end = new Date(endTime).getTime()
@@ -187,6 +199,16 @@ const changeRangePicker = (time) => {
   activeTabKey.value === 'session' ? getDeviceSession() : getDeviceAttr()
 }
 
+const getDeviceLabel = async (val: string) => {
+  console.log('val:', val)
+  if (!val) return
+  state.spinning = true
+  const { data } = await DeviceContriller.labelsByLabel(val)
+  state.spinning = false
+  state.dataSource = data.map(item => ({ value: item, label: item }))
+  console.log(data)
+}
+
 const getDeviceSession = async () => {
   if (!state.deviceId) return
   state.loading = true
@@ -202,7 +224,9 @@ const getDeviceAttr = async () => {
 }
 
 const getDeviceList = async () => {
+  state.spinning = true
   const { data } = await DeviceContriller.list()
+  state.spinning = false
   deviceState.dataSource = data
 }
 

+ 0 - 37
src/pages/Iot/device/components/deviceShadow.vue

@@ -71,43 +71,6 @@ const state = reactive({
   shadowList: []
 })
 
-// booleanValue
-// :
-// null
-// dataType
-// :
-// "STRING"
-// dataUnit
-// :
-// null
-// deviceId
-// :
-// "1"
-// doubleValue
-// :
-// null
-// jsonValue
-// :
-// null
-// key
-// :
-// "1"
-// keyLabel
-// :
-// "1"
-// longValue
-// :
-// null
-// scope
-// :
-// null
-// stringValue
-// :
-// "1"
-// ts
-// :
-// 1681181164001
-
 const getDeviceShadow = async () => {
   state.loading = true
   const { data } = await DeviceContriller.getDevicShadow(deviceId)

+ 8 - 3
src/pages/Iot/device/components/overview.vue

@@ -53,7 +53,7 @@
       <!-- <a-col><a-button type="primary" >查看全部属性</a-button></a-col> -->
     </a-row>
 
-    <a-row :gutter="[8, 8]" style="width: 100%;" >
+    <a-row :gutter="[8, 8]" style="width: 100%;margin-top: 20px;" >
       <a-col :span="24" v-if="state.liveDataSource.length === 0" >
         <a-empty></a-empty>
       </a-col>
@@ -66,11 +66,16 @@
           <div class="data">
             <div>{{item.key}}</div>
             <div>{{item.keyLabel}}</div>
+            <div v-if="item.cover" >
+              <a-image
+                :width="50"
+                :src="item.cover"
+              />
+            </div>
             <a-tooltip>
             <template #title><span> {{item[CommonController.dataTypeByKeyMap.get(item.dataType)]}}</span> <span v-if='item.dataUnit'>{{item.dataUnit}}</span></template>
             <span class="data-type" >{{'<'}}  <div class='elip' >{{item[CommonController.dataTypeByKeyMap.get(item.dataType)]}}</div> <span v-if='item.dataUnit'>{{item.dataUnit}}</span> {{'>'}}</span>
           </a-tooltip>
-
             <div>{{dayjs(item.ts).format('YYYY/MM/DD HH:MM:ss')}}</div>
           </div>
         </a-col>
@@ -140,7 +145,7 @@ const ok = async () => {
 
 const getLiveData = async () => {
   const { data } = await DeviceContriller.getLiveData(deviceId)
-  state.liveDataSource = data
+  state.liveDataSource = [{ key: 'participant', label: '耐心', dataUnit: '%', ts: 19283831323218 }]
 }
 
 const { start } = useScheduler(getLiveData, 1000)

+ 8 - 4
src/pages/Iot/model/components/modelDefine.vue

@@ -16,6 +16,9 @@
     @change="changeAttrPage"
   >
     <template #bodyCell="{column, record}">
+      <template v-if="column.key === 'dataType'" >
+        <span>{{ dataTypes.find(item => item.value === record.dataType)?.label }}</span>
+      </template>
       <template v-if="column.key === 'action'">
             <a-space>
                 <a @click="openModel('attrVisible', 'update', record)">修改</a>
@@ -213,6 +216,7 @@ import { nextTick, onMounted, reactive } from 'vue'
 import { Form } from 'ant-design-vue'
 import { useRoute } from 'vue-router'
 import { useId } from '@/hooks'
+import { Item } from 'ant-design-vue/es/menu'
 
 const columns = [
   {
@@ -304,19 +308,19 @@ const useForm = Form.useForm
 const dataTypes = [
   {
     value: 'STRING',
-    label: 'STRING'
+    label: '字符串'
   },
   {
     value: 'LONG',
-    label: 'LONG'
+    label: '长整型'
   },
   {
     value: 'BOOLEAN',
-    label: 'BOOLEAN'
+    label: '布尔'
   },
   {
     value: 'DOUBLE',
-    label: 'DOUBLE'
+    label: '双精度浮点数'
   },
   {
     value: 'JSON',

+ 1 - 1
src/service/request.ts

@@ -6,7 +6,7 @@ import { useUserStore } from '@/store'
 
 export const instance = axios.create({
   baseURL: '',
-  timeout: 10000
+  timeout: 100000
 })
 
 /**