feat(round-16): AI意图情绪分析/展会名片双向互换/雷达爬虫清洗/离线多媒体缓存 (103套件1101测试全绿)
这个提交包含在:
139
mpuniapp/common/media-cache.uts
普通文件
139
mpuniapp/common/media-cache.uts
普通文件
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* 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) {}
|
||||
}
|
||||
在新工单中引用
屏蔽一个用户