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,
|
logic_paradigms TEXT,
|
||||||
auto_match_refs INTEGER DEFAULT 1,
|
auto_match_refs INTEGER DEFAULT 1,
|
||||||
selected_refs TEXT,
|
selected_refs TEXT,
|
||||||
|
specialized_prompt TEXT,
|
||||||
|
expert_guidelines TEXT,
|
||||||
|
outline_template TEXT,
|
||||||
|
recommended_tags TEXT,
|
||||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
is_custom INTEGER DEFAULT 0
|
is_custom INTEGER DEFAULT 0
|
||||||
@@ -213,6 +217,45 @@ const initTables = async () => {
|
|||||||
`)
|
`)
|
||||||
|
|
||||||
console.log('✅ 数据表初始化完成')
|
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 = () => {
|
export const getAllParadigms = () => {
|
||||||
const paradigms = query('SELECT * FROM paradigms ORDER BY is_custom ASC, created_at DESC')
|
const paradigms = query('SELECT * FROM paradigms ORDER BY is_custom ASC, created_at DESC')
|
||||||
|
|
||||||
return paradigms.map(p => ({
|
return paradigms.map(p => ({
|
||||||
...p,
|
...p,
|
||||||
tags: p.tags ? JSON.parse(p.tags) : [],
|
tags: p.tags ? JSON.parse(p.tags) : [],
|
||||||
@@ -516,6 +559,10 @@ export const getAllParadigms = () => {
|
|||||||
customDimensions: p.custom_dimensions ? JSON.parse(p.custom_dimensions) : null,
|
customDimensions: p.custom_dimensions ? JSON.parse(p.custom_dimensions) : null,
|
||||||
logicParadigms: p.logic_paradigms ? JSON.parse(p.logic_paradigms) : null,
|
logicParadigms: p.logic_paradigms ? JSON.parse(p.logic_paradigms) : null,
|
||||||
selectedRefs: p.selected_refs ? JSON.parse(p.selected_refs) : [],
|
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,
|
isCustom: p.is_custom === 1,
|
||||||
autoMatchRefs: p.auto_match_refs === 1
|
autoMatchRefs: p.auto_match_refs === 1
|
||||||
}))
|
}))
|
||||||
@@ -526,11 +573,12 @@ export const getAllParadigms = () => {
|
|||||||
*/
|
*/
|
||||||
export const addParadigm = (paradigm) => {
|
export const addParadigm = (paradigm) => {
|
||||||
const id = paradigm.id || `paradigm-${Date.now()}`
|
const id = paradigm.id || `paradigm-${Date.now()}`
|
||||||
|
|
||||||
execute(`
|
execute(`
|
||||||
INSERT INTO paradigms (id, name, icon, description, tags, tag_class, system_constraints,
|
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)
|
dimension_set_id, custom_dimensions, logic_paradigms, auto_match_refs, selected_refs,
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
specialized_prompt, expert_guidelines, outline_template, recommended_tags, is_custom)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
`, [
|
`, [
|
||||||
id,
|
id,
|
||||||
paradigm.name,
|
paradigm.name,
|
||||||
@@ -544,9 +592,13 @@ export const addParadigm = (paradigm) => {
|
|||||||
paradigm.logicParadigms ? JSON.stringify(paradigm.logicParadigms) : null,
|
paradigm.logicParadigms ? JSON.stringify(paradigm.logicParadigms) : null,
|
||||||
paradigm.autoMatchRefs !== false ? 1 : 0,
|
paradigm.autoMatchRefs !== false ? 1 : 0,
|
||||||
JSON.stringify(paradigm.selectedRefs || []),
|
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
|
paradigm.isCustom ? 1 : 0
|
||||||
])
|
])
|
||||||
|
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -556,7 +608,7 @@ export const addParadigm = (paradigm) => {
|
|||||||
export const updateParadigm = (id, updates) => {
|
export const updateParadigm = (id, updates) => {
|
||||||
const setClauses = []
|
const setClauses = []
|
||||||
const params = []
|
const params = []
|
||||||
|
|
||||||
const fieldMap = {
|
const fieldMap = {
|
||||||
name: 'name',
|
name: 'name',
|
||||||
icon: 'icon',
|
icon: 'icon',
|
||||||
@@ -565,14 +617,14 @@ export const updateParadigm = (id, updates) => {
|
|||||||
dimensionSetId: 'dimension_set_id',
|
dimensionSetId: 'dimension_set_id',
|
||||||
autoMatchRefs: 'auto_match_refs'
|
autoMatchRefs: 'auto_match_refs'
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.entries(updates).forEach(([key, value]) => {
|
Object.entries(updates).forEach(([key, value]) => {
|
||||||
if (fieldMap[key]) {
|
if (fieldMap[key]) {
|
||||||
setClauses.push(`${fieldMap[key]} = ?`)
|
setClauses.push(`${fieldMap[key]} = ?`)
|
||||||
params.push(key === 'autoMatchRefs' ? (value ? 1 : 0) : value)
|
params.push(key === 'autoMatchRefs' ? (value ? 1 : 0) : value)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if (updates.tags !== undefined) {
|
if (updates.tags !== undefined) {
|
||||||
setClauses.push('tags = ?')
|
setClauses.push('tags = ?')
|
||||||
params.push(JSON.stringify(updates.tags))
|
params.push(JSON.stringify(updates.tags))
|
||||||
@@ -589,12 +641,28 @@ export const updateParadigm = (id, updates) => {
|
|||||||
setClauses.push('selected_refs = ?')
|
setClauses.push('selected_refs = ?')
|
||||||
params.push(JSON.stringify(updates.selectedRefs))
|
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')
|
setClauses.push('updated_at = CURRENT_TIMESTAMP')
|
||||||
params.push(id)
|
params.push(id)
|
||||||
|
|
||||||
execute(`UPDATE paradigms SET ${setClauses.join(', ')} WHERE id = ?`, params)
|
execute(`UPDATE paradigms SET ${setClauses.join(', ')} WHERE id = ?`, params)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,15 @@ import { ref, computed } from 'vue'
|
|||||||
/**
|
/**
|
||||||
* 自定义范式管理 Store
|
* 自定义范式管理 Store
|
||||||
* 用于管理用户通过需求文档生成的自定义范式
|
* 用于管理用户通过需求文档生成的自定义范式
|
||||||
|
* 现已迁移到数据库存储(IndexedDB/SQLite)
|
||||||
*/
|
*/
|
||||||
export const useParadigmStore = defineStore('paradigm', () => {
|
export const useParadigmStore = defineStore('paradigm', () => {
|
||||||
// 自定义范式列表(存储在 localStorage)
|
// 自定义范式列表(从数据库加载)
|
||||||
const customParadigms = ref([])
|
const customParadigms = ref([])
|
||||||
|
|
||||||
|
// 数据库是否已初始化
|
||||||
|
const isDbInitialized = ref(false)
|
||||||
|
|
||||||
// 当前正在编辑的范式
|
// 当前正在编辑的范式
|
||||||
const editingParadigm = ref(null)
|
const editingParadigm = ref(null)
|
||||||
|
|
||||||
@@ -19,14 +23,62 @@ export const useParadigmStore = defineStore('paradigm', () => {
|
|||||||
const parsingProgress = ref('')
|
const parsingProgress = ref('')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从 localStorage 加载自定义范式
|
* 从数据库加载自定义范式
|
||||||
|
* 如果 localStorage 中有旧数据,自动迁移到数据库
|
||||||
*/
|
*/
|
||||||
function loadCustomParadigms() {
|
async function loadCustomParadigms() {
|
||||||
try {
|
try {
|
||||||
const stored = localStorage.getItem('customParadigms')
|
// 动态导入数据库模块(避免循环依赖)
|
||||||
if (stored) {
|
const { getAllParadigms, addParadigm, updateParadigm } = await import('../db/index.js')
|
||||||
customParadigms.value = JSON.parse(stored)
|
|
||||||
|
// 从数据库加载所有范式
|
||||||
|
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) {
|
} catch (error) {
|
||||||
console.error('加载自定义范式失败:', error)
|
console.error('加载自定义范式失败:', error)
|
||||||
customParadigms.value = []
|
customParadigms.value = []
|
||||||
@@ -34,11 +86,26 @@ export const useParadigmStore = defineStore('paradigm', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存自定义范式到 localStorage
|
* 保存单个自定义范式到数据库(替换旧的批量保存)
|
||||||
*/
|
*/
|
||||||
function saveCustomParadigms() {
|
async function saveCustomParadigm(paradigm) {
|
||||||
try {
|
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) {
|
} catch (error) {
|
||||||
console.error('保存自定义范式失败:', error)
|
console.error('保存自定义范式失败:', error)
|
||||||
}
|
}
|
||||||
@@ -48,7 +115,7 @@ export const useParadigmStore = defineStore('paradigm', () => {
|
|||||||
* 添加自定义范式
|
* 添加自定义范式
|
||||||
* @param {Object} paradigm - 范式对象
|
* @param {Object} paradigm - 范式对象
|
||||||
*/
|
*/
|
||||||
function addCustomParadigm(paradigm) {
|
async function addCustomParadigm(paradigm) {
|
||||||
// 检查是否已存在相同ID
|
// 检查是否已存在相同ID
|
||||||
const index = customParadigms.value.findIndex(p => p.id === paradigm.id)
|
const index = customParadigms.value.findIndex(p => p.id === paradigm.id)
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
@@ -58,16 +125,21 @@ export const useParadigmStore = defineStore('paradigm', () => {
|
|||||||
// 添加新范式
|
// 添加新范式
|
||||||
customParadigms.value.push(paradigm)
|
customParadigms.value.push(paradigm)
|
||||||
}
|
}
|
||||||
saveCustomParadigms()
|
await saveCustomParadigm(paradigm)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除自定义范式
|
* 删除自定义范式
|
||||||
* @param {string} paradigmId - 范式ID
|
* @param {string} paradigmId - 范式ID
|
||||||
*/
|
*/
|
||||||
function deleteCustomParadigm(paradigmId) {
|
async function deleteCustomParadigm(paradigmId) {
|
||||||
customParadigms.value = customParadigms.value.filter(p => p.id !== paradigmId)
|
try {
|
||||||
saveCustomParadigms()
|
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 {string} field - 字段名
|
||||||
* @param {any} value - 新值
|
* @param {any} value - 新值
|
||||||
*/
|
*/
|
||||||
function updateParadigmField(paradigmId, field, value) {
|
async function updateParadigmField(paradigmId, field, value) {
|
||||||
const paradigm = getCustomParadigmById(paradigmId)
|
const paradigm = getCustomParadigmById(paradigmId)
|
||||||
if (paradigm) {
|
if (paradigm) {
|
||||||
paradigm[field] = value
|
paradigm[field] = value
|
||||||
saveCustomParadigms()
|
await saveCustomParadigm(paradigm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,9 +242,14 @@ export const useParadigmStore = defineStore('paradigm', () => {
|
|||||||
/**
|
/**
|
||||||
* 清空所有自定义范式(慎用)
|
* 清空所有自定义范式(慎用)
|
||||||
*/
|
*/
|
||||||
function clearAllCustomParadigms() {
|
async function clearAllCustomParadigms() {
|
||||||
customParadigms.value = []
|
try {
|
||||||
saveCustomParadigms()
|
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
|
return updatedParadigm
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化时加载
|
// 初始化时加载(异步)
|
||||||
loadCustomParadigms()
|
loadCustomParadigms()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -243,6 +320,7 @@ export const useParadigmStore = defineStore('paradigm', () => {
|
|||||||
editingParadigm,
|
editingParadigm,
|
||||||
isParsing,
|
isParsing,
|
||||||
parsingProgress,
|
parsingProgress,
|
||||||
|
isDbInitialized,
|
||||||
|
|
||||||
// 计算属性
|
// 计算属性
|
||||||
customParadigmCount,
|
customParadigmCount,
|
||||||
@@ -250,7 +328,7 @@ export const useParadigmStore = defineStore('paradigm', () => {
|
|||||||
|
|
||||||
// 方法
|
// 方法
|
||||||
loadCustomParadigms,
|
loadCustomParadigms,
|
||||||
saveCustomParadigms,
|
saveCustomParadigm, // 单个保存(新)
|
||||||
addCustomParadigm,
|
addCustomParadigm,
|
||||||
deleteCustomParadigm,
|
deleteCustomParadigm,
|
||||||
getCustomParadigmById,
|
getCustomParadigmById,
|
||||||
|
|||||||
Reference in New Issue
Block a user