完成基础功能

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] 实现子网路由功能
- [ ] 实现配置保存和加载功能(支持加密私钥) - [x] 实现配置保存和加载功能(支持加密私钥)
--- ---

View File

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

View File

@ -26,7 +26,7 @@
border-radius:4px; border-radius:4px;
} }
/* Use .toolbar-btn for button styles so Save/Load matches other toolbar actions */ /* 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 */ /* divider removed to match toolbar style */
/* Modal styles */ /* Modal styles */

View File

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