indexedDB.ts 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. import { defineStore } from 'pinia'
  2. interface IndexedDBStoreConfig {
  3. name: string;
  4. keyPath: string;
  5. indexes?: Array<{
  6. name: string
  7. keyPath: string | string[]
  8. options?: IDBIndexParameters
  9. }>;
  10. }
  11. interface IndexedDBConfig {
  12. dbName: string;
  13. version?: number;
  14. }
  15. export const useIndexedDBStore = defineStore('indexedDB', {
  16. state: () => ({
  17. storeRegistry: new Map<string, IndexedDBStoreConfig>(),
  18. dbName: <string>'',
  19. db: <IDBDatabase | null>null,
  20. currentVersion: <number>0,
  21. isInitialized: <boolean>false
  22. }),
  23. actions: {
  24. registerStore(storeConfig: IndexedDBStoreConfig) {
  25. if (!this.storeRegistry.has(storeConfig.name)) {
  26. this.storeRegistry.set(storeConfig.name, storeConfig)
  27. }
  28. },
  29. deleteDB() {
  30. return new Promise<boolean>((resolve, reject) => {
  31. const request = indexedDB.deleteDatabase(this.dbName)
  32. request.onsuccess = () => {
  33. resolve(true)
  34. window.location.reload()
  35. }
  36. request.onerror = () => {
  37. reject(request.error)
  38. }
  39. })
  40. },
  41. openDB(config: IndexedDBConfig) {
  42. if (config) {
  43. this.dbName = config.dbName
  44. this.currentVersion = config.version || 1
  45. }
  46. return new Promise((resolve, reject) => {
  47. const request = indexedDB.open(this.dbName, this.currentVersion)
  48. request.onupgradeneeded = (event: IDBVersionChangeEvent) => {
  49. const db = (event.target as IDBOpenDBRequest).result
  50. // 从注册中心获取所有Store配置
  51. const stores = Array.from(this.storeRegistry.values())
  52. stores.forEach((storeConfig: any) => {
  53. if (!db.objectStoreNames.contains(storeConfig.name)) {
  54. const objectStore = db.createObjectStore(
  55. storeConfig.name,
  56. { keyPath: storeConfig.keyPath }
  57. )
  58. storeConfig.indexes?.forEach((index: any) => {
  59. objectStore.createIndex(
  60. index.name,
  61. index.keyPath,
  62. index.options
  63. )
  64. })
  65. }
  66. })
  67. }
  68. request.onsuccess = (event: Event) => {
  69. this.db = (event.target as IDBOpenDBRequest).result
  70. this.isInitialized = true
  71. Array.from(this.db.objectStoreNames).forEach((storeName: any) => {
  72. this.registerStore({
  73. name: storeName,
  74. keyPath: 'id'
  75. })
  76. })
  77. resolve(this.db)
  78. }
  79. request.onerror = (event: Event) => {
  80. reject((event.target as IDBOpenDBRequest).error)
  81. }
  82. })
  83. },
  84. // 动态升级数据库版本
  85. async upgradeVersion() {
  86. this.currentVersion += 1
  87. localStorage.setItem('dbVersion', this.currentVersion.toString())
  88. this.db?.close()
  89. return this.openDB({ dbName: this.dbName, version: this.currentVersion })
  90. },
  91. useStore(storeName: string) {
  92. const verifyStore = async () => {
  93. if (!this.storeRegistry.has(storeName)) {
  94. throw new Error(`Store ${storeName} not registered`)
  95. }
  96. if (this.db && !this.db.objectStoreNames.contains(storeName)) {
  97. await this.upgradeVersion()
  98. }
  99. }
  100. const executeWithTransaction = async (mode: IDBTransactionMode, operation: any) => {
  101. await verifyStore()
  102. if (!this.db) await this.openDB({ dbName: this.dbName, version: this.currentVersion })
  103. return new Promise((resolve, reject) => {
  104. // this.db;
  105. const transaction = this.db!.transaction(storeName, mode)
  106. const objectStore = transaction.objectStore(storeName)
  107. // 事务成功完成时的回调
  108. // transaction.oncomplete = () => {
  109. // resolve(); // 事务成功完成,返回结果
  110. // };
  111. // 事务失败时的回调
  112. transaction.onerror = (event) => {
  113. reject((event.target as IDBRequest).error)
  114. }
  115. // 执行操作
  116. operation(objectStore).then((result: any) => {
  117. // 操作成功,返回结果
  118. resolve(result)
  119. }).catch((error: any) => {
  120. // 操作失败,拒绝 Promise
  121. reject(error)
  122. })
  123. })
  124. }
  125. return {
  126. add: (data: any) => executeWithTransaction(
  127. 'readwrite',
  128. (store: any) => new Promise((resolve, reject) => {
  129. const request = store.add(data)
  130. request.onsuccess = () => resolve(request.result as IDBValidKey)
  131. request.onerror = () => reject(request.error)
  132. })
  133. ),
  134. get: (key: IDBValidKey) => executeWithTransaction(
  135. 'readonly',
  136. (store: any) => new Promise((resolve, reject) => {
  137. const request = store.get(key)
  138. request.onsuccess = () => resolve(request.result as any)
  139. request.onerror = () => reject(request.error)
  140. })
  141. ),
  142. update: (data: any) => executeWithTransaction(
  143. 'readwrite',
  144. (store: any) => new Promise((resolve, reject) => {
  145. const request = store.put(data)
  146. request.onsuccess = () => resolve(request.result as IDBValidKey)
  147. request.onerror = () => reject(request.error)
  148. })
  149. ),
  150. delete: (key: IDBValidKey) => executeWithTransaction(
  151. 'readwrite',
  152. (store: any) => new Promise((resolve, reject) => {
  153. const request = store.delete(key)
  154. request.onsuccess = () => resolve(undefined)
  155. request.onerror = () => reject(request.error)
  156. })
  157. ),
  158. getAll: () => executeWithTransaction(
  159. 'readonly',
  160. (store: any) => new Promise((resolve, reject) => {
  161. const request = store.getAll()
  162. request.onsuccess = () => resolve(request.result as any[])
  163. request.onerror = () => reject(request.error)
  164. })
  165. ),
  166. clearAll: () => executeWithTransaction(
  167. 'readwrite',
  168. (store: any) => new Promise((resolve, reject) => {
  169. const request = store.clear()
  170. request.onsuccess = () => resolve(true)
  171. request.onerror = () => reject(request.error)
  172. })
  173. )
  174. }
  175. }
  176. }
  177. })