import Database from 'better-sqlite3'; import path from 'path'; import fs from 'fs'; import { fileURLToPath } from 'url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const DATA_DIR = path.join(__dirname, '../data'); const DB_PATH = path.join(DATA_DIR, 'paradigms.db'); if (!fs.existsSync(DATA_DIR)) { fs.mkdirSync(DATA_DIR, { recursive: true }); } const db = new Database(DB_PATH); db.pragma('journal_mode = WAL'); db.exec(` CREATE TABLE IF NOT EXISTS materials ( id TEXT PRIMARY KEY, type TEXT NOT NULL, title TEXT NOT NULL, source TEXT, date TEXT, tags TEXT, related_dimension_sets TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, is_default INTEGER DEFAULT 0 ); CREATE TABLE IF NOT EXISTS reference_excerpts ( id TEXT PRIMARY KEY, reference_id TEXT NOT NULL, topic TEXT NOT NULL, content TEXT NOT NULL, applicable_dimensions TEXT, use_for TEXT, FOREIGN KEY (reference_id) REFERENCES materials(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS paradigms ( id TEXT PRIMARY KEY, name TEXT NOT NULL, icon TEXT, description TEXT, tags TEXT, tag_class TEXT, system_constraints TEXT, dimension_set_id TEXT, custom_dimensions TEXT, 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 ); CREATE TABLE IF NOT EXISTS dimension_sets ( id TEXT PRIMARY KEY, name TEXT NOT NULL, description TEXT, applicable_for TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, is_custom INTEGER DEFAULT 0 ); CREATE TABLE IF NOT EXISTS dimensions ( id TEXT PRIMARY KEY, dimension_set_id TEXT NOT NULL, name TEXT NOT NULL, focus TEXT, keywords TEXT, negative_keywords TEXT, positive_benchmark TEXT, sort_order INTEGER DEFAULT 0, FOREIGN KEY (dimension_set_id) REFERENCES dimension_sets(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS user_config ( key TEXT PRIMARY KEY, value TEXT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS analysis_history ( id INTEGER PRIMARY KEY AUTOINCREMENT, paradigm_id TEXT, input_text TEXT, result TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS documents ( id TEXT PRIMARY KEY, title TEXT NOT NULL, content TEXT, paradigm_id TEXT, dimension_set_id TEXT, selected_refs TEXT, status TEXT DEFAULT 'draft', word_count INTEGER DEFAULT 0, tags TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS document_versions ( id INTEGER PRIMARY KEY AUTOINCREMENT, document_id TEXT NOT NULL, content TEXT, version_number INTEGER, change_note TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (document_id) REFERENCES documents(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS outline_materials ( id TEXT PRIMARY KEY, name TEXT NOT NULL, content TEXT NOT NULL, word_count INTEGER DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ); `); const ensureColumn = (table, column, definition) => { const columns = db.prepare(`PRAGMA table_info(${table})`).all(); const exists = columns.some(col => col.name === column); if (!exists) { try { db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`); } catch (error) { console.warn(`⚠️ 字段迁移失败: ${table}.${column}`, error.message); } } }; const ensureSchema = () => { ensureColumn('paradigms', 'system_constraints', 'TEXT'); ensureColumn('paradigms', 'dimension_set_id', 'TEXT'); ensureColumn('paradigms', 'custom_dimensions', 'TEXT'); ensureColumn('paradigms', 'logic_paradigms', 'TEXT'); ensureColumn('paradigms', 'auto_match_refs', 'INTEGER DEFAULT 1'); ensureColumn('paradigms', 'selected_refs', 'TEXT'); ensureColumn('paradigms', 'outline_template', 'TEXT'); ensureColumn('paradigms', 'recommended_tags', 'TEXT'); ensureColumn('paradigms', 'tag_class', "TEXT"); ensureColumn('paradigms', 'tags', 'TEXT'); ensureColumn('paradigms', 'specialized_prompt', 'TEXT'); ensureColumn('paradigms', 'expert_guidelines', 'TEXT'); ensureColumn('paradigms', 'is_custom', 'INTEGER DEFAULT 0'); ensureColumn('paradigms', 'created_at', 'TEXT'); ensureColumn('paradigms', 'updated_at', 'TEXT'); }; ensureSchema(); const parseJson = (value, fallback) => { if (!value) return fallback; try { return JSON.parse(value); } catch { return fallback; } }; const getExcerptsByReferenceId = (referenceId) => { const rows = db.prepare('SELECT * FROM reference_excerpts WHERE reference_id = ?').all(referenceId); return rows.map(row => ({ ...row, applicableDimensions: parseJson(row.applicable_dimensions, []), useFor: row.use_for || null })); }; const seedDefaultReferences = async () => { const count = db.prepare('SELECT COUNT(*) as count FROM materials').get().count; if (count > 0) return; try { const { REFERENCES } = await import('../src/config/references.js'); const insertMaterial = db.prepare(` INSERT INTO materials (id, type, title, source, date, tags, related_dimension_sets, is_default) VALUES (?, ?, ?, ?, ?, ?, ?, ?) `); const insertExcerpt = db.prepare(` INSERT INTO reference_excerpts (id, reference_id, topic, content, applicable_dimensions, use_for) VALUES (?, ?, ?, ?, ?, ?) `); const insertMany = db.transaction((items) => { items.forEach((ref) => { insertMaterial.run( ref.id, ref.type, ref.title, ref.source || null, ref.date || null, JSON.stringify(ref.tags || []), JSON.stringify(ref.relatedDimensionSets || []), 1 ); if (ref.excerpts?.length) { ref.excerpts.forEach((excerpt, index) => { insertExcerpt.run( excerpt.id || `${ref.id}-excerpt-${index}`, ref.id, excerpt.topic, excerpt.content, JSON.stringify(excerpt.applicableDimensions || []), excerpt.useFor || null ); }); } }); }); insertMany(Object.values(REFERENCES)); console.log('✅ 默认素材导入完成'); } catch (error) { console.warn('⚠️ 默认素材导入失败:', error.message); } }; await seedDefaultReferences(); /** * 同步现有的提纲素材到通用素材库 */ const syncExistingOutlineMaterials = () => { try { const materials = db.prepare('SELECT * FROM outline_materials').all(); if (materials.length === 0) return; console.log(`🔍 正在同步 ${materials.length} 个存量提纲素材到通用素材库...`); db.transaction(() => { materials.forEach(mat => { syncToReferences(mat.id, mat.name, mat.content); }); })(); console.log(`✅ 存量提纲素材同步完成`); } catch (err) { console.error('⚠️ 同步存量素材失败:', err.message); } }; syncExistingOutlineMaterials(); console.log('📦 SQLite 数据库初始化完成:', DB_PATH); export function getAllReferences() { const refs = db.prepare('SELECT * FROM materials ORDER BY created_at DESC').all(); return refs.map(ref => ({ ...ref, tags: parseJson(ref.tags, []), relatedDimensionSets: parseJson(ref.related_dimension_sets, []), excerpts: getExcerptsByReferenceId(ref.id) })); } export function getReferenceById(id) { const ref = db.prepare('SELECT * FROM materials WHERE id = ?').get(id); if (!ref) return null; return { ...ref, tags: parseJson(ref.tags, []), relatedDimensionSets: parseJson(ref.related_dimension_sets, []), excerpts: getExcerptsByReferenceId(ref.id) }; } export function getReferencesByType(type) { const refs = db.prepare('SELECT * FROM materials WHERE type = ? ORDER BY created_at DESC').all(type); return refs.map(ref => ({ ...ref, tags: parseJson(ref.tags, []), relatedDimensionSets: parseJson(ref.related_dimension_sets, []), excerpts: getExcerptsByReferenceId(ref.id) })); } export function addReference(reference) { const id = reference.id || `ref-${Date.now()}`; db.prepare(` INSERT INTO materials (id, type, title, source, date, tags, related_dimension_sets, is_default) VALUES (?, ?, ?, ?, ?, ?, ?, ?) `).run( id, reference.type, reference.title, reference.source || null, reference.date || null, JSON.stringify(reference.tags || []), JSON.stringify(reference.relatedDimensionSets || []), reference.isDefault ? 1 : 0 ); if (reference.excerpts?.length) { const insertExcerpt = db.prepare(` INSERT INTO reference_excerpts (id, reference_id, topic, content, applicable_dimensions, use_for) VALUES (?, ?, ?, ?, ?, ?) `); reference.excerpts.forEach((excerpt, index) => { insertExcerpt.run( excerpt.id || `${id}-excerpt-${index}`, id, excerpt.topic, excerpt.content, JSON.stringify(excerpt.applicableDimensions || []), excerpt.useFor || null ); }); } return id; } export function updateReference(id, updates) { const setClauses = []; const params = []; if (updates.type !== undefined) { setClauses.push('type = ?'); params.push(updates.type); } if (updates.title !== undefined) { setClauses.push('title = ?'); params.push(updates.title); } if (updates.source !== undefined) { setClauses.push('source = ?'); params.push(updates.source); } if (updates.tags !== undefined) { setClauses.push('tags = ?'); params.push(JSON.stringify(updates.tags)); } if (updates.relatedDimensionSets !== undefined) { setClauses.push('related_dimension_sets = ?'); params.push(JSON.stringify(updates.relatedDimensionSets)); } setClauses.push('updated_at = CURRENT_TIMESTAMP'); params.push(id); db.prepare(`UPDATE materials SET ${setClauses.join(', ')} WHERE id = ?`).run(...params); return true; } export function deleteReference(id) { db.prepare('DELETE FROM reference_excerpts WHERE reference_id = ?').run(id); db.prepare('DELETE FROM materials WHERE id = ?').run(id); return true; } export function getAllParadigms() { const paradigms = db.prepare('SELECT * FROM paradigms ORDER BY is_custom ASC, created_at DESC').all(); return paradigms.map(p => ({ ...p, tagClass: p.tag_class || 'bg-blue-900/30 text-blue-300', tags: parseJson(p.tags, []), systemConstraints: parseJson(p.system_constraints, []), customDimensions: parseJson(p.custom_dimensions, null), logicParadigms: parseJson(p.logic_paradigms, null), selectedRefs: parseJson(p.selected_refs, []), specializedPrompt: p.specialized_prompt || null, expertGuidelines: parseJson(p.expert_guidelines, null), outlineTemplate: p.outline_template || null, recommendedTags: parseJson(p.recommended_tags, []), isCustom: p.is_custom === 1, autoMatchRefs: p.auto_match_refs === 1 })); } export function getParadigmById(id) { const p = db.prepare('SELECT * FROM paradigms WHERE id = ?').get(id); if (!p) return null; return { ...p, tagClass: p.tag_class || 'bg-blue-900/30 text-blue-300', tags: parseJson(p.tags, []), systemConstraints: parseJson(p.system_constraints, []), customDimensions: parseJson(p.custom_dimensions, null), logicParadigms: parseJson(p.logic_paradigms, null), selectedRefs: parseJson(p.selected_refs, []), specializedPrompt: p.specialized_prompt || null, expertGuidelines: parseJson(p.expert_guidelines, null), outlineTemplate: p.outline_template || null, recommendedTags: parseJson(p.recommended_tags, []), isCustom: p.is_custom === 1, autoMatchRefs: p.auto_match_refs === 1 }; } export function addParadigm(paradigm) { const id = paradigm.id || `paradigm-${Date.now()}`; db.prepare(` 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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `).run( id, paradigm.name, paradigm.icon || '📝', paradigm.description || null, JSON.stringify(paradigm.tags || []), paradigm.tagClass || 'bg-blue-900/30 text-blue-300', JSON.stringify(paradigm.systemConstraints || []), paradigm.dimensionSetId || null, paradigm.customDimensions ? JSON.stringify(paradigm.customDimensions) : null, 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; } export function updateParadigm(id, updates) { const setClauses = []; const params = []; const fieldMap = { name: 'name', icon: 'icon', description: 'description', tagClass: 'tag_class', 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)); } if (updates.systemConstraints !== undefined) { setClauses.push('system_constraints = ?'); params.push(JSON.stringify(updates.systemConstraints)); } if (updates.customDimensions !== undefined) { setClauses.push('custom_dimensions = ?'); params.push(updates.customDimensions ? JSON.stringify(updates.customDimensions) : null); } if (updates.logicParadigms !== undefined) { setClauses.push('logic_paradigms = ?'); params.push(updates.logicParadigms ? JSON.stringify(updates.logicParadigms) : null); } if (updates.selectedRefs !== undefined) { 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); db.prepare(`UPDATE paradigms SET ${setClauses.join(', ')} WHERE id = ?`).run(...params); return true; } export function deleteParadigm(id) { db.prepare('DELETE FROM paradigms WHERE id = ?').run(id); return true; } export function getConfig(key, defaultValue = null) { const result = db.prepare('SELECT value FROM user_config WHERE key = ?').get(key); if (!result) return defaultValue; return parseJson(result.value, result.value); } export function setConfig(key, value) { const valueStr = typeof value === 'string' ? value : JSON.stringify(value); db.prepare(` INSERT INTO user_config (key, value, updated_at) VALUES (?, ?, CURRENT_TIMESTAMP) ON CONFLICT(key) DO UPDATE SET value = ?, updated_at = CURRENT_TIMESTAMP `).run(key, valueStr, valueStr); return true; } export function getAllDocuments() { const docs = db.prepare('SELECT * FROM documents ORDER BY updated_at DESC').all(); return docs.map(doc => ({ ...doc, tags: parseJson(doc.tags, []), selectedRefs: parseJson(doc.selected_refs, []) })); } export function getDocumentById(id) { const doc = db.prepare('SELECT * FROM documents WHERE id = ?').get(id); if (!doc) return null; return { ...doc, tags: parseJson(doc.tags, []), selectedRefs: parseJson(doc.selected_refs, []), versions: getDocumentVersions(id) }; } export function getDocumentVersions(documentId) { return db.prepare('SELECT * FROM document_versions WHERE document_id = ? ORDER BY version_number DESC').all(documentId); } export function createDocument(document) { const id = document.id || `doc-${Date.now()}`; db.prepare(` INSERT INTO documents (id, title, content, paradigm_id, dimension_set_id, selected_refs, status, word_count, tags) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) `).run( id, document.title || '未命名文稿', document.content || '', document.paradigmId || null, document.dimensionSetId || null, JSON.stringify(document.selectedRefs || []), document.status || 'draft', document.wordCount || 0, JSON.stringify(document.tags || []) ); return id; } export function updateDocument(id, updates) { const setClauses = []; const params = []; if (updates.title !== undefined) { setClauses.push('title = ?'); params.push(updates.title); } if (updates.content !== undefined) { setClauses.push('content = ?'); params.push(updates.content); setClauses.push('word_count = ?'); params.push(updates.content.length); } if (updates.paradigmId !== undefined) { setClauses.push('paradigm_id = ?'); params.push(updates.paradigmId); } if (updates.dimensionSetId !== undefined) { setClauses.push('dimension_set_id = ?'); params.push(updates.dimensionSetId); } if (updates.status !== undefined) { setClauses.push('status = ?'); params.push(updates.status); } if (updates.tags !== undefined) { setClauses.push('tags = ?'); params.push(JSON.stringify(updates.tags)); } if (updates.selectedRefs !== undefined) { setClauses.push('selected_refs = ?'); params.push(JSON.stringify(updates.selectedRefs)); } setClauses.push('updated_at = CURRENT_TIMESTAMP'); params.push(id); db.prepare(`UPDATE documents SET ${setClauses.join(', ')} WHERE id = ?`).run(...params); return true; } export function saveDocumentVersion(documentId, content, changeNote = '') { const result = db.prepare('SELECT MAX(version_number) as max_version FROM document_versions WHERE document_id = ?').get(documentId); const nextVersion = (result?.max_version || 0) + 1; db.prepare(` INSERT INTO document_versions (document_id, content, version_number, change_note) VALUES (?, ?, ?, ?) `).run(documentId, content, nextVersion, changeNote); return nextVersion; } export function deleteDocument(id) { db.prepare('DELETE FROM document_versions WHERE document_id = ?').run(id); db.prepare('DELETE FROM documents WHERE id = ?').run(id); return true; } export function clearDocuments() { db.prepare('DELETE FROM document_versions').run(); db.prepare('DELETE FROM documents').run(); return true; } export function getDocumentsByStatus(status) { const docs = db.prepare('SELECT * FROM documents WHERE status = ? ORDER BY updated_at DESC').all(status); return docs.map(doc => ({ ...doc, tags: parseJson(doc.tags, []), selectedRefs: parseJson(doc.selected_refs, []) })); } export function getAllOutlineMaterials() { return db.prepare('SELECT * FROM outline_materials ORDER BY created_at DESC').all(); } /** * 将提纲素材同步到通用素材库 (materials/excerpts) * 提纲素材作为 'outline' 类型存储,便于在通用素材库中管理 */ const syncToReferences = (id, name, content) => { const refId = `ref-${id}`; // 使用固定前缀关联 // 1. 更新或插入到 materials 表 db.prepare(` INSERT INTO materials (id, type, title, source, is_default, created_at, updated_at) VALUES (?, 'outline', ?, '提纲写作', 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) ON CONFLICT(id) DO UPDATE SET title = EXCLUDED.title, updated_at = CURRENT_TIMESTAMP `).run(refId, name); // 2. 更新或插入到 reference_excerpts 表 const excerptId = `${refId}-content`; db.prepare(` INSERT INTO reference_excerpts (id, reference_id, topic, content) VALUES (?, ?, '正文', ?) ON CONFLICT(id) DO UPDATE SET content = EXCLUDED.content `).run(excerptId, refId, content); }; export function addOutlineMaterial(material) { const id = material.id || `omat-${Date.now()}`; db.prepare(` INSERT INTO outline_materials (id, name, content, word_count) VALUES (?, ?, ?, ?) `).run( id, material.name, material.content, material.content?.length || 0 ); // 同步到通用素材库 try { syncToReferences(id, material.name, material.content); } catch (err) { console.error('同步素材到通用库失败:', err); } return id; } export function updateOutlineMaterial(id, updates) { const setClauses = []; const params = []; if (updates.name !== undefined) { setClauses.push('name = ?'); params.push(updates.name); } if (updates.content !== undefined) { setClauses.push('content = ?'); params.push(updates.content); setClauses.push('word_count = ?'); params.push(updates.content?.length || 0); } setClauses.push('updated_at = CURRENT_TIMESTAMP'); params.push(id); db.prepare(`UPDATE outline_materials SET ${setClauses.join(', ')} WHERE id = ?`).run(...params); // 如果更新了名称或内容,需要同步 try { const current = db.prepare('SELECT * FROM outline_materials WHERE id = ?').get(id); if (current) { syncToReferences(id, current.name, current.content); } } catch (err) { console.error('更新素材同步失败:', err); } return true; } export function deleteOutlineMaterial(id) { db.prepare('DELETE FROM outline_materials WHERE id = ?').run(id); // 同时从通用库删除 (如果存在) try { const refId = `ref-${id}`; db.prepare('DELETE FROM reference_excerpts WHERE reference_id = ?').run(refId); db.prepare('DELETE FROM materials WHERE id = ?').run(refId); } catch (err) { console.error('删除素材同步失败:', err); } return true; } export function exportDatabase() { return fs.readFileSync(DB_PATH); } export function exportAsJSON() { return { references: getAllReferences(), paradigms: getAllParadigms(), documents: getAllDocuments(), config: db.prepare('SELECT * FROM user_config').all(), exportedAt: new Date().toISOString() }; } export async function resetDatabase() { db.exec(` DROP TABLE IF EXISTS reference_excerpts; DROP TABLE IF EXISTS materials; DROP TABLE IF EXISTS paradigms; DROP TABLE IF EXISTS dimension_sets; DROP TABLE IF EXISTS dimensions; DROP TABLE IF EXISTS user_config; DROP TABLE IF EXISTS analysis_history; DROP TABLE IF EXISTS documents; DROP TABLE IF EXISTS document_versions; DROP TABLE IF EXISTS outline_materials; `); db.exec(` CREATE TABLE IF NOT EXISTS materials ( id TEXT PRIMARY KEY, type TEXT NOT NULL, title TEXT NOT NULL, source TEXT, date TEXT, tags TEXT, related_dimension_sets TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, is_default INTEGER DEFAULT 0 ); CREATE TABLE IF NOT EXISTS reference_excerpts ( id TEXT PRIMARY KEY, reference_id TEXT NOT NULL, topic TEXT NOT NULL, content TEXT NOT NULL, applicable_dimensions TEXT, use_for TEXT, FOREIGN KEY (reference_id) REFERENCES materials(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS paradigms ( id TEXT PRIMARY KEY, name TEXT NOT NULL, icon TEXT, description TEXT, tags TEXT, tag_class TEXT, system_constraints TEXT, dimension_set_id TEXT, custom_dimensions TEXT, 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 ); CREATE TABLE IF NOT EXISTS dimension_sets ( id TEXT PRIMARY KEY, name TEXT NOT NULL, description TEXT, applicable_for TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, is_custom INTEGER DEFAULT 0 ); CREATE TABLE IF NOT EXISTS dimensions ( id TEXT PRIMARY KEY, dimension_set_id TEXT NOT NULL, name TEXT NOT NULL, focus TEXT, keywords TEXT, negative_keywords TEXT, positive_benchmark TEXT, sort_order INTEGER DEFAULT 0, FOREIGN KEY (dimension_set_id) REFERENCES dimension_sets(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS user_config ( key TEXT PRIMARY KEY, value TEXT, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS analysis_history ( id INTEGER PRIMARY KEY AUTOINCREMENT, paradigm_id TEXT, input_text TEXT, result TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS documents ( id TEXT PRIMARY KEY, title TEXT NOT NULL, content TEXT, paradigm_id TEXT, dimension_set_id TEXT, selected_refs TEXT, status TEXT DEFAULT 'draft', word_count INTEGER DEFAULT 0, tags TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS document_versions ( id INTEGER PRIMARY KEY AUTOINCREMENT, document_id TEXT NOT NULL, content TEXT, version_number INTEGER, change_note TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (document_id) REFERENCES documents(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS outline_materials ( id TEXT PRIMARY KEY, name TEXT NOT NULL, content TEXT NOT NULL, word_count INTEGER DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ); `); await seedDefaultReferences(); console.log('🔄 数据库已重置并恢复默认数据'); return true; } export default db;