diff --git a/app/src/main/ipc-handlers.js b/app/src/main/ipc-handlers.js
index a738149..f566162 100644
--- a/app/src/main/ipc-handlers.js
+++ b/app/src/main/ipc-handlers.js
@@ -58,6 +58,14 @@ export function registerIpcHandlers() {
return true;
});
+ ipcMain.handle('mqtt:export-servers', () => {
+ return mqttManager.exportServers();
+ });
+
+ ipcMain.handle('mqtt:import-servers', (_, serverList) => {
+ return mqttManager.importServers(serverList);
+ });
+
// ==================== 连接管理 ====================
ipcMain.handle('mqtt:connect', (_, id) => {
diff --git a/app/src/main/mqtt-manager.js b/app/src/main/mqtt-manager.js
index 7bccea7..cd13303 100644
--- a/app/src/main/mqtt-manager.js
+++ b/app/src/main/mqtt-manager.js
@@ -164,23 +164,47 @@ class MqttManager {
return this.servers.get(id) || null;
}
+ getServerConfigSchema() {
+ return {
+ name: (c, e) => c.name ?? e?.name,
+ host: (c, e) => c.host ?? e?.host,
+ port: (c, e) => c.port || e?.port || 1883,
+ protocol: (c, e) => c.protocol || e?.protocol || 'mqtt',
+ clientId: (c, e) => c.clientId || e?.clientId || 'frost_' + Math.random().toString(36).slice(2, 10),
+ username: (c, e) => c.username ?? e?.username ?? '',
+ password: (c, e, opts) => c.password ?? (opts.keepExistingPassword ? e?.password : '') ?? '',
+ keepAlive: (c, e) => c.keepAlive || e?.keepAlive || 60,
+ cleanSession: (c) => c.cleanSession !== false,
+ connectTimeout: (c, e) => c.connectTimeout ?? e?.connectTimeout ?? 10000,
+ reconnect: (c) => c.reconnect !== false,
+ reconnectInterval: (c, e) => c.reconnectInterval ?? e?.reconnectInterval ?? 5000,
+ };
+ }
+
+ buildServerFields(config, existing = null, options = {}) {
+ let schema = this.getServerConfigSchema();
+ let fields = {};
+ for (let key of Object.keys(schema)) {
+ fields[key] = schema[key](config, existing, options);
+ }
+ return fields;
+ }
+
+ buildTopic(t) {
+ return {
+ id: t.id || 'topic_' + Date.now() + '_' + Math.random().toString(36).slice(2, 6),
+ topic: t.topic,
+ qos: t.qos ?? 1,
+ subscribed: false,
+ };
+ }
+
addServer(config) {
let id = 'srv_' + Date.now() + '_' + Math.random().toString(36).slice(2, 6);
let server = {
id,
- name: config.name,
- host: config.host,
- port: config.port || 1883,
- protocol: config.protocol || 'mqtt',
- clientId: config.clientId || 'frost_' + Math.random().toString(36).slice(2, 10),
- username: config.username || '',
- password: config.password || '',
- keepAlive: config.keepAlive || 60,
- cleanSession: config.cleanSession !== false,
- connectTimeout: config.connectTimeout ?? 10000,
- reconnect: config.reconnect !== false,
- reconnectInterval: config.reconnectInterval ?? 5000,
+ ...this.buildServerFields(config),
status: 'disconnected',
topics: [],
};
@@ -202,23 +226,7 @@ class MqttManager {
return null;
}
- Object.assign(server, {
- name: config.name,
- host: config.host,
- port: config.port || 1883,
- protocol: config.protocol || 'mqtt',
- clientId: config.clientId || server.clientId,
- username: config.username || '',
- keepAlive: config.keepAlive || 60,
- cleanSession: config.cleanSession !== false,
- connectTimeout: config.connectTimeout ?? server.connectTimeout ?? 10000,
- reconnect: config.reconnect !== false,
- reconnectInterval: config.reconnectInterval ?? server.reconnectInterval ?? 5000,
- });
-
- if (config.password) {
- server.password = config.password;
- }
+ Object.assign(server, this.buildServerFields(config, server, { keepExistingPassword: true }));
this.saveData();
@@ -235,6 +243,63 @@ class MqttManager {
this.saveData();
}
+ exportServers() {
+ let schemaKeys = Object.keys(this.getServerConfigSchema());
+ return Array.from(this.servers.values()).map((s) => {
+ let exported = {};
+ for (let key of schemaKeys) {
+ exported[key] = s[key];
+ }
+ exported.topics = (s.topics || []).map((t) => this.buildTopicExport(t));
+ return exported;
+ });
+ }
+
+ buildTopicExport(t) {
+ return {
+ id: t.id,
+ topic: t.topic,
+ qos: t.qos,
+ };
+ }
+
+ importServers(serverList) {
+ if (!Array.isArray(serverList)) {
+ throw new Error('导入格式错误:必须是服务器配置数组');
+ }
+
+ // 断开所有现有连接
+ this.clients.forEach((client, id) => {
+ this.disconnect(id);
+ });
+ this.clients.clear();
+
+ this.servers.clear();
+ this.messages.clear();
+ this.publishHistory.clear();
+
+ serverList.forEach((config) => {
+ if (!config.name || !config.host) {
+ return;
+ }
+
+ let id = 'srv_' + Date.now() + '_' + Math.random().toString(36).slice(2, 6);
+ let server = {
+ id,
+ ...this.buildServerFields(config),
+ status: 'disconnected',
+ topics: (config.topics || []).map((t) => this.buildTopic(t)),
+ };
+
+ this.servers.set(id, server);
+ this.messages.set(id, []);
+ this.publishHistory.set(id, []);
+ });
+
+ this.saveData();
+ return this.getServers();
+ }
+
// ==================== 连接管理 ====================
connect(id) {
diff --git a/app/src/preload/index.js b/app/src/preload/index.js
index fa50a05..a5f4c43 100644
--- a/app/src/preload/index.js
+++ b/app/src/preload/index.js
@@ -9,6 +9,8 @@ const api = {
addServer: (config) => ipcRenderer.invoke('mqtt:add-server', config),
updateServer: (id, config) => ipcRenderer.invoke('mqtt:update-server', id, config),
deleteServer: (id) => ipcRenderer.invoke('mqtt:delete-server', id),
+ exportServers: () => ipcRenderer.invoke('mqtt:export-servers'),
+ importServers: (serverList) => ipcRenderer.invoke('mqtt:import-servers', serverList),
// 连接管理
connect: (id) => ipcRenderer.invoke('mqtt:connect', id),
diff --git a/app/src/renderer/src/components/Sidebar.vue b/app/src/renderer/src/components/Sidebar.vue
index 4bd54cd..9601b99 100644
--- a/app/src/renderer/src/components/Sidebar.vue
+++ b/app/src/renderer/src/components/Sidebar.vue
@@ -1,4 +1,5 @@
@@ -125,6 +161,25 @@ function handleDelete(server) {
block
@click="$emit('add-server')"
> + 添加服务器
+
+
@@ -297,4 +352,11 @@ function handleDelete(server) {
border-top: 1px solid var(--n-border-color);
flex-shrink: 0;
}
+
+.sidebar-import-export {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 8px;
+ margin-top: 8px;
+}
diff --git a/app/src/renderer/src/stores/mqtt.js b/app/src/renderer/src/stores/mqtt.js
index c9a007d..ff91ea1 100644
--- a/app/src/renderer/src/stores/mqtt.js
+++ b/app/src/renderer/src/stores/mqtt.js
@@ -161,6 +161,20 @@ export function useMqttStore() {
}
+ async function exportServers() {
+ return await window.api.exportServers();
+ }
+
+ async function importServers(serverList) {
+ let data = await window.api.importServers(serverList);
+ servers.value = data;
+ sortServers();
+ if (servers.value.length > 0 && !activeServerId.value) {
+ activeServerId.value = servers.value[0].id;
+ }
+ return data;
+ }
+
async function connectServer(id) {
return await window.api.connect(id);
}
@@ -273,6 +287,8 @@ export function useMqttStore() {
addServer,
updateServer,
deleteServer,
+ exportServers,
+ importServers,
connectServer,
disconnectServer,
addTopic,