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:
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user