Skip to content

Commit 4417135

Browse files
✨ feat: 支持导出导入设置
1 parent bec6074 commit 4417135

5 files changed

Lines changed: 167 additions & 3 deletions

File tree

auto-eslint.mjs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ export default {
5959
"isRef": true,
6060
"isShallow": true,
6161
"makeDestructurable": true,
62-
"manualResetRef": true,
6362
"markRaw": true,
6463
"nextTick": true,
6564
"onActivated": true,
@@ -97,11 +96,11 @@ export default {
9796
"refAutoReset": true,
9897
"refDebounced": true,
9998
"refDefault": true,
100-
"refManualReset": true,
10199
"refThrottled": true,
102100
"refWithControl": true,
103101
"resolveComponent": true,
104102
"resolveRef": true,
103+
"resolveUnref": true,
105104
"shallowReactive": true,
106105
"shallowReadonly": true,
107106
"shallowRef": true,

electron/main/ipc/ipc-store.ts

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { ipcMain } from "electron";
1+
import { ipcMain, dialog, app } from "electron";
2+
import { writeFile, readFile } from "fs/promises";
23
import { useStore } from "../store";
34
import type { StoreType } from "../store";
45

@@ -40,6 +41,72 @@ const initStoreIpc = (): void => {
4041
}
4142
return true;
4243
});
44+
// 导出配置
45+
ipcMain.handle("store-export", async (_event, rendererData: any) => {
46+
console.log("[IPC] store-export called");
47+
try {
48+
const now = new Date();
49+
const timestamp = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}_${String(now.getHours()).padStart(2, "0")}-${String(now.getMinutes()).padStart(2, "0")}-${String(now.getSeconds()).padStart(2, "0")}`;
50+
const filename = `SPlayer_Settings_${timestamp}.json`;
51+
52+
const { filePath } = await dialog.showSaveDialog({
53+
title: "导出设置",
54+
defaultPath: filename,
55+
filters: [{ name: "JSON", extensions: ["json"] }],
56+
});
57+
58+
if (filePath) {
59+
console.log("[IPC] Exporting to:", filePath);
60+
const fullData = {
61+
version: app.getVersion(),
62+
timestamp: now.getTime(),
63+
electron: store.store,
64+
renderer: rendererData,
65+
};
66+
const data = JSON.stringify(fullData, null, 2);
67+
await writeFile(filePath, data, "utf-8");
68+
return true;
69+
}
70+
console.log("[IPC] Export cancelled");
71+
return false;
72+
} catch (error) {
73+
console.error("❌ Export settings failed:", error);
74+
return false;
75+
}
76+
});
77+
78+
// 导入配置
79+
ipcMain.handle("store-import", async () => {
80+
console.log("[IPC] store-import called");
81+
try {
82+
const { filePaths } = await dialog.showOpenDialog({
83+
title: "导入设置",
84+
filters: [{ name: "JSON", extensions: ["json"] }],
85+
properties: ["openFile"],
86+
});
87+
88+
if (filePaths && filePaths.length > 0) {
89+
console.log("[IPC] Importing from:", filePaths[0]);
90+
const data = await readFile(filePaths[0], "utf-8");
91+
const settings = JSON.parse(data);
92+
93+
// 恢复 Electron Store 配置
94+
if (settings.electron) {
95+
store.store = settings.electron;
96+
} else if (!settings.renderer) {
97+
// 兼容旧版导出(如果是纯 electron store 数据)
98+
store.store = settings;
99+
}
100+
101+
return settings;
102+
}
103+
console.log("[IPC] Import cancelled");
104+
return false;
105+
} catch (error) {
106+
console.error("❌ Import settings failed:", error);
107+
return false;
108+
}
109+
});
43110
};
44111

45112
export default initStoreIpc;

electron/preload/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ if (process.contextIsolated) {
1515
has: (key: string) => ipcRenderer.invoke("store-has", key),
1616
delete: (key: string) => ipcRenderer.invoke("store-delete", key),
1717
reset: (keys?: string[]) => ipcRenderer.invoke("store-reset", keys),
18+
export: (data: any) => ipcRenderer.invoke("store-export", data),
19+
import: () => ipcRenderer.invoke("store-import"),
1820
},
1921
});
2022
} catch (error) {

src/components/Setting/OtherSetting.vue

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,26 @@
101101
</n-card>
102102
</n-collapse-transition>
103103
</div>
104+
<div v-if="isElectron" class="set-list">
105+
<n-h3 prefix="bar">
106+
备份与恢复
107+
<n-tag type="warning" size="small" round>Beta</n-tag>
108+
</n-h3>
109+
<n-card class="set-item">
110+
<div class="label">
111+
<n-text class="name">导出设置</n-text>
112+
<n-text class="tip" :depth="3">将当前所有设置导出为 JSON 文件</n-text>
113+
</div>
114+
<n-button type="primary" strong secondary @click="exportSettings"> 导出设置 </n-button>
115+
</n-card>
116+
<n-card class="set-item">
117+
<div class="label">
118+
<n-text class="name">导入设置</n-text>
119+
<n-text class="tip" :depth="3">从 JSON 文件恢复设置(导入后将自动重启)</n-text>
120+
</div>
121+
<n-button type="primary" strong secondary @click="importSettings"> 导入设置 </n-button>
122+
</n-card>
123+
</div>
104124
<div class="set-list">
105125
<n-h3 prefix="bar"> 重置 </n-h3>
106126
<n-card class="set-item">
@@ -125,6 +145,7 @@
125145
import { useSettingStore, useDataStore } from "@/stores";
126146
import { isElectron } from "@/utils/env";
127147
import { debounce } from "lodash-es";
148+
import { NAlert, NTag } from "naive-ui";
128149
129150
const dataStore = useDataStore();
130151
const settingStore = useSettingStore();
@@ -159,6 +180,69 @@ const testProxy = async () => {
159180
window.$message.error("代理测试失败,请重试");
160181
}
161182
testProxyLoading.value = false;
183+
testProxyLoading.value = false;
184+
};
185+
186+
// 导出设置
187+
const exportSettings = async () => {
188+
console.log("[Frontend] Export settings clicked");
189+
try {
190+
// 收集渲染进程数据 (localStorage)
191+
const rendererData = {
192+
"setting-store": localStorage.getItem("setting-store"),
193+
"shortcut-store": localStorage.getItem("shortcut-store"),
194+
};
195+
196+
const result = await window.api.store.export(rendererData);
197+
console.log("[Frontend] Export result:", result);
198+
if (result) {
199+
window.$message.success("设置导出成功");
200+
} else {
201+
window.$message.error("设置导出失败");
202+
}
203+
} catch (error) {
204+
console.error("[Frontend] Export error:", error);
205+
window.$message.error("设置导出出错");
206+
}
207+
};
208+
209+
// 导入设置
210+
const importSettings = async () => {
211+
console.log("[Frontend] Import settings clicked");
212+
window.$dialog.warning({
213+
title: "导入设置",
214+
content: () => h("div", null, [
215+
h(NAlert, { type: "warning", showIcon: true, style: { marginBottom: "12px" } }, { default: () => "目前备份数据功能属于测试阶段,不保证可用性" }),
216+
h("div", null, "导入设置将覆盖当前所有配置并重启软件,是否继续?")
217+
]),
218+
positiveText: "确定",
219+
negativeText: "取消",
220+
onPositiveClick: async () => {
221+
console.log("[Frontend] Import confirmed");
222+
try {
223+
const data = await window.api.store.import();
224+
console.log("[Frontend] Import data:", data);
225+
226+
if (data) {
227+
// 恢复渲染进程数据
228+
if (data.renderer) {
229+
if (data.renderer["setting-store"]) localStorage.setItem("setting-store", data.renderer["setting-store"]);
230+
if (data.renderer["shortcut-store"]) localStorage.setItem("shortcut-store", data.renderer["shortcut-store"]);
231+
}
232+
233+
window.$message.success("设置导入成功,即将重启");
234+
setTimeout(() => {
235+
window.location.reload();
236+
}, 1000);
237+
} else {
238+
window.$message.error("设置导入失败或已取消");
239+
}
240+
} catch (error) {
241+
console.error("[Frontend] Import error:", error);
242+
window.$message.error("设置导入出错");
243+
}
244+
},
245+
});
162246
};
163247
164248
// 重置设置

src/types/global.d.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,17 @@ declare global {
1313
$notification: NotificationApi;
1414
$loadingBar: LoadingBarApi;
1515
$modal: ModalApi;
16+
// electron
17+
api: {
18+
store: {
19+
get: (key: string) => Promise<any>;
20+
set: (key: string, value: unknown) => Promise<boolean>;
21+
has: (key: string) => Promise<boolean>;
22+
delete: (key: string) => Promise<boolean>;
23+
reset: (keys?: string[]) => Promise<boolean>;
24+
export: (data: any) => Promise<boolean>;
25+
import: () => Promise<any>;
26+
};
27+
};
1628
}
1729
}

0 commit comments

Comments
 (0)