Files
ks-app-employment-service/utils/addressDataLoader.js
2025-11-10 15:27:34 +08:00

353 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.

/**
* 地址数据加载器 - 支持缓存和版本控制
* 优化90M+地址JSON文件的加载性能
*/
import IndexedDBHelper from '@/common/IndexedDBHelper.js';
class AddressDataLoader {
constructor() {
this.dbHelper = null;
this.dbName = 'AddressDataDB';
this.storeName = 'addressData';
this.cacheKey = 'address_data_cache';
this.versionKey = 'address_data_version';
this.cacheExpireDays = 7; // 缓存有效期7天
this.isInitialized = false;
}
/**
* 初始化数据库
*/
async init() {
if (this.isInitialized && this.dbHelper) {
return;
}
try {
this.dbHelper = new IndexedDBHelper(this.dbName, 1);
await this.dbHelper.openDB([{
name: this.storeName,
keyPath: 'key',
indexes: [
{ name: 'version', key: 'version', unique: false },
{ name: 'updateTime', key: 'updateTime', unique: false }
]
}]);
this.isInitialized = true;
console.log('✅ 地址数据加载器初始化成功');
} catch (error) {
console.error('❌ 地址数据加载器初始化失败:', error);
// 降级到 uni.storage
this.isInitialized = true;
}
}
/**
* 获取缓存版本号
*/
async getCacheVersion() {
try {
const cached = await this.dbHelper?.get(this.storeName, this.versionKey);
return cached?.version || null;
} catch (e) {
// 降级方案:从 uni.storage 读取
return uni.getStorageSync(this.versionKey) || null;
}
}
/**
* 保存版本号
*/
async saveVersion(version) {
try {
if (this.dbHelper) {
const versionData = {
key: this.versionKey,
version: version,
updateTime: Date.now()
};
// 先尝试获取,如果不存在则添加,存在则更新
try {
const existing = await this.dbHelper.get(this.storeName, this.versionKey);
if (existing) {
await this.dbHelper.update(this.storeName, versionData);
} else {
await this.dbHelper.add(this.storeName, versionData);
}
} catch (e) {
// 如果获取失败,尝试直接添加
await this.dbHelper.add(this.storeName, versionData);
}
}
} catch (e) {
// 降级方案:保存到 uni.storage
uni.setStorageSync(this.versionKey, version);
}
}
/**
* 从缓存获取数据
*/
async getCachedData() {
try {
if (this.dbHelper) {
const cached = await this.dbHelper.get(this.storeName, this.cacheKey);
if (cached && cached.data) {
// 检查缓存是否过期
const updateTime = cached.updateTime || 0;
const expireTime = this.cacheExpireDays * 24 * 60 * 60 * 1000;
if (Date.now() - updateTime < expireTime) {
console.log('✅ 从 IndexedDB 缓存加载地址数据');
return cached.data;
} else {
console.log('⚠️ 缓存已过期,需要重新加载');
}
}
}
} catch (e) {
console.warn('从 IndexedDB 读取缓存失败,尝试 uni.storage:', e);
}
// 降级方案:从 uni.storage 读取
try {
const cached = uni.getStorageSync(this.cacheKey);
if (cached && cached.data) {
const updateTime = cached.updateTime || 0;
const expireTime = this.cacheExpireDays * 24 * 60 * 60 * 1000;
if (Date.now() - updateTime < expireTime) {
console.log('✅ 从 uni.storage 缓存加载地址数据');
return cached.data;
}
}
} catch (e) {
console.warn('从 uni.storage 读取缓存失败:', e);
}
return null;
}
/**
* 保存数据到缓存
*/
async saveToCache(data) {
const cacheData = {
key: this.cacheKey,
data: data,
updateTime: Date.now()
};
try {
if (this.dbHelper) {
// 先尝试获取,如果不存在则添加,存在则更新
try {
const existing = await this.dbHelper.get(this.storeName, this.cacheKey);
if (existing) {
await this.dbHelper.update(this.storeName, cacheData);
} else {
await this.dbHelper.add(this.storeName, cacheData);
}
console.log('✅ 地址数据已保存到 IndexedDB');
} catch (e) {
// 如果获取失败,尝试直接添加
await this.dbHelper.add(this.storeName, cacheData);
console.log('✅ 地址数据已保存到 IndexedDB');
}
return;
}
} catch (e) {
console.warn('保存到 IndexedDB 失败,降级到 uni.storage:', e);
}
// 降级方案:保存到 uni.storage
try {
uni.setStorageSync(this.cacheKey, cacheData);
console.log('✅ 地址数据已保存到 uni.storage');
} catch (e) {
console.error('❌ 保存缓存失败,可能超出存储限制:', e);
// 如果存储空间不足,尝试清理旧数据
if (e.errMsg?.includes('exceed')) {
await this.clearOldCache();
// 重试保存
try {
uni.setStorageSync(this.cacheKey, cacheData);
} catch (e2) {
console.error('❌ 重试保存仍然失败:', e2);
}
}
}
}
/**
* 清理过期缓存
*/
async clearOldCache() {
try {
if (this.dbHelper) {
await this.dbHelper.delete(this.storeName, this.cacheKey);
}
uni.removeStorageSync(this.cacheKey);
console.log('✅ 已清理旧缓存');
} catch (e) {
console.warn('清理缓存失败:', e);
}
}
/**
* 从服务器获取数据版本号(如果服务器支持)
*/
async fetchRemoteVersion() {
try {
// 如果服务器提供版本接口,可以在这里实现
// const res = await uni.request({
// url: 'http://124.243.245.42/ks_cms/address_version.json',
// method: 'GET'
// });
// return res.data?.version || null;
return null;
} catch (e) {
return null;
}
}
/**
* 从服务器加载地址数据
*/
async fetchRemoteData(url, onProgress) {
return new Promise((resolve, reject) => {
console.log('📥 开始从服务器加载地址数据...');
const startTime = Date.now();
uni.request({
url: url,
method: 'GET',
timeout: 300000, // 5分钟超时
success: (res) => {
const endTime = Date.now();
const duration = ((endTime - startTime) / 1000).toFixed(2);
console.log(`✅ 地址数据加载完成,耗时 ${duration}`);
if (res.statusCode === 200) {
// 如果返回的是字符串尝试解析JSON
let data = res.data;
if (typeof data === 'string') {
try {
data = JSON.parse(data);
} catch (e) {
reject(new Error('JSON解析失败: ' + e.message));
return;
}
}
resolve(data);
} else {
reject(new Error(`请求失败,状态码: ${res.statusCode}`));
}
},
fail: (err) => {
console.error('❌ 地址数据加载失败:', err);
reject(err);
}
});
// 注意uni.request 不支持进度回调,如果需要进度提示,可以考虑:
// 1. 使用流式请求(如果服务器支持)
// 2. 显示固定加载提示
if (onProgress) {
onProgress({ loaded: 0, total: 0, percent: 0 });
}
});
}
/**
* 加载地址数据(带缓存)
* @param {string} url - 地址数据URL
* @param {boolean} forceRefresh - 是否强制刷新
* @param {Function} onProgress - 进度回调
*/
async loadAddressData(url = 'http://124.243.245.42/ks_cms/address.json', forceRefresh = false, onProgress = null) {
// 初始化数据库
await this.init();
// 如果不是强制刷新,先尝试从缓存加载
if (!forceRefresh) {
const cachedData = await this.getCachedData();
if (cachedData) {
return cachedData;
}
}
// 检查版本(如果服务器支持版本控制)
const remoteVersion = await this.fetchRemoteVersion();
if (remoteVersion) {
const cachedVersion = await this.getCacheVersion();
if (cachedVersion === remoteVersion && !forceRefresh) {
const cachedData = await this.getCachedData();
if (cachedData) {
console.log('✅ 使用缓存数据(版本匹配)');
return cachedData;
}
}
}
// 显示加载提示
uni.showLoading({
title: '正在加载地址数据...',
mask: true
});
try {
// 从服务器加载数据
const data = await this.fetchRemoteData(url, onProgress);
// 保存到缓存
await this.saveToCache(data);
// 保存版本号
if (remoteVersion) {
await this.saveVersion(remoteVersion);
}
return data;
} catch (error) {
console.error('❌ 加载地址数据失败:', error);
// 如果加载失败,尝试使用缓存数据(即使已过期)
if (!forceRefresh) {
try {
const cachedData = await this.getCachedData();
if (cachedData) {
console.log('⚠️ 使用过期缓存数据');
uni.showToast({
title: '使用缓存数据',
icon: 'none',
duration: 2000
});
return cachedData;
}
} catch (e) {
console.warn('获取缓存数据失败:', e);
}
}
throw error;
} finally {
uni.hideLoading();
}
}
/**
* 清除所有缓存
*/
async clearCache() {
await this.init();
await this.clearOldCache();
await this.saveVersion(null);
console.log('✅ 已清除所有地址数据缓存');
}
}
// 单例模式
const addressDataLoader = new AddressDataLoader();
export default addressDataLoader;