完成基础功能

This commit is contained in:
limil 2026-02-18 15:07:28 +08:00
parent 855d0c8c28
commit 4370189e81
4 changed files with 19 additions and 17 deletions

View File

@ -9,7 +9,7 @@
---
- [x] 实现子网路由功能
- [ ] 实现配置保存和加载功能(支持加密私钥)
- [x] 实现配置保存和加载功能(支持加密私钥)
---

View File

@ -151,12 +151,14 @@ function FlowContent(): ReactNode {
const handleSaveConfig = async (pass?: string): Promise<void> => {
try {
const saveConfig: SaveConfig = {settings: settings, nodes: [], edges: [], encrypted: false}
if(pass) saveConfig.encrypted = true;
nodes.forEach(node => {
const nodeData = node.data;
let privateKey = nodeData.privateKey;
if(pass && typeof privateKey === 'string') privateKey = CryptoJS.AES.encrypt(privateKey, pass).toString();
let privateKey: string = nodeData.privateKey;
if(pass) {
privateKey = CryptoJS.AES.encrypt(privateKey, pass).toString();
saveConfig.encrypted = true;
}
saveConfig.nodes.push({...node, data: {...nodeData, privateKey: privateKey}});
});
@ -184,13 +186,13 @@ function FlowContent(): ReactNode {
if (saveConfig.encrypted) {
if (!pass) { toast.error('需要密码以解密私钥'); return; }
try {
for(let node of saveConfig.nodes) {
node.data.privateKey = CryptoJS.AES.decrypt(node.data.privateKey, pass).toString(CryptoJS.enc.Utf8);
for(let node of saveConfig.nodes) {
const privateKey = CryptoJS.AES.decrypt(node.data.privateKey, pass).toString(CryptoJS.enc.Utf8);
if(!privateKey) {
toast.error('密码错误');
return;
}
} catch (err) {
toast.error('解密失败: ' + err);
return;
node.data.privateKey = privateKey;
}
}
setSettings(saveConfig.settings);
@ -233,11 +235,6 @@ function FlowContent(): ReactNode {
<div className="toolbar">
<div className="toolbar-group">
<div className="action-section">
<div className="section-title"></div>
<SaveLoadPanel onSave={handleSaveConfig} onLoad={handleLoadConfig} />
</div>
<div className="action-section">
<div className="section-title"></div>
<Toggle
@ -253,6 +250,11 @@ function FlowContent(): ReactNode {
📋
</button>
</div>
<div className="action-section">
<div className="section-title"></div>
<SaveLoadPanel onSave={handleSaveConfig} onLoad={handleLoadConfig} />
</div>
</div>
</div>

View File

@ -26,7 +26,7 @@
border-radius:4px;
}
/* Use .toolbar-btn for button styles so Save/Load matches other toolbar actions */
.save-load-panel .toolbar-btn{width:100%;text-align:left;padding:8px 16px;border-radius:4px}
.save-load-panel .toolbar-btn{width:100%;text-align:center;padding:8px 16px;border-radius:4px}
/* divider removed to match toolbar style */
/* Modal styles */

View File

@ -73,7 +73,7 @@ export default function SaveLoadPanel({ onSave, onLoad }: Props) {
<button className="sl-close" onClick={closeModal}></button>
</div>
<div className="sl-modal-body">
<label className="sl-label"></label>
<label className="sl-label"></label>
<input type="password" className="sl-input" value={password} onChange={e => setPassword(e.target.value)} />
{modalType === 'load' ? (