|
|
@@ -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>
|
|
|
|