From 5985971041d9f8b7ef7f84f1a8ed895abe8db43c Mon Sep 17 00:00:00 2001 From: limil Date: Wed, 18 Feb 2026 15:36:36 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BF=9D=E5=AD=98=E6=96=B9?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TODO.md | 3 +-- src/App.tsx | 48 ++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/TODO.md b/TODO.md index a527228..9ee62f0 100644 --- a/TODO.md +++ b/TODO.md @@ -17,6 +17,5 @@ --- -- [ ] 使用Reducer 和 Immer重构代码 +- [ ] 整理、重构代码 - [ ] 添加测试用例 -- [ ] 体验调优:生成配置完成后弹出预览窗口可以下载或者复制 diff --git a/src/App.tsx b/src/App.tsx index 91d793c..d124e0c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -168,12 +168,48 @@ function FlowContent(): ReactNode { const json = instanceToPlain(saveConfig); const blob = new Blob([JSON.stringify(json, null, 2)], { type: 'application/json' }); - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = 'wg-config.json'; - a.click(); - URL.revokeObjectURL(url); + const lastNameKey = 'wg-last-filename'; + const suggestedName = (localStorage.getItem(lastNameKey) || 'wg-config.json'); + + // Use File System Access API when available to show save file picker + if ((window as any).showSaveFilePicker) { + try { + const handle = await (window as any).showSaveFilePicker({ + suggestedName: suggestedName, + types: [{ + description: 'WireGuard Config', + accept: { 'application/json': ['.json'] } + }] + }); + const writable = await handle.createWritable(); + await writable.write(blob); + await writable.close(); + // remember chosen name if available + try { + const name = handle.name || suggestedName; + localStorage.setItem(lastNameKey, name); + } catch (e) { + localStorage.setItem(lastNameKey, suggestedName); + } + } catch (e) { + // If user cancels or error, fallback to anchor download + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = suggestedName; + a.click(); + URL.revokeObjectURL(url); + } + } else { + // Fallback: create an anchor and trigger download, using last used filename + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = suggestedName; + a.click(); + URL.revokeObjectURL(url); + localStorage.setItem(lastNameKey, suggestedName); + } } catch (e) { toast.error('保存失败: ' + e); }