Files
ks-app-employment-service/common/IndexedDBHelper.js
2025-04-16 14:24:06 +08:00

324 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

class IndexedDBHelper {
constructor(dbName, version = 1) {
this.dbName = dbName;
this.version = version;
this.db = null;
}
/**
* 初始化数据库(打开/创建)
* @param {Array} stores [{ name: "storeName", keyPath: "id", indexes: [{ name: "indexName", key: "keyPath", unique: false }] }]
* @returns {Promise}
*/
openDB(stores = []) {
return new Promise((resolve, reject) => {
const request = indexedDB.open(this.dbName, this.version);
request.onupgradeneeded = (event) => {
this.db = event.target.result;
stores.forEach(store => {
if (!this.db.objectStoreNames.contains(store.name)) {
const objectStore = this.db.createObjectStore(store.name, {
keyPath: store.keyPath,
autoIncrement: store.autoIncrement || false
});
if (store.indexes) {
store.indexes.forEach(index => {
objectStore.createIndex(index.name, index.key, {
unique: index.unique
});
});
}
}
});
};
request.onsuccess = (event) => {
this.db = event.target.result;
console.log("✅ IndexedDB 连接成功");
resolve(this.db);
};
request.onerror = (event) => {
reject(`IndexedDB Error: ${event.target.error}`);
};
});
}
// 通用查询方法,按指定字段查询
async queryByField(storeName, fieldName, value) {
return new Promise(async (resolve, reject) => {
try {
if (!this.db) {
await this.openDB();
}
const transaction = this.db.transaction(storeName, 'readonly');
const store = transaction.objectStore(storeName);
if (!store.indexNames.contains(fieldName)) {
return reject(`索引 ${fieldName} 不存在`);
}
const index = store.index(fieldName);
const request = index.getAll(value);
request.onsuccess = (event) => {
resolve(event.target.result);
};
request.onerror = (event) => {
reject('查询失败: ' + event.target.error);
};
} catch (error) {
reject('查询错误: ' + error);
}
});
}
/**
* 添加数据(支持单条或批量)
* @param {string} storeName - 存储空间名称
* @param {Object|Array} data - 要添加的数据(单条对象或数组)
* @returns {Promise<number|Array<number>>} - 返回添加数据的ID单条返回数字批量返回数组
*/
add(storeName, data) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], "readwrite");
const store = transaction.objectStore(storeName);
// 统一处理为数组格式
const items = Array.isArray(data) ? data : [data];
const results = [];
// 监听每个添加操作的成功事件
items.forEach((item, index) => {
const request = store.add(item);
request.onsuccess = (event) => {
results[index] = event.target.result; // 保存生成的ID
};
request.onerror = (event) => {
transaction.abort(); // 遇到错误时中止事务
reject(`${index + 1} 条数据添加失败: ${event.target.error}`);
};
});
// 监听事务完成事件
transaction.oncomplete = () => {
// 单条数据返回单个ID批量返回数组
resolve(items.length === 1 ? results[0] : results);
};
// 统一错误处理
transaction.onerror = (event) => {
reject(`添加失败: ${event.target.error}`);
};
});
}
/**
* 读取数据(根据主键)
* @param {string} storeName
* @param {any} key
* @returns {Promise}
*/
get(storeName, key) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], "readonly");
const store = transaction.objectStore(storeName);
const request = store.get(key);
request.onsuccess = () => resolve(request.result);
request.onerror = (event) => reject(`Get Error: ${event.target.error}`);
});
}
/**
* 读取所有数据兼容X5内核方案
* @param {string} storeName
* @returns {Promise}
*/
getAll(storeName) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], "readonly");
const store = transaction.objectStore(storeName);
// 兼容性检测优先尝试原生getAll方法
if (typeof store.getAll === 'function') {
const request = store.getAll();
request.onsuccess = () => resolve(request.result);
request.onerror = (e) => reject(`GetAll Error: ${e.target.error}`);
}
// 降级方案:使用游标手动遍历
else {
const results = [];
const request = store.openCursor();
request.onsuccess = (e) => {
const cursor = e.target.result;
if (cursor) {
results.push(cursor.value);
cursor.continue();
} else {
resolve(results);
}
};
request.onerror = (e) => reject(`Cursor Error: ${e.target.error}`);
}
});
}
/**
* 获取表的总记录数
* @param {string} storeName - 表名Object Store 名称)
* @returns {Promise<number>} - 记录总数
*/
async getRecordCount(storeName) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], "readonly");
const store = transaction.objectStore(storeName);
const request = store.count();
request.onsuccess = () => resolve(request.result);
request.onerror = (event) => reject(`❌ Count Error: ${event.target.error}`);
});
}
/**
* 更新数据(支持指定 key 或自动使用 keyPath
* @param {string} storeName 存储对象名
* @param {Object} data 待更新数据
* @param {IDBValidKey|IDBKeyRange} [key] 可选参数,指定更新的 key
* @returns {Promise<string>} 更新结果
*/
update(storeName, data, key) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], "readwrite");
const store = transaction.objectStore(storeName);
const keyPath = store.keyPath;
// 有传入 key直接使用 key 更新
if (key !== undefined) {
const request = store.put(data, key);
request.onsuccess = () => resolve("数据更新成功(指定 key");
request.onerror = (event) => reject(`更新失败: ${event.target.error}`);
return;
}
// 无传入 key依赖 keyPath 更新
if (!keyPath) {
reject("当前 store 未设置 keyPath必须传入 key 参数");
return;
}
// 检查数据是否包含 keyPath 属性
let missingKeys = [];
if (Array.isArray(keyPath)) {
missingKeys = keyPath.filter(k => !data.hasOwnProperty(k));
} else if (typeof keyPath === 'string') {
if (!data.hasOwnProperty(keyPath)) {
missingKeys.push(keyPath);
}
}
if (missingKeys.length > 0) {
reject(`数据缺少必要的 keyPath 属性: ${missingKeys.join(', ')}`);
return;
}
// 默认使用 keyPath 更新
const request = store.put(data);
request.onsuccess = () => resolve("数据更新成功(默认 keyPath");
request.onerror = (event) => reject(`更新失败: ${event.target.error}`);
});
}
/**
* 删除数据(根据主键)
* @param {string} storeName
* @param {any} key
* @returns {Promise}
*/
delete(storeName, key) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], "readwrite");
const store = transaction.objectStore(storeName);
const request = store.delete(key);
request.onsuccess = () => resolve("Data deleted successfully");
request.onerror = (event) => reject(`Delete Error: ${event.target.error}`);
});
}
/**
* 通过索引查询数据
* @param {string} storeName
* @param {string} indexName
* @param {any} value
* @returns {Promise}
*/
getByIndex(storeName, indexName, value) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], "readonly");
const store = transaction.objectStore(storeName);
const index = store.index(indexName);
const request = index.get(value);
request.onsuccess = () => resolve(request.result);
request.onerror = (event) => reject(`Get By Index Error: ${event.target.error}`);
});
}
/**
* 清空表
* @param {string} storeName
* @returns {Promise}
*/
clearStore(storeName) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], "readwrite");
const store = transaction.objectStore(storeName);
const request = store.clear();
request.onsuccess = () => resolve("Store cleared successfully");
request.onerror = (event) => reject(`Clear Store Error: ${event.target.error}`);
});
}
/**
* 删除数据库
* @returns {Promise}
*/
deleteDB(dbNamed = null) {
return new Promise((resolve, reject) => {
const request = indexedDB.deleteDatabase(dbNamed || this.dbName);
request.onsuccess = () => resolve("Database deleted successfully");
request.onerror = (event) => reject(`Delete DB Error: ${event.target.error}`);
});
}
async deleteOldestRecord(storeName) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], "readwrite");
const store = transaction.objectStore(storeName);
const request = store.openCursor(); // 🔹 获取最早的记录(按主键 ID 排序)
request.onsuccess = function(event) {
const cursor = event.target.result;
if (cursor) {
console.log(`🗑️ 删除最早的记录 ID: ${cursor.key}`);
store.delete(cursor.key); // 🔥 删除最小 ID最早记录
resolve();
} else {
resolve(); // 没有记录时跳过
}
};
request.onerror = (event) => reject(`❌ Cursor Error: ${event.target.error}`);
});
}
}
export default IndexedDBHelper