From 46f64a432f2ea1a1c70a304db8b0417edbfb8314 Mon Sep 17 00:00:00 2001 From: kjqwer <2990346238@qq.com> Date: Tue, 11 Nov 2025 11:19:35 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=AF=BC=E5=85=A5=E5=AF=BC?= =?UTF-8?q?=E5=87=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.vue | 20 ++--- src/components/PresetManager.vue | 45 +++++----- src/components/PromptManager.vue | 2 +- src/stores/promptStore.ts | 149 +++++++++++++++++++++++++++---- 4 files changed, 168 insertions(+), 48 deletions(-) diff --git a/src/App.vue b/src/App.vue index e8b922b..bee13c6 100644 --- a/src/App.vue +++ b/src/App.vue @@ -66,16 +66,6 @@ function switchView(view: 'editor' | 'manager' | 'presets') { 编辑器 - +
diff --git a/src/components/PresetManager.vue b/src/components/PresetManager.vue index 5b02c6e..2bd0f6b 100644 --- a/src/components/PresetManager.vue +++ b/src/components/PresetManager.vue @@ -275,21 +275,22 @@ function formatDate(dateStr: string) { // 导入导出 function exportPresets() { - const data = { - folders: store.presetFolders || [], - presets: store.extendedPresets || [], - exportedAt: new Date().toISOString() - }; - - const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }); - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = `presets-${new Date().toISOString().split('T')[0]}.json`; - a.click(); - URL.revokeObjectURL(url); - - showNotification('预设已导出', 'success'); + try { + const jsonData = store.exportPresetsToJson(); + const blob = new Blob([jsonData], { type: 'application/json' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = `presets-${new Date().toISOString().split('T')[0]}.json`; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + + showNotification('预设已导出', 'success'); + } catch (error) { + showNotification('导出失败', 'error'); + } } function importPresets(event: Event) { @@ -299,18 +300,22 @@ function importPresets(event: Event) { const reader = new FileReader(); reader.onload = (e) => { try { - const data = JSON.parse(e.target?.result as string); - if (data.folders && data.presets) { - store.importExtendedPresets(data); + const jsonData = e.target?.result as string; + const success = store.importPresetsFromJson(jsonData); + + if (success) { showNotification('预设导入成功', 'success'); } else { - showNotification('导入文件格式不正确', 'error'); + showNotification('导入文件格式不正确或不是预设文件', 'error'); } } catch (error) { - showNotification('导入失败,请检查文件格式', 'error'); + showNotification('导入失败:文件格式错误', 'error'); } }; reader.readAsText(file); + + // 清空文件输入 + (event.target as HTMLInputElement).value = ''; } onMounted(() => { diff --git a/src/components/PromptManager.vue b/src/components/PromptManager.vue index 2dd1a05..3558f3e 100644 --- a/src/components/PromptManager.vue +++ b/src/components/PromptManager.vue @@ -124,7 +124,7 @@ function resetDefault() {
- 导出 JSON 会同时包含你的预设 + 导出 JSON 仅包含词库(不包含预设) diff --git a/src/stores/promptStore.ts b/src/stores/promptStore.ts index e1b49d6..65ab103 100644 --- a/src/stores/promptStore.ts +++ b/src/stores/promptStore.ts @@ -141,45 +141,48 @@ export const usePromptStore = defineStore('promptStore', { if (!bundle) { if (!baseline) baseline = await loadInitialDataset(); this.dataset = deepClone(baseline!); - this.presets = []; - this.extendedPresets = []; - this.presetFolders = []; + // 重置时不清空预设数据,只重置词库 } else { - // 确保兼容性 - bundle = this.ensureCompatibility(bundle); - + // 词库导入:只处理词库相关数据,不影响预设 if (bundle.dataset) { this.dataset = bundle.dataset; } else if (bundle.customDiff) { if (!baseline) baseline = await loadInitialDataset(); this.dataset = this.applyDiff(deepClone(baseline!), bundle.customDiff); } - this.presets = bundle.presets || []; - // 导入扩展预设数据 - this.extendedPresets = bundle.extendedPresets || []; - this.presetFolders = bundle.presetFolders || []; - if (bundle.presetManagement) { - this.presetManagement = bundle.presetManagement; + + // 兼容旧版本:如果导入的是包含预设的旧格式,提示用户使用预设导入功能 + if (bundle.presets || bundle.extendedPresets || bundle.presetFolders) { + console.warn('检测到预设数据,请使用预设管理页面的导入功能来导入预设数据'); } } this.selectedCategoryIndex = 0; this.selectedGroupIndex = 0; - // 确保扩展预设管理已初始化 - this.initializeExtendedPresets(); this.save(); }, exportToJson(): string { - // 导出仅包含自定义差异(不包含公共词库) + // 词库导出:仅包含自定义差异(不包含公共词库和预设数据) const diff = this.buildDiff(baseline!, this.dataset!); const bundle: ExportBundle = { version: 1, savedAt: new Date().toISOString(), customDiff: diff, - presets: deepClone(this.presets), - // 导出扩展预设数据 + // 词库导出不包含预设数据 + }; + return JSON.stringify(bundle, null, 2); + }, + + // 预设导出:仅导出预设相关数据 + exportPresetsToJson(): string { + const bundle = { + version: 1, + type: 'presets', + savedAt: new Date().toISOString(), extendedPresets: deepClone(this.extendedPresets), presetFolders: deepClone(this.presetFolders), presetManagement: deepClone(this.presetManagement), + // 保留旧预设以兼容 + presets: deepClone(this.presets), }; return JSON.stringify(bundle, null, 2); }, @@ -811,6 +814,118 @@ export const usePromptStore = defineStore('promptStore', { this.save(); }, + // 预设导入:专门处理预设导入文件 + importPresetsFromJson(jsonData: string): boolean { + try { + const data = JSON.parse(jsonData); + + // 仅处理预设相关的导入文件 + if (!(data.type === 'presets' || data.extendedPresets || data.presetFolders || data.presets)) { + return false; + } + + // 1) 构建旧ID到新ID的映射,按名称合并已存在的文件夹 + const idMap = new Map(); + const existingByName = new Map((this.presetFolders || []).map((f) => [f.name, f])); + + const foldersToCreate: any[] = []; + const incomingFolders: any[] = Array.isArray(data.presetFolders) ? data.presetFolders : []; + + // 先确定每个旧ID对应的新ID(复用同名文件夹,否则生成新ID) + for (const folder of incomingFolders) { + const sameName = existingByName.get(folder.name); + if (sameName) { + idMap.set(folder.id, sameName.id); + // 更新同名文件夹的基础信息(不改ID) + Object.assign(sameName, { + description: folder.description ?? sameName.description, + color: folder.color ?? sameName.color, + updatedAt: new Date().toISOString(), + }); + } else { + const newId = `folder_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`; + idMap.set(folder.id, newId); + foldersToCreate.push({ ...folder, id: newId }); + } + } + + // 创建不存在的文件夹,修正其父子关系(父ID按映射转换) + for (const folder of foldersToCreate) { + const created = { + id: folder.id, + name: folder.name, + description: folder.description ?? undefined, + color: folder.color ?? '#6366f1', + parentId: folder.parentId ? idMap.get(folder.parentId) : undefined, + createdAt: folder.createdAt || new Date().toISOString(), + updatedAt: new Date().toISOString(), + } as PresetFolder; + this.presetFolders.push(created); + } + + // 2) 导入扩展预设,修正其 folderId 指向到新ID + const incomingPresets: any[] = Array.isArray(data.extendedPresets) ? data.extendedPresets : []; + for (const preset of incomingPresets) { + // 如果已存在同名同类型,则更新;否则创建新预设 + const existing = (this.extendedPresets || []).find((p) => p.name === preset.name && p.type === preset.type); + const mappedFolderId = preset.folderId ? idMap.get(preset.folderId) : undefined; + + if (existing) { + Object.assign(existing, { + content: preset.content, + description: preset.description ?? existing.description, + tags: Array.isArray(preset.tags) ? preset.tags : existing.tags, + folderId: mappedFolderId ?? existing.folderId, + updatedAt: new Date().toISOString(), + }); + } else { + this.extendedPresets.push({ + id: `preset_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`, + name: preset.name, + type: preset.type, + content: preset.content, + description: preset.description ?? undefined, + tags: Array.isArray(preset.tags) ? preset.tags : undefined, + folderId: mappedFolderId, + createdAt: preset.createdAt || new Date().toISOString(), + updatedAt: new Date().toISOString(), + } as ExtendedPreset); + } + } + + // 3) 合并预设管理配置(不覆盖现有设置),无需变更 defaultFolder + if (data.presetManagement) { + this.presetManagement = { + ...this.presetManagement, + folders: [...(this.presetManagement?.folders || []), ...(data.presetManagement.folders || [])], + presets: [...(this.presetManagement?.presets || []), ...(data.presetManagement.presets || [])], + settings: { ...(this.presetManagement?.settings || {}) }, + }; + } + + // 4) 兼容旧预设格式(旧格式只含 presets: [{ name, text }...]) + if (Array.isArray(data.presets)) { + for (const oldPreset of data.presets) { + this.extendedPresets.push({ + id: `preset_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`, + name: oldPreset.name, + type: 'positive' as PresetType, + content: oldPreset.text, + description: '从旧格式导入', + createdAt: oldPreset.updatedAt || new Date().toISOString(), + updatedAt: new Date().toISOString(), + } as ExtendedPreset); + } + } + + this.save(); + return true; + } catch (error) { + console.error('预设导入失败:', error); + return false; + } + }, + // 兼容性:从旧预设迁移到新预设系统 migrateOldPresets() { if (this.presets.length === 0) return; // 没有旧预设需要迁移