feat: 快速发送列表持久化到本地文件 frost-mqtt-data.json

This commit is contained in:
2026-07-21 23:22:18 +08:00
parent 4aaf584451
commit 9723495f12
4 changed files with 90 additions and 17 deletions
+11
View File
@@ -77,6 +77,17 @@ export function registerIpcHandlers() {
return mqttManager.importServers(serverList); return mqttManager.importServers(serverList);
}); });
// ==================== 快速发送 ====================
ipcMain.handle('mqtt:get-quick-send-list', () => {
return mqttManager.getQuickSendList();
});
ipcMain.handle('mqtt:save-quick-send-list', (_, list) => {
mqttManager.saveQuickSendList(list);
return true;
});
// ==================== 连接管理 ==================== // ==================== 连接管理 ====================
ipcMain.handle('mqtt:connect', (_, id) => { ipcMain.handle('mqtt:connect', (_, id) => {
+32
View File
@@ -35,6 +35,7 @@ class MqttManager {
this.listeners = new Set(); // IPC callback functions this.listeners = new Set(); // IPC callback functions
this.msgIdCounter = 0; // 用于生成唯一消息 id this.msgIdCounter = 0; // 用于生成唯一消息 id
this.dataPath = join(app.getPath('userData'), 'frost-mqtt-data.json'); this.dataPath = join(app.getPath('userData'), 'frost-mqtt-data.json');
this.quickSendList = [];
this.loadData(); this.loadData();
} }
@@ -101,6 +102,12 @@ class MqttManager {
}); });
} }
if (Array.isArray(data.quickSendList)) {
this.quickSendList = data.quickSendList.filter((item) => {
return item && typeof item.id === 'string' && typeof item.topic === 'string';
});
}
} else { } else {
this.initDefaultServers(); this.initDefaultServers();
} }
@@ -124,6 +131,7 @@ class MqttManager {
})), })),
messages: Object.fromEntries(this.messages), messages: Object.fromEntries(this.messages),
publishHistory: Object.fromEntries(this.publishHistory), publishHistory: Object.fromEntries(this.publishHistory),
quickSendList: this.quickSendList,
}; };
writeFileSync(this.dataPath, JSON.stringify(data, null, 2), 'utf-8'); writeFileSync(this.dataPath, JSON.stringify(data, null, 2), 'utf-8');
@@ -409,6 +417,30 @@ class MqttManager {
return this.getServers(); return this.getServers();
} }
// ==================== 快速发送 ====================
/**
* 获取快速发送列表
* @returns {QuickSendItem[]} 快速发送项数组
*/
getQuickSendList() {
return this.quickSendList;
}
/**
* 保存快速发送列表
* @param {QuickSendItem[]} list - 快速发送项数组
*/
saveQuickSendList(list) {
if (!Array.isArray(list)) {
return;
}
this.quickSendList = list.filter((item) => {
return item && typeof item.id === 'string' && typeof item.topic === 'string';
});
this.saveData();
}
// ==================== 连接管理 ==================== // ==================== 连接管理 ====================
/** /**
+4
View File
@@ -15,6 +15,10 @@ const api = {
exportServers: () => ipcRenderer.invoke('mqtt:export-servers'), exportServers: () => ipcRenderer.invoke('mqtt:export-servers'),
importServers: (serverList) => ipcRenderer.invoke('mqtt:import-servers', serverList), importServers: (serverList) => ipcRenderer.invoke('mqtt:import-servers', serverList),
// 快速发送
getQuickSendList: () => ipcRenderer.invoke('mqtt:get-quick-send-list'),
saveQuickSendList: (list) => ipcRenderer.invoke('mqtt:save-quick-send-list', list),
// 连接管理 // 连接管理
connect: (id) => ipcRenderer.invoke('mqtt:connect', id), connect: (id) => ipcRenderer.invoke('mqtt:connect', id),
disconnect: (id) => ipcRenderer.invoke('mqtt:disconnect', id), disconnect: (id) => ipcRenderer.invoke('mqtt:disconnect', id),
+38 -12
View File
@@ -8,8 +8,8 @@ const store = useMqttStore();
const msg = useMessage(); const msg = useMessage();
const dialog = useDialog(); const dialog = useDialog();
// localStorage 持久化 key // 旧版 localStorage key,用于数据迁移
const storageKey = 'mqtt-client.quick-send-list'; const oldStorageKey = 'mqtt-client.quick-send-list';
/** /**
* @typedef {Object} QuickSendItem * @typedef {Object} QuickSendItem
@@ -24,6 +24,9 @@ const storageKey = 'mqtt-client.quick-send-list';
/** @type {import('vue').Ref<QuickSendItem[]>} */ /** @type {import('vue').Ref<QuickSendItem[]>} */
const quickList = ref([]); const quickList = ref([]);
// 列表是否已从本地文件加载完成
const quickListLoaded = ref(false);
// 表单弹窗显隐 // 表单弹窗显隐
const showModal = ref(false); const showModal = ref(false);
const isEdit = ref(false); const isEdit = ref(false);
@@ -35,26 +38,33 @@ const formPayload = ref('');
const formQos = ref(1); const formQos = ref(1);
const formRetain = ref(false); const formRetain = ref(false);
// 从 localStorage 恢复列表 // 从旧版 localStorage 迁移数据
function migrateFromLocalStorage() {
try { try {
let saved = JSON.parse(localStorage.getItem(oldStorageKey) || '[]');
let saved = JSON.parse(localStorage.getItem(storageKey) || '[]'); if (Array.isArray(saved) && saved.length > 0) {
if (Array.isArray(saved)) {
quickList.value = saved.filter((item) => { quickList.value = saved.filter((item) => {
return item && typeof item.id === 'string' && typeof item.topic === 'string'; return item && typeof item.id === 'string' && typeof item.topic === 'string';
}); });
window.api.saveQuickSendList(JSON.parse(JSON.stringify(quickList.value)));
} }
} catch { } catch {
localStorage.removeItem(storageKey); // 忽略旧数据解析错误
} finally {
localStorage.removeItem(oldStorageKey);
}
} }
// 列表变化时持久化 // 列表变化时持久化到本地文件
watch( watch(
quickList, quickList,
() => { () => {
localStorage.setItem(storageKey, JSON.stringify(quickList.value)); if (!quickListLoaded.value) {
return;
}
window.api.saveQuickSendList(JSON.parse(JSON.stringify(quickList.value))).catch((e) => {
console.error('保存快速发送列表失败:', e);
});
}, },
{ deep: true } { deep: true }
); );
@@ -461,7 +471,23 @@ function updateColumnCount(width) {
} }
} }
onMounted(() => { onMounted(async () => {
try {
let list = await window.api.getQuickSendList();
if (Array.isArray(list)) {
quickList.value = list.filter((item) => {
return item && typeof item.id === 'string' && typeof item.topic === 'string';
});
}
if (quickList.value.length === 0) {
migrateFromLocalStorage();
}
} catch (e) {
console.error('加载快速发送列表失败:', e);
} finally {
quickListLoaded.value = true;
}
resizeObserver = new ResizeObserver((entries) => { resizeObserver = new ResizeObserver((entries) => {
for (let entry of entries) { for (let entry of entries) {
updateColumnCount(entry.contentRect.width); updateColumnCount(entry.contentRect.width);