gaoluyang
2026-06-24 712aa51536236d43e87273e4ce45ac5691dffad8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
<!-- 设备配置 -->
<script lang="ts" setup>
import type { IotDeviceApi } from '#/api/iot/device/device';
 
import { computed, ref, watchEffect } from 'vue';
 
import { IotDeviceMessageMethodEnum } from '..\..\..\..\..\..\packages\constants\src';
 
import { Alert, Button, message, Popconfirm, Textarea } from 'ant-design-vue';
 
import { sendDeviceMessage, updateDevice } from '#/api/iot/device/device';
 
const props = defineProps<{
  device: IotDeviceApi.Device;
}>();
 
const emit = defineEmits<{
  (e: 'success'): void; // 定义 success 事件,不需要参数
}>();
 
const loading = ref(false); // 加载中
const pushLoading = ref(false); // 推送加载中
const saveLoading = ref(false); // 保存加载中
const config = ref<any>({}); // 只存储 config 字段
const configString = ref(''); // 用于编辑器的字符串格式
 
/** 监听 props.device 的变化,只更新 config 字段 */
watchEffect(() => {
  try {
    config.value = props.device.config ? JSON.parse(props.device.config) : {};
    // 将对象转换为格式化的 JSON 字符串
    configString.value = JSON.stringify(config.value, null, 2);
  } catch {
    config.value = {};
    configString.value = '{}';
  }
});
 
const isEditing = ref(false); // 编辑状态
 
/** 格式化的配置用于只读展示 */
const formattedConfig = computed(() => {
  try {
    if (typeof config.value === 'string') {
      return JSON.stringify(JSON.parse(config.value), null, 2);
    }
    return JSON.stringify(config.value, null, 2);
  } catch {
    return JSON.stringify(config.value, null, 2);
  }
});
 
/** 启用编辑模式的函数 */
function handleEdit() {
  isEditing.value = true;
  // 重新同步编辑器内容
  configString.value = JSON.stringify(config.value, null, 2);
}
 
/** 取消编辑的函数 */
function handleCancelEdit() {
  try {
    config.value = props.device.config ? JSON.parse(props.device.config) : {};
    configString.value = JSON.stringify(config.value, null, 2);
  } catch {
    config.value = {};
    configString.value = '{}';
  }
  isEditing.value = false;
}
 
/** 保存配置的函数 */
async function saveConfig() {
  // 验证 JSON 格式
  try {
    config.value = JSON.parse(configString.value);
  } catch (error) {
    console.error('JSON格式错误:', error);
    message.error('JSON格式错误,请修正后再提交!');
    return;
  }
  saveLoading.value = true;
  try {
    await updateDeviceConfig();
    isEditing.value = false;
  } finally {
    saveLoading.value = false;
  }
}
 
/** 配置推送处理函数 */
async function handleConfigPush() {
  pushLoading.value = true;
  try {
    // 调用配置推送接口
    await sendDeviceMessage({
      deviceId: props.device.id!,
      method: IotDeviceMessageMethodEnum.CONFIG_PUSH.method,
      params: config.value,
    });
    // 提示成功
    message.success('配置推送成功!');
  } finally {
    pushLoading.value = false;
  }
}
 
/** 更新设备配置 */
async function updateDeviceConfig() {
  try {
    // 提交请求
    loading.value = true;
    await updateDevice({
      id: props.device.id,
      config: JSON.stringify(config.value),
    } as IotDeviceApi.Device);
    message.success('更新成功!');
    // 触发 success 事件
    emit('success');
  } finally {
    loading.value = false;
  }
}
</script>
 
<template>
  <div>
    <!-- 使用说明提示 -->
    <Alert
      class="!mb-4"
      description="如需编辑文件,请点击下方编辑按钮"
      message="支持远程更新设备的配置文件(JSON 格式),可以在下方编辑配置模板,对设备的系统参数、网络参数等进行远程配置。配置完成后,需点击「配置推送」按钮,设备即可进行远程配置。"
      show-icon
      type="info"
    />
 
    <!-- 代码视图 - 只读展示 -->
    <pre
      v-if="!isEditing"
      class="m-0 h-[460px] overflow-y-auto whitespace-pre-wrap break-words rounded border border-[#d9d9d9] bg-[#f5f5f5] p-3 font-mono text-[13px] leading-normal text-[#333] dark:border-[#3a3a3a] dark:bg-[#1a1a1a] dark:text-gray-300"
      v-text="formattedConfig"
    ></pre>
 
    <!-- 编辑器视图 - 可编辑 -->
    <Textarea
      v-else
      v-model:value="configString"
      class="!h-[460px] font-mono text-[13px]"
      placeholder="请输入 JSON 格式的配置信息"
    />
 
    <!-- 操作按钮 -->
    <div class="mt-4 flex justify-center gap-2">
      <Button v-if="isEditing" @click="handleCancelEdit">取消</Button>
      <Button
        v-if="isEditing"
        :loading="saveLoading"
        type="primary"
        @click="saveConfig"
      >
        保存
      </Button>
      <Button v-else @click="handleEdit">编辑</Button>
      <Popconfirm
        v-if="!isEditing"
        title="确定要推送配置到设备吗?此操作将远程更新设备配置。"
        @confirm="handleConfigPush"
      >
        <Button :loading="pushLoading" type="primary"> 配置推送 </Button>
      </Popconfirm>
    </div>
  </div>
</template>