|
@@ -0,0 +1,193 @@
|
|
|
+import { defineStore } from "pinia";
|
|
|
+
|
|
|
+interface IndexedDBStoreConfig {
|
|
|
+ name: string;
|
|
|
+ keyPath: string;
|
|
|
+ indexes?: Array<{
|
|
|
+ name: string
|
|
|
+ keyPath: string | string[]
|
|
|
+ options?: IDBIndexParameters
|
|
|
+ }>;
|
|
|
+}
|
|
|
+
|
|
|
+interface IndexedDBConfig {
|
|
|
+ dbName: string;
|
|
|
+ version?: number;
|
|
|
+}
|
|
|
+
|
|
|
+export const useIndexedDBStore = defineStore("indexedDB", {
|
|
|
+ state: () => ({
|
|
|
+ storeRegistry: new Map<string, IndexedDBStoreConfig>(),
|
|
|
+ dbName: <string>"",
|
|
|
+ db: <IDBDatabase | null>null,
|
|
|
+ currentVersion: <number>0,
|
|
|
+ isInitialized: <boolean>false
|
|
|
+ }),
|
|
|
+ actions: {
|
|
|
+ registerStore(storeConfig: IndexedDBStoreConfig) {
|
|
|
+ if (!this.storeRegistry.has(storeConfig.name)) {
|
|
|
+ this.storeRegistry.set(storeConfig.name, storeConfig);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ deleteDB() {
|
|
|
+ return new Promise<boolean>((resolve, reject) => {
|
|
|
+ const request = indexedDB.deleteDatabase(this.dbName);
|
|
|
+ request.onsuccess = () => {
|
|
|
+ resolve(true);
|
|
|
+ window.location.reload();
|
|
|
+ };
|
|
|
+ request.onerror = () => {
|
|
|
+ reject(request.error);
|
|
|
+ };
|
|
|
+ });
|
|
|
+ },
|
|
|
+ openDB(config: IndexedDBConfig) {
|
|
|
+ if (config) {
|
|
|
+ this.dbName = config.dbName;
|
|
|
+ this.currentVersion = config.version || 1;
|
|
|
+ }
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ const request = indexedDB.open(this.dbName, this.currentVersion);
|
|
|
+ request.onupgradeneeded = (event: IDBVersionChangeEvent) => {
|
|
|
+ const db = (event.target as IDBOpenDBRequest).result;
|
|
|
+ // 从注册中心获取所有Store配置
|
|
|
+ const stores = Array.from(this.storeRegistry.values());
|
|
|
+ stores.forEach((storeConfig: any) => {
|
|
|
+ if (!db.objectStoreNames.contains(storeConfig.name)) {
|
|
|
+ const objectStore = db.createObjectStore(
|
|
|
+ storeConfig.name,
|
|
|
+ { keyPath: storeConfig.keyPath }
|
|
|
+ );
|
|
|
+ storeConfig.indexes?.forEach((index: any) => {
|
|
|
+ objectStore.createIndex(
|
|
|
+ index.name,
|
|
|
+ index.keyPath,
|
|
|
+ index.options
|
|
|
+ );
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ request.onsuccess = (event: Event) => {
|
|
|
+ this.db = (event.target as IDBOpenDBRequest).result;
|
|
|
+ this.isInitialized = true;
|
|
|
+ Array.from(this.db.objectStoreNames).forEach((storeName: any) => {
|
|
|
+ this.registerStore({
|
|
|
+ name: storeName,
|
|
|
+ keyPath: "id"
|
|
|
+ });
|
|
|
+ });
|
|
|
+ resolve(this.db);
|
|
|
+ };
|
|
|
+
|
|
|
+ request.onerror = (event: Event) => {
|
|
|
+ reject((event.target as IDBOpenDBRequest).error);
|
|
|
+ };
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 动态升级数据库版本
|
|
|
+ async upgradeVersion() {
|
|
|
+ this.currentVersion += 1;
|
|
|
+ localStorage.setItem("dbVersion", this.currentVersion.toString());
|
|
|
+ this.db?.close();
|
|
|
+ return this.openDB({ dbName: this.dbName, version: this.currentVersion });
|
|
|
+ },
|
|
|
+ useStore(storeName: string) {
|
|
|
+ const verifyStore = async () => {
|
|
|
+ if (!this.storeRegistry.has(storeName)) {
|
|
|
+ throw new Error(`Store ${storeName} not registered`);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.db && !this.db.objectStoreNames.contains(storeName)) {
|
|
|
+ await this.upgradeVersion();
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const executeWithTransaction = async (mode: IDBTransactionMode, operation: any) => {
|
|
|
+ await verifyStore();
|
|
|
+ if (!this.db) await this.openDB({ dbName: this.dbName, version: this.currentVersion });
|
|
|
+
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ // this.db;
|
|
|
+ const transaction = this.db!.transaction(storeName, mode);
|
|
|
+ const objectStore = transaction.objectStore(storeName);
|
|
|
+
|
|
|
+ // 事务成功完成时的回调
|
|
|
+ // transaction.oncomplete = () => {
|
|
|
+ // resolve(); // 事务成功完成,返回结果
|
|
|
+ // };
|
|
|
+
|
|
|
+ // 事务失败时的回调
|
|
|
+ transaction.onerror = (event) => {
|
|
|
+ reject((event.target as IDBRequest).error);
|
|
|
+ };
|
|
|
+
|
|
|
+ // 执行操作
|
|
|
+ operation(objectStore).then((result: any) => {
|
|
|
+ // 操作成功,返回结果
|
|
|
+ resolve(result);
|
|
|
+ }).catch((error: any) => {
|
|
|
+ // 操作失败,拒绝 Promise
|
|
|
+ reject(error);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ return {
|
|
|
+ add: (data: any) => executeWithTransaction(
|
|
|
+ "readwrite",
|
|
|
+ (store: any) => new Promise((resolve, reject) => {
|
|
|
+ const request = store.add(data);
|
|
|
+ request.onsuccess = () => resolve(request.result as IDBValidKey);
|
|
|
+ request.onerror = () => reject(request.error);
|
|
|
+ })
|
|
|
+ ),
|
|
|
+
|
|
|
+ get: (key: IDBValidKey) => executeWithTransaction(
|
|
|
+ "readonly",
|
|
|
+ (store: any) => new Promise((resolve, reject) => {
|
|
|
+ const request = store.get(key);
|
|
|
+ request.onsuccess = () => resolve(request.result as any);
|
|
|
+ request.onerror = () => reject(request.error);
|
|
|
+ })
|
|
|
+ ),
|
|
|
+
|
|
|
+ update: (data: any) => executeWithTransaction(
|
|
|
+ "readwrite",
|
|
|
+ (store: any) => new Promise((resolve, reject) => {
|
|
|
+ const request = store.put(data);
|
|
|
+ request.onsuccess = () => resolve(request.result as IDBValidKey);
|
|
|
+ request.onerror = () => reject(request.error);
|
|
|
+ })
|
|
|
+ ),
|
|
|
+
|
|
|
+ delete: (key: IDBValidKey) => executeWithTransaction(
|
|
|
+ "readwrite",
|
|
|
+ (store: any) => new Promise((resolve, reject) => {
|
|
|
+ const request = store.delete(key);
|
|
|
+ request.onsuccess = () => resolve(undefined);
|
|
|
+ request.onerror = () => reject(request.error);
|
|
|
+ })
|
|
|
+ ),
|
|
|
+
|
|
|
+ getAll: () => executeWithTransaction(
|
|
|
+ "readonly",
|
|
|
+ (store: any) => new Promise((resolve, reject) => {
|
|
|
+ const request = store.getAll();
|
|
|
+ request.onsuccess = () => resolve(request.result as any[]);
|
|
|
+ request.onerror = () => reject(request.error);
|
|
|
+ })
|
|
|
+ ),
|
|
|
+ clearAll: () => executeWithTransaction(
|
|
|
+ "readwrite",
|
|
|
+ (store: any) => new Promise((resolve, reject) => {
|
|
|
+ const request = store.clear();
|
|
|
+ request.onsuccess = () => resolve(true);
|
|
|
+ request.onerror = () => reject(request.error);
|
|
|
+ })
|
|
|
+ )
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+});
|