feat: 将自定义范式从 localStorage 迁移到数据库存储

**数据库层 (src/db/index.js)**:
- 为 paradigms 表添加 4 个新字段:
  * specialized_prompt: 存储专业化提示词
  * expert_guidelines: 存储专家检查指令(JSON)
  * outline_template: 存储大纲模板
  * recommended_tags: 存储推荐标签(JSON)
- 新增数据库迁移函数 migrateDatabase(),自动为现有数据库添加新列
- 更新 getAllParadigms() 解析新字段
- 更新 addParadigm() 保存新字段
- 更新 updateParadigm() 支持新字段的更新

**Store 层 (src/stores/paradigm.js)**:
- 将存储从 localStorage 改为数据库(IndexedDB/SQLite)
- loadCustomParadigms() 现在从数据库加载,并自动迁移 localStorage 旧数据
- 新增 saveCustomParadigm(paradigm) 用于保存单个范式
- addCustomParadigm() 改为异步,调用数据库保存
- deleteCustomParadigm() 改为异步,调用数据库删除
- updateParadigmField() 改为异步,调用数据库更新
- clearAllCustomParadigms() 改为异步,调用数据库清空
- 迁移后自动清理 localStorage 中的旧数据

**优势**:
- 范式数据现在包含在数据导出中
- 统一的数据管理接口
- 更可靠的数据持久化
- 自动迁移现有数据,用户无感知

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
empty
2026-01-12 01:18:41 +08:00
parent 7f985ed317
commit 81b0e937b3
2 changed files with 179 additions and 33 deletions

View File

@@ -128,6 +128,10 @@ const initTables = async () => {
logic_paradigms TEXT,
auto_match_refs INTEGER DEFAULT 1,
selected_refs TEXT,
specialized_prompt TEXT,
expert_guidelines TEXT,
outline_template TEXT,
recommended_tags TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
is_custom INTEGER DEFAULT 0
@@ -213,6 +217,45 @@ const initTables = async () => {
`)
console.log('✅ 数据表初始化完成')
// 运行数据库迁移
migrateDatabase()
}
/**
* 数据库迁移:添加范式表的新字段
*/
const migrateDatabase = () => {
try {
// 检查是否已存在 specialized_prompt 列
const columns = query(`
SELECT name FROM pragma_table_info('paradigms')
`).map(row => row.name)
const neededColumns = ['specialized_prompt', 'expert_guidelines', 'outline_template', 'recommended_tags']
const missingColumns = neededColumns.filter(col => !columns.includes(col))
if (missingColumns.length > 0) {
console.log('🔄 检测到数据库需要迁移,添加新字段...')
if (missingColumns.includes('specialized_prompt')) {
execute('ALTER TABLE paradigms ADD COLUMN specialized_prompt TEXT')
}
if (missingColumns.includes('expert_guidelines')) {
execute('ALTER TABLE paradigms ADD COLUMN expert_guidelines TEXT')
}
if (missingColumns.includes('outline_template')) {
execute('ALTER TABLE paradigms ADD COLUMN outline_template TEXT')
}
if (missingColumns.includes('recommended_tags')) {
execute('ALTER TABLE paradigms ADD COLUMN recommended_tags TEXT')
}
console.log('✅ 数据库迁移完成')
}
} catch (error) {
console.error('❌ 数据库迁移失败:', error)
}
}
// ============================================
@@ -508,7 +551,7 @@ export const deleteReference = (id) => {
*/
export const getAllParadigms = () => {
const paradigms = query('SELECT * FROM paradigms ORDER BY is_custom ASC, created_at DESC')
return paradigms.map(p => ({
...p,
tags: p.tags ? JSON.parse(p.tags) : [],
@@ -516,6 +559,10 @@ export const getAllParadigms = () => {
customDimensions: p.custom_dimensions ? JSON.parse(p.custom_dimensions) : null,
logicParadigms: p.logic_paradigms ? JSON.parse(p.logic_paradigms) : null,
selectedRefs: p.selected_refs ? JSON.parse(p.selected_refs) : [],
specializedPrompt: p.specialized_prompt || null,
expertGuidelines: p.expert_guidelines ? JSON.parse(p.expert_guidelines) : null,
outlineTemplate: p.outline_template || null,
recommendedTags: p.recommended_tags ? JSON.parse(p.recommended_tags) : [],
isCustom: p.is_custom === 1,
autoMatchRefs: p.auto_match_refs === 1
}))
@@ -526,11 +573,12 @@ export const getAllParadigms = () => {
*/
export const addParadigm = (paradigm) => {
const id = paradigm.id || `paradigm-${Date.now()}`
execute(`
INSERT INTO paradigms (id, name, icon, description, tags, tag_class, system_constraints,
dimension_set_id, custom_dimensions, logic_paradigms, auto_match_refs, selected_refs, is_custom)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
INSERT INTO paradigms (id, name, icon, description, tags, tag_class, system_constraints,
dimension_set_id, custom_dimensions, logic_paradigms, auto_match_refs, selected_refs,
specialized_prompt, expert_guidelines, outline_template, recommended_tags, is_custom)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`, [
id,
paradigm.name,
@@ -544,9 +592,13 @@ export const addParadigm = (paradigm) => {
paradigm.logicParadigms ? JSON.stringify(paradigm.logicParadigms) : null,
paradigm.autoMatchRefs !== false ? 1 : 0,
JSON.stringify(paradigm.selectedRefs || []),
paradigm.specializedPrompt || null,
paradigm.expertGuidelines ? JSON.stringify(paradigm.expertGuidelines) : null,
paradigm.outlineTemplate || null,
paradigm.recommendedTags ? JSON.stringify(paradigm.recommendedTags || []) : null,
paradigm.isCustom ? 1 : 0
])
return id
}
@@ -556,7 +608,7 @@ export const addParadigm = (paradigm) => {
export const updateParadigm = (id, updates) => {
const setClauses = []
const params = []
const fieldMap = {
name: 'name',
icon: 'icon',
@@ -565,14 +617,14 @@ export const updateParadigm = (id, updates) => {
dimensionSetId: 'dimension_set_id',
autoMatchRefs: 'auto_match_refs'
}
Object.entries(updates).forEach(([key, value]) => {
if (fieldMap[key]) {
setClauses.push(`${fieldMap[key]} = ?`)
params.push(key === 'autoMatchRefs' ? (value ? 1 : 0) : value)
}
})
if (updates.tags !== undefined) {
setClauses.push('tags = ?')
params.push(JSON.stringify(updates.tags))
@@ -589,12 +641,28 @@ export const updateParadigm = (id, updates) => {
setClauses.push('selected_refs = ?')
params.push(JSON.stringify(updates.selectedRefs))
}
if (updates.specializedPrompt !== undefined) {
setClauses.push('specialized_prompt = ?')
params.push(updates.specializedPrompt)
}
if (updates.expertGuidelines !== undefined) {
setClauses.push('expert_guidelines = ?')
params.push(updates.expertGuidelines ? JSON.stringify(updates.expertGuidelines) : null)
}
if (updates.outlineTemplate !== undefined) {
setClauses.push('outline_template = ?')
params.push(updates.outlineTemplate)
}
if (updates.recommendedTags !== undefined) {
setClauses.push('recommended_tags = ?')
params.push(updates.recommendedTags ? JSON.stringify(updates.recommendedTags) : null)
}
setClauses.push('updated_at = CURRENT_TIMESTAMP')
params.push(id)
execute(`UPDATE paradigms SET ${setClauses.join(', ')} WHERE id = ?`, params)
return true
}

View File

@@ -4,11 +4,15 @@ import { ref, computed } from 'vue'
/**
* 自定义范式管理 Store
* 用于管理用户通过需求文档生成的自定义范式
* 现已迁移到数据库存储IndexedDB/SQLite
*/
export const useParadigmStore = defineStore('paradigm', () => {
// 自定义范式列表(存储在 localStorage
// 自定义范式列表(从数据库加载
const customParadigms = ref([])
// 数据库是否已初始化
const isDbInitialized = ref(false)
// 当前正在编辑的范式
const editingParadigm = ref(null)
@@ -19,14 +23,62 @@ export const useParadigmStore = defineStore('paradigm', () => {
const parsingProgress = ref('')
/**
* 从 localStorage 加载自定义范式
* 从数据库加载自定义范式
* 如果 localStorage 中有旧数据,自动迁移到数据库
*/
function loadCustomParadigms() {
async function loadCustomParadigms() {
try {
const stored = localStorage.getItem('customParadigms')
if (stored) {
customParadigms.value = JSON.parse(stored)
// 动态导入数据库模块(避免循环依赖)
const { getAllParadigms, addParadigm, updateParadigm } = await import('../db/index.js')
// 从数据库加载所有范式
const allParadigms = getAllParadigms()
// 过滤出自定义范式
customParadigms.value = allParadigms.filter(p => p.isCustom)
// 检查 localStorage 中是否有旧数据需要迁移
const localStorageData = localStorage.getItem('customParadigms')
if (localStorageData && !isDbInitialized.value) {
try {
const oldParadigms = JSON.parse(localStorageData)
if (oldParadigms.length > 0) {
console.log(`🔄 检测到 localStorage 中有 ${oldParadigms.length} 个范式,开始迁移...`)
// 迁移每个范式到数据库
for (const oldParadigm of oldParadigms) {
// 检查数据库中是否已存在
const existing = customParadigms.value.find(p => p.id === oldParadigm.id)
if (existing) {
// 更新现有范式
updateParadigm(oldParadigm.id, oldParadigm)
} else {
// 添加新范式
addParadigm({
...oldParadigm,
isCustom: true,
autoMatchRefs: oldParadigm.autoMatchRefs !== false
})
}
}
// 重新加载从数据库
const updatedParadigms = getAllParadigms()
customParadigms.value = updatedParadigms.filter(p => p.isCustom)
// 清除 localStorage 中的旧数据
localStorage.removeItem('customParadigms')
console.log('✅ 范式迁移完成localStorage 已清理')
}
} catch (migrateError) {
console.error('❌ 迁移 localStorage 数据失败:', migrateError)
}
}
isDbInitialized.value = true
} catch (error) {
console.error('加载自定义范式失败:', error)
customParadigms.value = []
@@ -34,11 +86,26 @@ export const useParadigmStore = defineStore('paradigm', () => {
}
/**
* 保存自定义范式到 localStorage
* 保存单个自定义范式到数据库(替换旧的批量保存)
*/
function saveCustomParadigms() {
async function saveCustomParadigm(paradigm) {
try {
localStorage.setItem('customParadigms', JSON.stringify(customParadigms.value))
const { addParadigm, updateParadigm } = await import('../db/index.js')
// 检查是否已存在
const existing = customParadigms.value.find(p => p.id === paradigm.id)
if (existing) {
// 更新现有范式
updateParadigm(paradigm.id, paradigm)
} else {
// 添加新范式
addParadigm({
...paradigm,
isCustom: true,
autoMatchRefs: paradigm.autoMatchRefs !== false
})
}
} catch (error) {
console.error('保存自定义范式失败:', error)
}
@@ -48,7 +115,7 @@ export const useParadigmStore = defineStore('paradigm', () => {
* 添加自定义范式
* @param {Object} paradigm - 范式对象
*/
function addCustomParadigm(paradigm) {
async function addCustomParadigm(paradigm) {
// 检查是否已存在相同ID
const index = customParadigms.value.findIndex(p => p.id === paradigm.id)
if (index >= 0) {
@@ -58,16 +125,21 @@ export const useParadigmStore = defineStore('paradigm', () => {
// 添加新范式
customParadigms.value.push(paradigm)
}
saveCustomParadigms()
await saveCustomParadigm(paradigm)
}
/**
* 删除自定义范式
* @param {string} paradigmId - 范式ID
*/
function deleteCustomParadigm(paradigmId) {
customParadigms.value = customParadigms.value.filter(p => p.id !== paradigmId)
saveCustomParadigms()
async function deleteCustomParadigm(paradigmId) {
try {
const { deleteParadigm } = await import('../db/index.js')
deleteParadigm(paradigmId)
customParadigms.value = customParadigms.value.filter(p => p.id !== paradigmId)
} catch (error) {
console.error('删除自定义范式失败:', error)
}
}
/**
@@ -85,11 +157,11 @@ export const useParadigmStore = defineStore('paradigm', () => {
* @param {string} field - 字段名
* @param {any} value - 新值
*/
function updateParadigmField(paradigmId, field, value) {
async function updateParadigmField(paradigmId, field, value) {
const paradigm = getCustomParadigmById(paradigmId)
if (paradigm) {
paradigm[field] = value
saveCustomParadigms()
await saveCustomParadigm(paradigm)
}
}
@@ -170,9 +242,14 @@ export const useParadigmStore = defineStore('paradigm', () => {
/**
* 清空所有自定义范式(慎用)
*/
function clearAllCustomParadigms() {
customParadigms.value = []
saveCustomParadigms()
async function clearAllCustomParadigms() {
try {
const { execute } = await import('../db/index.js')
execute('DELETE FROM paradigms WHERE is_custom = 1')
customParadigms.value = []
} catch (error) {
console.error('清空自定义范式失败:', error)
}
}
/**
@@ -234,7 +311,7 @@ export const useParadigmStore = defineStore('paradigm', () => {
return updatedParadigm
}
// 初始化时加载
// 初始化时加载(异步)
loadCustomParadigms()
return {
@@ -243,6 +320,7 @@ export const useParadigmStore = defineStore('paradigm', () => {
editingParadigm,
isParsing,
parsingProgress,
isDbInitialized,
// 计算属性
customParadigmCount,
@@ -250,7 +328,7 @@ export const useParadigmStore = defineStore('paradigm', () => {
// 方法
loadCustomParadigms,
saveCustomParadigms,
saveCustomParadigm, // 单个保存(新)
addCustomParadigm,
deleteCustomParadigm,
getCustomParadigmById,