import { Capacitor } from '@capacitor/core' import { CapacitorSQLite, SQLiteConnection } from '@capacitor-community/sqlite' import { defineCustomElements as defineJeep } from 'jeep-sqlite/loader' const DB_NAME = 'echo_local' const DB_VERSION = 1 const TRANSACTION_TABLE_SQL = ` CREATE TABLE IF NOT EXISTS transactions ( id TEXT PRIMARY KEY NOT NULL, amount REAL NOT NULL, merchant TEXT NOT NULL, category TEXT DEFAULT 'Uncategorized', date TEXT NOT NULL, note TEXT, sync_status INTEGER DEFAULT 0 ); ` let sqliteConnection let db let initialized = false let jeepLoaderPromise let jeepElementReadyPromise const waitFor = (ms = 100) => new Promise((resolve) => { setTimeout(resolve, ms) }) const ensureStoreReady = async (jeepEl, retries = 5) => { for (let attempt = 0; attempt < retries; attempt += 1) { const isOpen = (await jeepEl.isStoreOpen?.()) === true if (isOpen) return if (typeof jeepEl.openStore === 'function') { const opened = await jeepEl.openStore('jeepSqliteStore', 'databases') if (opened) return } await waitFor(200 * (attempt + 1)) } throw new Error('jeep-sqlite IndexedDB store 未初始化成功') } const ensureJeepElement = async () => { if (!jeepLoaderPromise) { jeepLoaderPromise = defineJeep(window) } await jeepLoaderPromise if (!jeepElementReadyPromise) { jeepElementReadyPromise = (async () => { let jeepEl = document.querySelector('jeep-sqlite') if (!jeepEl) { jeepEl = document.createElement('jeep-sqlite') jeepEl.setAttribute('auto-save', 'true') document.body.appendChild(jeepEl) } jeepEl.setAttribute('wasm-path', '/assets') await customElements.whenDefined('jeep-sqlite') await jeepEl.componentOnReady?.() return jeepEl })() } const element = await jeepElementReadyPromise await ensureStoreReady(element) await CapacitorSQLite.initWebStore() } const prepareConnection = async () => { if (!sqliteConnection) { sqliteConnection = new SQLiteConnection(CapacitorSQLite) } if (Capacitor.getPlatform() === 'web') { await ensureJeepElement() } const consistency = await sqliteConnection.checkConnectionsConsistency() if (!consistency.result) { await sqliteConnection.closeAllConnections() } const isConn = (await sqliteConnection.isConnection(DB_NAME, false)).result if (isConn) { db = await sqliteConnection.retrieveConnection(DB_NAME, false) } else { db = await sqliteConnection.createConnection(DB_NAME, false, 'no-encryption', DB_VERSION, false) } await db.open() await db.execute(TRANSACTION_TABLE_SQL) initialized = true } export const initSQLite = async () => { if (!initialized) { await prepareConnection() } return db } export const getDb = async () => { if (!initialized) { await initSQLite() } return db } export const saveDbToStore = async () => { await initSQLite() if (!sqliteConnection?.saveToStore) return try { await sqliteConnection.saveToStore(DB_NAME) } catch (error) { console.warn('[sqlite] saveToStore 执行失败,数据将保留在内存中', error) } } export const closeSQLite = async () => { if (db) { await db.close() db = null } initialized = false } export const databaseName = DB_NAME