【功能完善】IoT:增加 device config 配置

This commit is contained in:
YunaiV 2025-03-13 08:18:12 +08:00
parent 6636068bd5
commit 3685e438fa
4 changed files with 64 additions and 61 deletions

View File

@ -27,6 +27,7 @@ export interface DeviceVO {
areaId: number // 地区编码 areaId: number // 地区编码
address: string // 设备详细地址 address: string // 设备详细地址
serialNumber: string // 设备序列号 serialNumber: string // 设备序列号
config: string // 设备配置
groupIds?: number[] // 添加分组 ID groupIds?: number[] // 添加分组 ID
} }
@ -72,7 +73,7 @@ export interface IotDeviceDownstreamReqVO {
data: any // 请求参数 data: any // 请求参数
} }
// MQTT连接参数 VO // MQTT 连接参数 VO
export interface MqttConnectionParamsVO { export interface MqttConnectionParamsVO {
mqttClientId: string // MQTT 客户端 ID mqttClientId: string // MQTT 客户端 ID
mqttUsername: string // MQTT 用户名 mqttUsername: string // MQTT 用户名

View File

@ -11,9 +11,8 @@
<!-- JSON 编辑器读模式 --> <!-- JSON 编辑器读模式 -->
<Vue3Jsoneditor <Vue3Jsoneditor
ref="editor"
v-if="isEditing" v-if="isEditing"
v-model="deviceConfigState" v-model="config"
:options="editorOptions" :options="editorOptions"
height="500px" height="500px"
currentMode="code" currentMode="code"
@ -21,62 +20,48 @@
/> />
<!-- JSON 编辑器写模式 --> <!-- JSON 编辑器写模式 -->
<Vue3Jsoneditor <Vue3Jsoneditor
ref="editor"
v-else v-else
v-model="deviceConfigState" v-model="config"
:options="editorOptions" :options="editorOptions"
height="500px" height="500px"
currentMode="view" currentMode="view"
v-loading.fullscreen.lock="loading" v-loading.fullscreen.lock="loading"
@error="onError" @error="onError"
/> />
<div class="flex justify-center mt-24"> <div class="mt-5 text-center">
<el-button v-if="isEditing" @click="cancelEdit">取消</el-button> <el-button v-if="isEditing" @click="cancelEdit">取消</el-button>
<el-button v-if="isEditing" type="primary" @click="saveConfig">保存</el-button> <el-button v-if="isEditing" type="primary" @click="saveConfig" :disabled="hasJsonError"
>保存</el-button
>
<el-button v-else @click="enableEdit">编辑</el-button> <el-button v-else @click="enableEdit">编辑</el-button>
<!-- TODO @芋艿缺一个下发按钮 -->
</div> </div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, computed } from 'vue'
import Vue3Jsoneditor from 'v3-jsoneditor/src/Vue3Jsoneditor.vue' import Vue3Jsoneditor from 'v3-jsoneditor/src/Vue3Jsoneditor.vue'
import { DeviceApi } from '@/api/iot/device/device/index' import { DeviceApi, DeviceVO } from '@/api/iot/device/device'
import { useTagsViewStore } from '@/store/modules/tagsView' import { jsonParse } from '@/utils'
import { DeviceVO } from '../../../../../api/iot/device/device/index';
const props = defineProps<{
device: DeviceVO
}>()
const emit = defineEmits<{
(e: 'success'): void // success
}>()
const route = useRoute()
const message = useMessage() const message = useMessage()
const { delView } = useTagsViewStore() // const loading = ref(false) //
const { currentRoute } = useRouter() // const config = ref<any>({}) // config
const id = Number(route.params.id) // const hasJsonError = ref(false) // JSON
const loading = ref(true) //
const deviceConfigState = ref({}) //
/** 监听 props.device 的变化,只更新 config 字段 */
// watchEffect(() => {
const getDeviceConfig = async (id: number) => { config.value = jsonParse(props.device.config)
try {
loading.value = true
const res = await DeviceApi.getDevice(id)
deviceConfigState.value = res
} catch (error) {
console.error(error)
} finally {
loading.value = false
}
}
onMounted(async () => {
if (!id) {
message.warning('参数错误,产品不能为空!')
delView(unref(currentRoute))
return
}
await getDeviceConfig(id)
}) })
const isEditing = ref(false) // const isEditing = ref(false) //
const editorOptions = computed(() => ({ const editorOptions = computed(() => ({
mainMenuBar: false, mainMenuBar: false,
@ -87,40 +72,48 @@ const editorOptions = computed(() => ({
/** 启用编辑模式的函数 */ /** 启用编辑模式的函数 */
const enableEdit = () => { const enableEdit = () => {
isEditing.value = true isEditing.value = true
hasJsonError.value = false //
} }
/** 取消编辑的函数 */ /** 取消编辑的函数 */
const cancelEdit = () => { const cancelEdit = () => {
config.value = jsonParse(props.device.config)
isEditing.value = false isEditing.value = false
// hasJsonError.value = false //
console.log('取消编辑')
} }
/** 保存配置的函数 */ /** 保存配置的函数 */
const saveConfig = async () => { const saveConfig = async () => {
const params = { if (hasJsonError.value) {
...deviceConfigState.value message.error('JSON格式错误请修正后再提交')
} as DeviceVO return
await updateDeviceConfig(params) }
await updateDeviceConfig()
isEditing.value = false isEditing.value = false
} }
/** 处理 JSON 编辑器错误的函数 */ /** 更新设备配置 */
const onError = (e: any) => { const updateDeviceConfig = async () => {
console.log('onError', e)
}
//
const updateDeviceConfig = async (params: DeviceVO) => {
try { try {
//
loading.value = true loading.value = true
await DeviceApi.updateDevice(params) await DeviceApi.updateDevice({
await getDeviceConfig(id) id: props.device.id,
config: JSON.stringify(config.value)
} as DeviceVO)
message.success('更新成功!') message.success('更新成功!')
// success
emit('success')
} catch (error) { } catch (error) {
console.error(error) console.error(error)
} finally { } finally {
loading.value = false loading.value = false
} }
} }
/** 处理 JSON 编辑器错误的函数 */
const onError = (e: any) => {
console.log('onError', e)
hasJsonError.value = true
}
</script> </script>

View File

@ -63,7 +63,11 @@
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item label="passwd"> <el-form-item label="passwd">
<el-input v-model="mqttParams.mqttPassword" readonly :type="passwordVisible ? 'text' : 'password'"> <el-input
v-model="mqttParams.mqttPassword"
readonly
:type="passwordVisible ? 'text' : 'password'"
>
<template #append> <template #append>
<el-button @click="passwordVisible = !passwordVisible" type="primary"> <el-button @click="passwordVisible = !passwordVisible" type="primary">
<Icon :icon="passwordVisible ? 'ph:eye-slash' : 'ph:eye'" /> <Icon :icon="passwordVisible ? 'ph:eye-slash' : 'ph:eye'" />
@ -117,13 +121,14 @@ const copyToClipboard = async (text: string) => {
const openMqttParams = async () => { const openMqttParams = async () => {
try { try {
const res = await DeviceApi.getMqttConnectionParams(device.id) const res = await DeviceApi.getMqttConnectionParams(device.id)
// API
// API
mqttParams.value = { mqttParams.value = {
mqttClientId: res.mqttClientId || 'N/A', mqttClientId: res.mqttClientId || 'N/A',
mqttUsername: res.mqttUsername || 'N/A', mqttUsername: res.mqttUsername || 'N/A',
mqttPassword: res.mqttPassword || 'N/A' mqttPassword: res.mqttPassword || 'N/A'
} }
// MQTT
mqttDialogVisible.value = true mqttDialogVisible.value = true
} catch (error) { } catch (error) {
console.error('获取MQTT连接参数出错', error) console.error('获取MQTT连接参数出错', error)

View File

@ -27,7 +27,11 @@
/> />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="设备配置" name="config"> <el-tab-pane label="设备配置" name="config">
<DeviceDetailConfig /> <DeviceDetailConfig
v-if="activeTab === 'config'"
:device="device"
@success="getDeviceData"
/>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
</el-col> </el-col>
@ -41,7 +45,7 @@ import DeviceDetailsInfo from './DeviceDetailsInfo.vue'
import DeviceDetailsModel from './DeviceDetailsModel.vue' import DeviceDetailsModel from './DeviceDetailsModel.vue'
import DeviceDetailsLog from './DeviceDetailsLog.vue' import DeviceDetailsLog from './DeviceDetailsLog.vue'
import DeviceDetailsSimulator from './DeviceDetailsSimulator.vue' import DeviceDetailsSimulator from './DeviceDetailsSimulator.vue'
import DeviceDetailConfig from './DeviceDetailConfig.vue'; import DeviceDetailConfig from './DeviceDetailConfig.vue'
defineOptions({ name: 'IoTDeviceDetail' }) defineOptions({ name: 'IoTDeviceDetail' })
@ -54,7 +58,7 @@ const device = ref<DeviceVO>({} as DeviceVO) // 设备详情
const activeTab = ref('info') // const activeTab = ref('info') //
/** 获取设备详情 */ /** 获取设备详情 */
const getDeviceData = async (id: number) => { const getDeviceData = async () => {
loading.value = true loading.value = true
try { try {
device.value = await DeviceApi.getDevice(id) device.value = await DeviceApi.getDevice(id)
@ -78,7 +82,7 @@ onMounted(async () => {
delView(unref(currentRoute)) delView(unref(currentRoute))
return return
} }
await getDeviceData(id) await getDeviceData()
activeTab.value = (route.query.tab as string) || 'info' activeTab.value = (route.query.tab as string) || 'info'
}) })
</script> </script>