Pārlūkot izejas kodu

feat: 数据统计

lvkun 3 gadi atpakaļ
vecāks
revīzija
46adc910a5

+ 3 - 3
src/api/iot/devOps.ts

@@ -28,9 +28,9 @@ export const getNoticePage = (params: { page: number, pageSize: number}) => {
   })
 }
 
-export const getStatsPage = () => {
-  return request<{label: string, value: string}[]>({
-    url: '/stats/page',
+export const getStatsList = () => {
+  return request<{label: string, dataValue: string}[]>({
+    url: '/stats',
     method: 'GET'
   })
 }

+ 14 - 2
src/controller/iot/devOps.ts

@@ -1,6 +1,18 @@
-import { getNoticePage, getStatsPage, getWarnPage } from '@/api/iot/devOps'
+import { getNoticePage, getStatsList, getWarnPage } from '@/api/iot/devOps'
 
 export class DevOpsController {
+  static statsMap = new Map([
+    ['transportSuccessCounter', { name: '设备上报成功消息数', key: 'transportSuccessCounter' }],
+    ['transportFailCounter', { name: '设备上报失败消息数', key: 'transportFailCounter' }],
+    ['transportTotalCounter', { name: '设备上报总消息数', key: 'transportTotalCounter' }],
+    ['toTransportSuccessCounter', { name: '发送到设备成功消息数', key: 'toTransportSuccessCounter' }],
+    ['toTransportFailCounter', { name: '发送到设备失败消息数', key: 'toTransportFailCounter' }],
+    ['toTransportTotalCounter', { name: '发送到设备总消息数', key: 'toTransportTotalCounter' }],
+    ['transportReqSuccessCounter', { name: '设备请求成功消息数', key: 'transportReqSuccessCounter' }],
+    ['transportReqFailCounter', { name: '设备请求失败消息数', key: 'transportReqFailCounter' }],
+    ['transportReqTotalCounter', { name: '设备请求总消息数', key: 'transportReqTotalCounter' }]
+  ])
+
   static async pageWarn (params: {duration: number, page: number, pageSize: number}) {
     return await getWarnPage(params)
   }
@@ -10,6 +22,6 @@ export class DevOpsController {
   }
 
   static async pageStats () {
-    return await getStatsPage()
+    return await getStatsList()
   }
 }

+ 1 - 1
src/pages/Iot/dataServer/history.vue

@@ -31,7 +31,7 @@
     :columns="columns"
     :loading="state.loading"
     :data-source="state.dataSource"
-    :pagenation="queryParams"
+    :pagination="queryParams"
     @change="changePage"
   >
 

+ 1 - 1
src/pages/Iot/dataServer/openApi.vue

@@ -13,7 +13,7 @@
     :loading="state.loading"
     :data-source="state.dataSource"
     style="margin-top: 20px;"
-    :pagenation="queryParams"
+    :pagination="queryParams"
     @change="changePage"
   >
   <template #bodyCell="{column, record}" >

+ 147 - 15
src/pages/Iot/devOps/onlineTest.vue

@@ -2,6 +2,9 @@
     <a-row>
         <a-col :span="13">
             <a-card title="调试输出" style="background-color: #eef0f5;">
+                <template #extra >
+                    <a-button type="primary" @click="clearLog" >清空日志</a-button>
+                </template>
                 <a-row>
                     <a-col :span="6" class="app-imitate" >应用模拟器</a-col>
                     <a-col :span="3" class="app-to-platform" >
@@ -17,10 +20,12 @@
                             <div class="border-dot-bottom">数据上报</div>
                         </div>
                     </a-col>
-                    <a-col :span="6" class="device-imitate" >设备模拟器</a-col>
+                    <a-col :span="6" class="device-imitate" >真实设备</a-col>
                 </a-row>
                 <a-row style="height: 505px;width: 100%" justify="space-between"   >
-                    <a-col :span="11" style="height: 100%;background-color: #fff" ></a-col>
+                    <a-col :span="11" style="height: 100%;background-color: #fff" >
+                        <div v-for="(item, index) in state.eventList" :key="index" >{{JSON.stringify(item)}}</div>
+                    </a-col>
                     <a-col :span="11" style='background-color: #fff;eight: 100%' ></a-col>
                 </a-row>
             </a-card>
@@ -28,17 +33,63 @@
         <a-col :span="9">
             <a-row justify='end' >
                 <a-col>
-                    <a-button type="link" >{{state.device.deviceLabel ? state.device.deviceLabel : "尚未选择产品"}}</a-button>
+                    <a-button type="link" >{{state.device.deviceLabel ? state.device.deviceLabel : "尚未选择设备"}}</a-button>
                     <a-button type="primary" @click="state.drawerVisible = true" >选择设备</a-button>
                 </a-col>
             </a-row>
+            <!-- :tab-list="tabListNoTitle"
+                :active-tab-key="state.activeKey"
+                @tabChange="onTabChange" -->
             <a-card
+                title="应用模拟器"
                 style="width: 100%;height: 100%;margin-top: 10px;"
-                :tab-list="tabListNoTitle"
-                :active-tab-key="state.activeKey"
-                @tabChange="onTabChange"
+
             >
-                <div></div>
+                <a-row :gutter="[8, 8]">
+                    <a-col span="24" ><a-tag color="blue" style="scale: 1.2;" >命令下发</a-tag></a-col>
+                    <a-col class="subtitle"  span="24"  >
+                        应用模拟器可根据产品定义向设备下发命令。<br/>
+                        若您使用了图形化开发的编解码插件,为获得正确的编码结果,下发命令时,请携带所有在插件中定义的字段,且每个命令的长度需小于512个字节
+                    </a-col>
+                    <a-col  span="24" v-if="false" >
+                        <a-form
+                            :labelCol="{span: 2}"
+                            :wrapperCol="{span: 14}"
+                        >
+                            <a-form-item label="产品" >
+                                <a-select v-model:value="state.modelId" >
+                                    <a-select-option
+                                        v-for="item in state.modelSouce"
+                                        :key="item.id"
+                                        :value="item.id"
+                                    >
+                                        {{item.modelLabel}}
+                                    </a-select-option>
+                                </a-select>
+                            </a-form-item>
+                            <a-form-item label="命令" >
+                                <a-select v-model:value="state.cmdId" >
+                                    <a-select-option
+                                        v-for="item in state.modelCmdList"
+                                        :key="item.id"
+                                        :value="item.id"
+                                    >
+                                        {{item.cmdLabel}}
+                                    </a-select-option>
+                                </a-select>
+                            </a-form-item>
+
+                            <span  v-if="cmdDetail?.cmdParams.length" >
+                                <a-form-item :label="item.paramLabel"  v-for="(item, index) in cmdDetail?.cmdParams" :key="item.id" >
+                                    <a-input v-model:value="item.dataUnit" ></a-input>
+                                </a-form-item>
+                            </span>
+                        </a-form>
+                    </a-col>
+                </a-row>
+                <template #extra >
+                    <a-button type="primary" @click="addEventList">发送</a-button>
+                </template>
             </a-card>
         </a-col>
     </a-row>
@@ -64,31 +115,72 @@
   </a-drawer>
 </template>
 <script lang='ts' setup >
-import { reactive, ref } from 'vue'
+import { computed, onMounted, reactive, ref, watch } from 'vue'
 import SelectDevice from '@/pages/iot/rule/components/selectDevice.vue'
 import { message } from 'ant-design-vue'
+import { DeviceContriller, EventController, ModelCmdController, ModelController } from '@/controller'
+import { useRoute } from 'vue-router'
+import dayjs from 'dayjs'
+import { useScheduler } from '@/hooks'
+
+const route = useRoute()
 
 const tabListNoTitle = [
   {
     key: 'app',
     tab: '应用模拟器'
-  },
-  {
-    key: 'device',
-    tab: '设备模拟器'
   }
+//   {
+//     key: 'device',
+//     tab: '设备模拟器'
+//   }
 ]
 
 const selectDeviceRef = ref()
 
-const state = reactive({
+const state = reactive<{
+    activeKey: 'app',
+    drawerVisible: boolean,
+    modelSouce: IOT.API.MODEL.Model[],
+    modelId: string,
+    cmdId: string,
+    modelCmdList: IOT.API.CMD.Cmd[],
+    eventList: any,
+    startTime: number,
+    lastId: string
+    device: {
+        id: string
+        deviceLabel: string
+    }
+}>({
   activeKey: 'app',
   drawerVisible: false,
+  modelSouce: [],
+  modelId: '',
+  cmdId: '',
+  modelCmdList: [],
+  eventList: [],
+  startTime: new Date().getTime(),
+  lastId: '',
   device: {
+    id: '1',
     deviceLabel: ''
   }
 })
 
+watch(() => state.modelId, () => getModelCmdList())
+
+const cmdDetail = computed(() => {
+  const detail = state.modelCmdList.find(item => item.id === state.cmdId)
+
+  return detail
+})
+
+const clearLog = () => {
+  state.eventList = []
+  message.success('清除成功')
+}
+
 const handleSelectDevice = () => {
   const _device = selectDeviceRef.value.getSelectDevice()
   if (_device) {
@@ -99,11 +191,51 @@ const handleSelectDevice = () => {
   }
 }
 
-const onTabChange = (key: string) => {
-  state.activeKey = key
+const getModelCmdList = async () => {
+  const { data } = await ModelCmdController.list({ modelId: state.modelId })
+  state.modelCmdList = data
+}
+
+const getEventList = async () => {
+  const { data, sum } = await EventController.list({ deviceId: state.device.id, startTime: state.startTime, lastId: state.lastId })
+  state.eventList.push(data)
+}
+
+const { start, stop } = useScheduler(getEventList, 2000)
+
+const getEventTraceList = async () => {
+  const data = await EventController.listTrace({ deviceId: state.device.id }) as unknown as Number
+  //   state.formatStartTime = data ? dayjs(data).format('YYYY-MM-DD hh:mm:ss') : ''
+  start()
+}
+
+const addEventList = async () => {
+  stop()
+  await EventController.addTrace({ deviceId: state.device.id })
+  getEventTraceList()
 }
+
+const getDeviceById = async () => {
+  const data = await DeviceContriller.byId(state.device.id)
+  state.device = data
+}
+
+onMounted(() => {
+//   const deviceId = route.query.id as string
+  const deviceId = 1
+  if (deviceId) {
+    state.device.id = deviceId
+    getDeviceById()
+  }
+})
 </script>
 <style lang='less' scoped >
+
+@import "~@/styles/theme.less";
+.subtitle {
+  font-size: 12px;
+  color: @label-color;
+}
 .app-imitate {
     width: 250px;
     height: 80px;

+ 32 - 1
src/pages/Iot/devOps/statistReport.vue

@@ -1,9 +1,40 @@
 <template>
 <a-card>
-  <a-empty />
+  <a-row :gutter="[8, 8]" justify="space-between" >
+    <a-col :lg="5" :sm="1" :md="3"  v-for="item in state.statsSource" :key="item.key">
+      <a-card style="width: 300px" :title="item.name" >
+        <div style="font-size: 18px;" >{{item.value}}</div>
+      </a-card>
+    </a-col>
+  </a-row>
 </a-card>
 </template>
 <script lang='ts' setup >
+import { DevOpsController } from '@/controller/iot/devOps'
+import { onMounted, reactive } from 'vue'
+
+const state = reactive<{
+  statsSource: {key: string, name: string, value: string}[]
+}>({
+  statsSource: []
+})
+
+const getStats = async () => {
+  const { data } = await DevOpsController.pageStats()
+  state.statsSource = data.map(item => {
+    return {
+      key: item.label,
+      name: DevOpsController.statsMap.get(item.label)?.name,
+      value: item.dataValue
+    }
+  })
+  console.log(state.statsSource)
+}
+
+onMounted(() => {
+  getStats()
+})
+
 </script>
 <style lang='less' scoped >
 </style>

+ 9 - 0
src/pages/Iot/rule/components/selectDevice.vue

@@ -18,11 +18,13 @@
     :loading="state.loading"
     :columns="columns"
     :data-source="state.dataSource"
+    :pagination="state.queryParams"
     :rowSelection="{
       type: 'radio',
       selectedRowKeys: state.selectedRowKeys,
       onChange: onChangeRowKeys
     }"
+    @change="changePage"
   />
 </a-card>
 </template>
@@ -67,6 +69,11 @@ const state = reactive({
   }
 })
 
+const changePage = ({ current }) => {
+  state.queryParams.page = current
+  getDevicePage()
+}
+
 const onChangeRowKeys = (rowKeys: string[]) => {
   console.log(rowKeys)
   state.selectedRowKeys = rowKeys
@@ -77,10 +84,12 @@ const getDevicePage = async () => {
   const { data, sum } = await DeviceContriller.page(state.queryParams)
   state.dataSource = data
   state.queryParams.total = sum
+  console.log('sum:', sum)
 }
 
 defineExpose({
   getSelectDevice: () => state.dataSource.find(item => item.id === state.selectedRowKeys[0])
+
 })
 
 onMounted(() => {

+ 1 - 1
src/pages/Iot/rule/forwardRule.vue

@@ -21,7 +21,7 @@
     :columns="columns"
     :data-source="state.dataSource"
     :loading="state.loading"
-    :pagenation="queryParams"
+    :pagination="queryParams"
     @change="changePage"
   >
     <template #bodyCell="{column, record}" >

+ 1 - 1
src/pages/Iot/rule/linkRule.vue

@@ -15,7 +15,7 @@
       :columns="columns"
       :data-source="state.dataSource"
       :loading="state.loading"
-      :pagenation="queryParamsState"
+      :pagination="queryParamsState"
       @change="changePage"
     >
     <template #bodyCell="{column, record}" >

+ 2 - 0
src/type/iot.d.ts

@@ -48,8 +48,10 @@ declare namespace IOT {
 
     namespace CMD {
       interface Cmd {
+        id: string,
         'cmdLabel': string,
         'cmdParams': {
+          id: string
           'paramLabel': string,
           'dataType': string,
           'required': boolean,