重构数据库管理逻辑,简化用户数据库初始化流程。引入新的数据库管理类以支持动态数据库名称和用户状态管理。更新应用启动逻辑以确保在用户登录时正确初始化数据库。增强持久化数据恢复功能,确保用户数据的可靠性和一致性。
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user