upload project

This commit is contained in:
unknown 2025-12-27 17:16:03 +08:00
commit 06961cae04
422 changed files with 110626 additions and 0 deletions

View file

@ -0,0 +1,296 @@
/**
* 图片缓存管理器
* 实现头像和聊天图片的缓存功能
*/
class ImageCacheManager {
constructor() {
this.cache = new Map();
this.cacheExpiry = new Map();
this.maxCacheSize = 100; // 最大缓存数量
this.cacheExpiryTime = 7 * 24 * 60 * 60 * 1000; // 7天缓存过期时间
this.avatarCacheExpiryTime = 30 * 24 * 60 * 60 * 1000; // 头像30天缓存过期时间
// 初始化缓存
this.initCache();
}
/**
* 初始化缓存从本地存储加载
*/
initCache() {
try {
const cachedData = wx.getStorageSync('image_cache');
if (cachedData) {
const data = JSON.parse(cachedData);
this.cache = new Map(data.cache || []);
this.cacheExpiry = new Map(data.expiry || []);
}
} catch (error) {
console.error('❌ 初始化图片缓存失败:', error);
}
}
/**
* 保存缓存到本地存储
*/
saveCache() {
try {
const data = {
cache: Array.from(this.cache.entries()),
expiry: Array.from(this.cacheExpiry.entries())
};
wx.setStorageSync('image_cache', JSON.stringify(data));
} catch (error) {
console.error('❌ 保存图片缓存失败:', error);
}
}
/**
* 清理过期缓存
*/
cleanExpiredCache() {
const now = Date.now();
const expiredKeys = [];
for (const [key, expiryTime] of this.cacheExpiry.entries()) {
if (now > expiryTime) {
expiredKeys.push(key);
}
}
expiredKeys.forEach(key => {
this.cache.delete(key);
this.cacheExpiry.delete(key);
});
if (expiredKeys.length > 0) {
this.saveCache();
}
}
/**
* 清理超出最大数量的缓存
*/
cleanExcessCache() {
if (this.cache.size <= this.maxCacheSize) return;
// 按过期时间排序,删除最旧的
const sortedEntries = Array.from(this.cacheExpiry.entries())
.sort((a, b) => a[1] - b[1]);
const excessCount = this.cache.size - this.maxCacheSize;
const keysToDelete = sortedEntries.slice(0, excessCount).map(([key]) => key);
keysToDelete.forEach(key => {
this.cache.delete(key);
this.cacheExpiry.delete(key);
});
this.saveCache();
}
/**
* 生成缓存键
*/
generateCacheKey(url, type = 'image') {
return `${type}_${url}`;
}
/**
* 检查缓存是否存在且有效
*/
isCached(url, type = 'image') {
const key = this.generateCacheKey(url, type);
const expiryTime = this.cacheExpiry.get(key);
if (!expiryTime) return false;
if (Date.now() > expiryTime) {
// 缓存已过期,删除
this.cache.delete(key);
this.cacheExpiry.delete(key);
return false;
}
return this.cache.has(key);
}
/**
* 获取缓存的图片路径
*/
getCachedPath(url, type = 'image') {
const key = this.generateCacheKey(url, type);
return this.cache.get(key);
}
/**
* 缓存图片
*/
async cacheImage(url, type = 'image') {
if (!url || url.startsWith('data:')) {
return url; // 不缓存base64等
}
// 对于本地路径前缀,直接返回
if (url.startsWith('/')) {
return url;
}
// 确保URL是完整的添加https前缀如果缺少
let fullUrl = url;
if (!fullUrl.startsWith('http://') && !fullUrl.startsWith('https://')) {
fullUrl = 'https://' + url;
}
const key = this.generateCacheKey(fullUrl, type);
// 检查是否已缓存
if (this.isCached(fullUrl, type)) {
return this.getCachedPath(fullUrl, type);
}
try {
// 下载图片
const downloadResult = await new Promise((resolve, reject) => {
wx.downloadFile({
url: fullUrl,
timeout: 15000, // 增加超时时间
success: resolve,
fail: reject
});
});
if (downloadResult.statusCode === 200) {
const localPath = downloadResult.tempFilePath;
// 设置缓存过期时间
const expiryTime = type === 'avatar'
? Date.now() + this.avatarCacheExpiryTime
: Date.now() + this.cacheExpiryTime;
// 保存到缓存
this.cache.set(key, localPath);
this.cacheExpiry.set(key, expiryTime);
// 清理过期和超量缓存
this.cleanExpiredCache();
this.cleanExcessCache();
return localPath;
} else {
console.warn('⚠️ 图片下载失败,状态码:', downloadResult.statusCode, 'URL:', fullUrl);
// 如果下载失败返回完整的URL
return fullUrl;
}
} catch (error) {
console.error('❌ 缓存图片失败:', fullUrl, error);
// 在缓存失败时返回完整的URL
return fullUrl;
}
}
/**
* 缓存头像
*/
async cacheAvatar(url) {
return this.cacheImage(url, 'avatar');
}
/**
* 更新头像缓存当头像URL变化时
*/
async updateAvatarCache(oldUrl, newUrl) {
if (oldUrl && oldUrl !== newUrl) {
const oldKey = this.generateCacheKey(oldUrl, 'avatar');
this.cache.delete(oldKey);
this.cacheExpiry.delete(oldKey);
}
if (newUrl) {
return await this.cacheAvatar(newUrl);
}
return newUrl;
}
/**
* 预加载图片用于聊天中的图片
*/
async preloadImage(url) {
return this.cacheImage(url, 'chat_image');
}
/**
* 获取缓存统计信息
*/
getCacheStats() {
const now = Date.now();
let avatarCount = 0;
let imageCount = 0;
let expiredCount = 0;
for (const [key, expiryTime] of this.cacheExpiry.entries()) {
if (key.startsWith('avatar_')) {
avatarCount++;
} else if (key.startsWith('image_') || key.startsWith('chat_image_')) {
imageCount++;
}
if (now > expiryTime) {
expiredCount++;
}
}
return {
total: this.cache.size,
avatar: avatarCount,
image: imageCount,
expired: expiredCount,
maxSize: this.maxCacheSize
};
}
/**
* 清空所有缓存
*/
clearAllCache() {
this.cache.clear();
this.cacheExpiry.clear();
this.saveCache();
}
/**
* 清理指定类型的缓存
*/
clearCacheByType(type) {
const keysToDelete = [];
for (const key of this.cache.keys()) {
if (key.startsWith(`${type}_`)) {
keysToDelete.push(key);
}
}
keysToDelete.forEach(key => {
this.cache.delete(key);
this.cacheExpiry.delete(key);
});
this.saveCache();
}
}
// 创建单例实例
const imageCacheManager = new ImageCacheManager();
module.exports = imageCacheManager;