140 行
2.7 KiB
Plaintext
140 行
2.7 KiB
Plaintext
/**
|
|
* OmniCard AI (CRMmp) - 移动端名片离线多媒体缓存与本地持久化策略
|
|
* 严格遵循 AGENTS.md 规范与 uts 跨端强类型语法
|
|
*/
|
|
|
|
export interface MediaCacheEntry {
|
|
url: string;
|
|
localPath: string;
|
|
cachedAt: number;
|
|
expireAt: number;
|
|
sizeBytes?: number;
|
|
}
|
|
|
|
export interface CachedMediaResult {
|
|
localPath: string;
|
|
isExpired: boolean;
|
|
}
|
|
|
|
export interface MediaCacheStats {
|
|
totalEntries: number;
|
|
oldestEntryAt?: number;
|
|
}
|
|
|
|
const STORAGE_CACHE_KEY = 'omni_media_cache_index';
|
|
|
|
/**
|
|
* 获取底层全部缓存索引映射
|
|
*/
|
|
function getIndexMap(): Record<string, MediaCacheEntry> {
|
|
try {
|
|
const raw = uni.getStorageSync(STORAGE_CACHE_KEY);
|
|
if (!raw) return {};
|
|
return JSON.parse(String(raw)) || {};
|
|
} catch (e) {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 保存索引映射
|
|
*/
|
|
function saveIndexMap(map: Record<string, MediaCacheEntry>): void {
|
|
try {
|
|
uni.setStorageSync(STORAGE_CACHE_KEY, JSON.stringify(map));
|
|
} catch (e) {}
|
|
}
|
|
|
|
/**
|
|
* 获取指定多媒体 URL 的本地缓存
|
|
*/
|
|
export function getCachedMedia(url?: string): CachedMediaResult | null {
|
|
if (!url || typeof url !== 'string') return null;
|
|
|
|
const map = getIndexMap();
|
|
const entry = map[url];
|
|
if (!entry) return null;
|
|
|
|
const now = Date.now();
|
|
const isExpired = now > entry.expireAt;
|
|
|
|
return {
|
|
localPath: entry.localPath,
|
|
isExpired,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 存入多媒体缓存索引
|
|
*/
|
|
export function saveMediaToCache(
|
|
url: string,
|
|
localPath: string,
|
|
expireHours: number = 72
|
|
): void {
|
|
if (!url || !localPath) return;
|
|
|
|
const map = getIndexMap();
|
|
const now = Date.now();
|
|
const expireAt = now + expireHours * 3600 * 1000;
|
|
|
|
map[url] = {
|
|
url,
|
|
localPath,
|
|
cachedAt: now,
|
|
expireAt,
|
|
};
|
|
|
|
saveIndexMap(map);
|
|
}
|
|
|
|
/**
|
|
* 定期/按需淘汰清理过期缓存条目
|
|
*/
|
|
export function pruneExpiredMediaCache(): number {
|
|
const map = getIndexMap();
|
|
const now = Date.now();
|
|
let prunedCount = 0;
|
|
|
|
const newMap: Record<string, MediaCacheEntry> = {};
|
|
for (const [key, entry] of Object.entries(map)) {
|
|
if (now > entry.expireAt) {
|
|
prunedCount++;
|
|
} else {
|
|
newMap[key] = entry;
|
|
}
|
|
}
|
|
|
|
saveIndexMap(newMap);
|
|
return prunedCount;
|
|
}
|
|
|
|
/**
|
|
* 获取多媒体缓存状态统计
|
|
*/
|
|
export function getMediaCacheStats(): MediaCacheStats {
|
|
const map = getIndexMap();
|
|
const entries = Object.values(map);
|
|
|
|
let oldest: number | undefined = undefined;
|
|
for (const e of entries) {
|
|
if (oldest === undefined || e.cachedAt < oldest) {
|
|
oldest = e.cachedAt;
|
|
}
|
|
}
|
|
|
|
return {
|
|
totalEntries: entries.length,
|
|
oldestEntryAt: oldest,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 清空全部多媒体缓存
|
|
*/
|
|
export function clearAllMediaCache(): void {
|
|
try {
|
|
uni.removeStorageSync(STORAGE_CACHE_KEY);
|
|
} catch (e) {}
|
|
}
|