重构数据库管理逻辑,简化用户数据库初始化流程。引入新的数据库管理类以支持动态数据库名称和用户状态管理。更新应用启动逻辑以确保在用户登录时正确初始化数据库。增强持久化数据恢复功能,确保用户数据的可靠性和一致性。

This commit is contained in:
超级老白兔
2025-11-13 11:58:12 +08:00
parent eb5dbe5066
commit ae4a165b07
7 changed files with 342 additions and 150 deletions

View File

@@ -16,6 +16,8 @@
*/
import Dexie, { Table } from "dexie";
import { getPersistedData, PERSIST_KEYS } from "@/store/persistUtils";
const DB_NAME_PREFIX = "CunkebaoDatabase";
// ==================== 用户登录记录 ====================
export interface UserLoginRecord {
@@ -123,8 +125,8 @@ class CunkebaoDatabase extends Dexie {
contactLabelMap!: Table<ContactLabelMap>; // 联系人标签映射表
userLoginRecords!: Table<UserLoginRecord>; // 用户登录记录表
constructor() {
super("CunkebaoDatabase");
constructor(dbName: string) {
super(dbName);
// 版本1统一表结构
this.version(1).stores({
@@ -188,12 +190,148 @@ class CunkebaoDatabase extends Dexie {
}
}
// 创建数据库实例
export const db = new CunkebaoDatabase();
class DatabaseManager {
private currentDb: CunkebaoDatabase | null = null;
private currentUserId: number | null = null;
private getDatabaseName(userId: number) {
return `${DB_NAME_PREFIX}_${userId}`;
}
private async openDatabase(dbName: string) {
const instance = new CunkebaoDatabase(dbName);
await instance.open();
return instance;
}
async ensureDatabase(userId: number) {
if (userId === undefined || userId === null) {
throw new Error("Invalid userId provided for database initialization");
}
if (
this.currentDb &&
this.currentUserId === userId &&
this.currentDb.isOpen()
) {
return this.currentDb;
}
await this.closeCurrentDatabase();
const dbName = this.getDatabaseName(userId);
this.currentDb = await this.openDatabase(dbName);
this.currentUserId = userId;
return this.currentDb;
}
getCurrentDatabase(): CunkebaoDatabase {
if (!this.currentDb) {
throw new Error("Database has not been initialized for the current user");
}
return this.currentDb;
}
getCurrentUserId() {
return this.currentUserId;
}
isInitialized(): boolean {
return !!this.currentDb && this.currentDb.isOpen();
}
async closeCurrentDatabase() {
if (this.currentDb) {
try {
this.currentDb.close();
} catch (error) {
console.warn("Failed to close current database:", error);
}
this.currentDb = null;
}
this.currentUserId = null;
}
}
export const databaseManager = new DatabaseManager();
let pendingDatabaseRestore: Promise<CunkebaoDatabase | null> | null = null;
async function restoreDatabaseFromPersistedState() {
if (typeof window === "undefined") {
return null;
}
const persistedData = getPersistedData<string | Record<string, any>>(
PERSIST_KEYS.USER_STORE,
"localStorage",
);
if (!persistedData) {
return null;
}
let parsed: any = persistedData;
if (typeof persistedData === "string") {
try {
parsed = JSON.parse(persistedData);
} catch (error) {
console.warn("Failed to parse persisted user-store value:", error);
return null;
}
}
const state = parsed?.state ?? parsed;
const userId = state?.user?.id;
if (!userId) {
return null;
}
try {
return await databaseManager.ensureDatabase(userId);
} catch (error) {
console.warn("Failed to initialize database from persisted user:", error);
return null;
}
}
export async function initializeDatabaseFromPersistedUser() {
if (databaseManager.isInitialized()) {
return databaseManager.getCurrentDatabase();
}
if (!pendingDatabaseRestore) {
pendingDatabaseRestore = restoreDatabaseFromPersistedState().finally(() => {
pendingDatabaseRestore = null;
});
}
return pendingDatabaseRestore;
}
const dbProxy = new Proxy({} as CunkebaoDatabase, {
get(_target, prop: string | symbol) {
const currentDb = databaseManager.getCurrentDatabase();
const value = (currentDb as any)[prop];
if (typeof value === "function") {
return value.bind(currentDb);
}
return value;
},
});
export const db = dbProxy;
// 简单的数据库操作类
export class DatabaseService<T> {
constructor(private table: Table<T>) {}
constructor(private readonly tableAccessor: () => Table<T>) {}
private get table(): Table<T> {
return this.tableAccessor();
}
// 基础 CRUD 操作 - 使用serverId作为主键
async create(data: Omit<T, "serverId">): Promise<string | number> {
@@ -446,10 +584,18 @@ export class DatabaseService<T> {
}
// 创建统一表的服务实例
export const chatSessionService = new DatabaseService(db.chatSessions);
export const contactUnifiedService = new DatabaseService(db.contactsUnified);
export const contactLabelMapService = new DatabaseService(db.contactLabelMap);
export const userLoginRecordService = new DatabaseService(db.userLoginRecords);
export const chatSessionService = new DatabaseService<ChatSession>(
() => databaseManager.getCurrentDatabase().chatSessions,
);
export const contactUnifiedService = new DatabaseService<Contact>(
() => databaseManager.getCurrentDatabase().contactsUnified,
);
export const contactLabelMapService = new DatabaseService<ContactLabelMap>(
() => databaseManager.getCurrentDatabase().contactLabelMap,
);
export const userLoginRecordService = new DatabaseService<UserLoginRecord>(
() => databaseManager.getCurrentDatabase().userLoginRecords,
);
// 默认导出数据库实例
export default db;