فهرست منبع

feat: 云端下发(cmd参数有可能是多个时存在问题)

lvkun 3 سال پیش
والد
کامیت
ac5d9ebc46
3فایلهای تغییر یافته به همراه172 افزوده شده و 21 حذف شده
  1. 8 0
      src/api/iot/model.ts
  2. 5 1
      src/controller/iot/modelCmd.ts
  3. 159 20
      src/pages/Iot/device/components/cloudview.vue

+ 8 - 0
src/api/iot/model.ts

@@ -173,6 +173,14 @@ export const delModelCmd = (id: string) => {
   })
 }
 
+export const getModelCmdLIst = (params: {modelId: string}) => {
+  return request<IOT.API.CMD.Cmd[]>({
+    url: '/modelCmd/list',
+    method: 'GET',
+    params
+  })
+}
+
 /**
  * 此函数通过 POST 请求将模型插件添加到特定模型 ID。
  * @param data - `data` 参数是一个包含三个属性的对象:

+ 5 - 1
src/controller/iot/modelCmd.ts

@@ -1,5 +1,5 @@
 
-import { addModelCmd, getModelCmd, updateModelCmd, delModelCmd } from '@/api/iot/model'
+import { addModelCmd, getModelCmd, updateModelCmd, delModelCmd, getModelList, getModelCmdLIst } from '@/api/iot/model'
 import { message } from 'ant-design-vue'
 
 export class ModelCmdController {
@@ -21,4 +21,8 @@ export class ModelCmdController {
     await delModelCmd(id)
     message.success('删除成功')
   }
+
+  static async list (params: {modelId: string}) {
+    return await getModelCmdLIst(params)
+  }
 }

+ 159 - 20
src/pages/Iot/device/components/cloudview.vue

@@ -23,10 +23,9 @@
         <a-col> <a-button type="primary" @click="state.visible = true">命令下发</a-button> </a-col>
       </a-row>
     </template>
-
     <a-table
         style="margin-top: 20px;"
-        :columns="columns"
+        :columns="state.tasActive === 'msg' ? columns :cmdColumns"
         :dataSource="state.msgDataSource"
         :loading="state.loading"
       >
@@ -34,12 +33,14 @@
           <template v-if="column.key === 'status'">
             <span>{{ DeviceContriller.deviceMag.get(record.status)?.name }}</span>
           </template>
+          <template v-if="column.key === 'createAt'">
+            {{dayjs(record.createAt).format('YYYY-MM-DD HH:mm:ss')}}
+          </template>
           <template v-if="column.key === 'action'">
             <a @click="openDetailModal(record)" >详情</a>
           </template>
         </template>
-      </a-table>
-
+    </a-table>
   </a-card>
 
   <modal-pro
@@ -79,10 +80,54 @@
     :wrapperCol="{span: 14}"
   >
     <a-form-item
-      label="选择命令"
-      v-bind="validateInfos.msgLabel"
+      label="命令名称"
+      v-bind="validateInfosCmd.cmdId"
     >
-      <a-input v-model:value="msgState.msgLabel" > </a-input>
+      <a-select v-model:value="cmdState.cmdId" >
+        <a-select-option
+          v-for="item in state.cmdList"
+          :key="item.id"
+          :value="item.id"
+        >
+        {{item.cmdLabel}}
+        </a-select-option>
+      </a-select>
+    </a-form-item>
+    <a-form-item
+      label="设置命令参数"
+      v-bind="validateInfos.validateInfosCmd"
+      v-if="cmdDetail?.cmdParams || cmdDetail?.cmdResponses"
+    >
+      <a-row>
+        <a-col>下发参数</a-col>
+        <a-col v-for="(item, index) in cmdDetail?.cmdParams" :key="index" style="margin: 10px 0px;"  >
+          <a-input-group  size="large"  >
+            <a-row :gutter="8" align="middle" >
+              <a-col :span="8">
+                <a-input placeholder="key" v-model:value="item.paramLabel"  disabled />
+              </a-col>
+              <a-col :span="8">
+                <a-input placeholder="value" v-model:value="item.dataUnit" />
+              </a-col>
+            </a-row>
+          </a-input-group>
+        </a-col>
+      </a-row>
+      <a-row>
+        <a-col>下发参数</a-col>
+        <a-col style="margin: 10px 0px;" v-for="(item, index) in cmdDetail?.cmdResponses" :key="index" >
+          <a-input-group  size="large"  >
+            <a-row :gutter="8" align="middle" >
+              <a-col :span="8">
+                <a-input placeholder="key" v-model:value="item.paramLabel" disabled />
+              </a-col>
+              <a-col :span="8">
+                <a-input placeholder="value" v-model:value="item.dataUnit" />
+              </a-col>
+            </a-row>
+          </a-input-group>
+        </a-col>
+      </a-row>
     </a-form-item>
     <a-form-item  label="设置命令参数" >
       产品尚未配置命令,请先去 <a @click="pushProductDetail" >产品详情</a> 定义命令。
@@ -96,18 +141,31 @@
     layout="vertical"
     :visible="state.detailVisible"
     @cancel="state.detailVisible = false"
-    @ok="state.detailVisible = false"
   >
     <a-descriptions
       :column="1"
       :labelStyle="{width: '100px', textAlign: 'left', display: 'block'}"
+      v-if="state.tasActive === 'msg'"
       >
       <a-descriptions-item :span="24" label="状态">{{ DeviceContriller.deviceMag.get(state.msgDetail!.status! )?.name }}</a-descriptions-item>
       <a-descriptions-item :span="24" label="消息 ID">{{state.msgDetail.msgId}}</a-descriptions-item>
       <a-descriptions-item :span="24" label="消息名称">{{state.msgDetail.msgLabel}}</a-descriptions-item>
       <a-descriptions-item :span="24" label="Topic">{{state.msgDetail.topic}}</a-descriptions-item>
       <a-descriptions-item :span="24" label="消息创建时间">
-        {{new Date()}}
+        {{dayjs(state.msgDetail.createAt).format('YYYY-MM-DD HH:mm:ss')}}
+      </a-descriptions-item>
+    </a-descriptions>
+    <a-descriptions
+      :column="1"
+      :labelStyle="{width: '100px', textAlign: 'left', display: 'block'}"
+      v-else
+      >
+      <a-descriptions-item :span="24" label="状态">{{ DeviceContriller.deviceMag.get(state.cmdDetail!.status! )?.name }}</a-descriptions-item>
+      <a-descriptions-item :span="24" label="命令名称">{{state.cmdDetail.cmdLabel}}</a-descriptions-item>
+      <a-descriptions-item :span="24" label="上传参数">{{state.cmdDetail.cmdPayload}}</a-descriptions-item>
+      <!-- <a-descriptions-item :span="24" label="下发参数">{{state.cmdDetail.msgLabel}}</a-descriptions-item> -->
+      <a-descriptions-item :span="24" label="消息创建时间">
+        {{dayjs(state.cmdDetail.createAt).format('YYYY-MM-DD HH:mm:ss')}}
       </a-descriptions-item>
     </a-descriptions>
   </modal-pro>
@@ -116,10 +174,11 @@
 
 <script lang="ts" setup >
 
-import { DeviceContriller } from '@/controller'
+import { DeviceContriller, ModelCmdController } from '@/controller'
 import { computed, onMounted, reactive, ref } from 'vue'
-import { useRoute } from 'vue-router'
-import { Form } from 'ant-design-vue'
+import { useRoute, useRouter } from 'vue-router'
+import { Form, message } from 'ant-design-vue'
+import dayjs from 'dayjs'
 
 const msg = '消息下发不依赖产品模型,平台会以异步方式(消息下发后无需等待设备侧回复响应)下发消息给设备。当前仅MQTT设备支持消息下发。'
 const cmdMsg = '如果设备所属产品定义了命令功能,则您可以通过应用调用平台接口或者操作下面的“下发命令”按钮下发命令。当前MQTT设备仅支持同步命令下发,NB设备仅支持异步命令下发 。'
@@ -155,20 +214,60 @@ const columns = [
   },
   {
     title: '消息创建时间',
-    dataIndex: 'createAt'
+    dataIndex: 'createAt',
+    key: 'createAt'
   },
   {
-    title: '操纵',
+    title: '操作',
+    key: 'action'
+  }
+]
+
+const cmdColumns = [
+  {
+    title: '状态',
+    dataIndex: 'status',
+    key: 'status'
+  },
+  {
+    title: '消息名称',
+    dataIndex: 'cmdLabel'
+  },
+  {
+    title: '消息id',
+    dataIndex: 'msgId'
+  },
+  {
+    title: '消息内容',
+    dataIndex: 'cmdPayload'
+  },
+  {
+    title: '消息创建时间',
+    dataIndex: 'createAt',
+    key: 'createAt'
+  },
+  {
+    title: '操作',
     key: 'action'
   }
 ]
 
 const useForm = Form.useForm
 const route = useRoute()
+const router = useRouter()
+
 const deviceId = route.query.id as string
 
 const tipMessage = computed(() => state.tasActive === 'msg' ? msg : cmdMsg)
 
+const cmdDetail = computed(() => state.cmdList.find(item => item.id === cmdState.cmdId))
+
+const cmdParametersTrans = computed(() => {
+  return Object.keys(cmdState.cmdParameters).map(key => {
+    return { key: key, value: cmdState.cmdParameters[key] }
+  })
+})
+
 const state = reactive<{
   tasActive: 'msg' | 'cmd',
   msgDataSource: (IOT.API.DEVICE.Msg | IOT.API.DEVICE.Cmd)[],
@@ -176,13 +275,19 @@ const state = reactive<{
   loading: boolean,
   detailVisible: boolean,
   msgDetail: Partial<IOT.API.DEVICE.Msg >
+  cmdDetail: Partial<IOT.API.DEVICE.Cmd>
+    cmdList: IOT.API.CMD.Cmd[],
+    deviceDetail: IOT.API.DEVICE.Device | null
     }>({
       tasActive: 'msg',
       msgDataSource: [],
       visible: false,
       loading: false,
       detailVisible: false,
-      msgDetail: {}
+      msgDetail: {},
+      cmdDetail: {},
+      cmdList: [],
+      deviceDetail: null
     })
 
 const msgState = reactive({
@@ -192,10 +297,16 @@ const msgState = reactive({
   topic: ''
 })
 
-const cmdState = reactive({
+const cmdState = reactive<{
+  cmdId: string
+  deviceId: string,
+  cmdLabel: string,
+  cmdParameters: {key: string, value: string}[]
+}>({
+  cmdId: '',
   deviceId: deviceId,
   cmdLabel: '',
-  cmdParameters: {}
+  cmdParameters: []
 })
 
 const { resetFields, validate, validateInfos } = useForm(msgState, reactive({
@@ -204,10 +315,16 @@ const { resetFields, validate, validateInfos } = useForm(msgState, reactive({
 }))
 
 const { resetFields: resetFieldsCmd, validate: validateCmd, validateInfos: validateInfosCmd } = useForm(cmdState, reactive({
+  cmdId: [{ required: true, message: '请填写命令名称' }]
 }))
 
+const getModelCmdList = async () => {
+  const { data } = await ModelCmdController.list({ modelId: state.deviceDetail!.modelId })
+  state.cmdList = data
+}
+
 const pushProductDetail = () => {
-  console.log('pushProductDetail')
+  router.push({ path: '/product/detail', query: { id: state.deviceDetail!.modelId } })
 }
 
 const ok = () => {
@@ -219,7 +336,22 @@ const ok = () => {
     })
   } else {
     validateCmd().then(async () => {
-      await DeviceContriller.addDeviceCmd(cmdState)
+      const _cmdParameters: Record<string, string> = {}
+      cmdState.cmdParameters.forEach(item => {
+        _cmdParameters[item.key] = item.value
+      })
+      // cmd的cmdParams有可能是多个
+      // Object.keys(cmdDetail.value.cmdParams).forEach(item => {
+      //   _cmdParameters[cmdDetail.value.cmdParams[item.key]] = cmdDetail.value.cmdParams[]
+      // })
+      const $params = {
+        ...cmdState,
+        cmdLabel: cmdDetail.value?.cmdLabel,
+        cmdParameters: _cmdParameters
+
+        { ...cmdDetail.value?.cmdParams, ...cmdDetail.value?.cmdResponses }
+      }
+      await DeviceContriller.addDeviceCmd($params)
       state.visible = false
       getDeviceMsgList()
     })
@@ -227,8 +359,9 @@ const ok = () => {
 }
 
 const openDetailModal = (record: IOT.API.DEVICE.Msg) => {
+  const key = state.tasActive === 'cmd' ? 'cmdDetail' : 'msgDetail'
   state.detailVisible = true
-  state.msgDetail = record
+  state[key] = record
 }
 
 const getDeviceMsgList = async () => {
@@ -237,6 +370,11 @@ const getDeviceMsgList = async () => {
   state.loading = false
 }
 
+const getDeviceById = async () => {
+  state.deviceDetail = await DeviceContriller.byId(deviceId)
+  getModelCmdList()
+}
+
 const onTabChange = (value: 'msg' | 'cmd') => {
   state.tasActive = value
   getDeviceMsgList()
@@ -244,6 +382,7 @@ const onTabChange = (value: 'msg' | 'cmd') => {
 
 onMounted(() => {
   getDeviceMsgList()
+  getDeviceById()
 })
 </script>