/** * PFP数据加载模块 * 直接从第三方API获取数据,使用LocalStorage缓存 */ class PFPLoader { constructor() { this.cache = new BrowserCache(); // 第三方API地址 this.externalApiUrl = 'https://h5.shuziwenbo.cn/json/shpfp/pfp.json'; this.allData = null; } /** * 从第三方API或缓存加载所有PFP数据 * @returns {Promise} PFP数据对象 */ async loadAllPFP() { // 1. 尝试从LocalStorage缓存读取 const cachedData = this.cache.getCache('pfp_data'); if (cachedData) { console.log('✓ 使用LocalStorage缓存数据'); this.allData = cachedData; return cachedData; } // 2. 缓存不存在或已过期,直接调用第三方API try { console.log('→ 从第三方API获取数据...'); console.log(' API地址:', this.externalApiUrl); const response = await fetch(this.externalApiUrl); if (!response.ok) { throw new Error(`HTTP错误! 状态: ${response.status}`); } const result = await response.json(); // 3. 修复图片URL协议(HTTP转HTTPS) if (result && result.data) { const fixedData = this.fixImageProtocol(result.data); // 4. 保存到LocalStorage(24小时过期) this.cache.setCache('pfp_data', fixedData); this.allData = fixedData; console.log(`✓ 数据已缓存到LocalStorage, 共 ${Object.keys(fixedData).length} 条`); console.log('✓ 图片URL已转换为HTTPS协议'); return fixedData; } else { throw new Error('API返回数据格式错误'); } } catch (error) { console.error('✗ 获取PFP数据失败:', error); throw error; } } /** * 获取分页数据(前端分页) * @param {Object} allData - 所有数据 * @param {number} page - 页码(从1开始) * @param {number} perPage - 每页数量 * @returns {Object} 分页结果 */ getPaginatedData(allData, page = 1, perPage = 20) { // 将对象转为数组并按num排序 const dataArray = Object.values(allData).map(pfp => { // 确保每条数据的图片URL都使用HTTPS const fixedPfp = { ...pfp }; if (fixedPfp.src && fixedPfp.src.startsWith('http://')) { fixedPfp.src = fixedPfp.src.replace('http://', 'https://'); } if (fixedPfp.cover && fixedPfp.cover.startsWith('http://')) { fixedPfp.cover = fixedPfp.cover.replace('http://', 'https://'); } return fixedPfp; }).sort((a, b) => a.num - b.num); const start = (page - 1) * perPage; const end = start + perPage; return { data: dataArray.slice(start, end), total: dataArray.length, page: page, perPage: perPage, totalPages: Math.ceil(dataArray.length / perPage) }; } /** * 根据编号数组筛选数据 * @param {Object} allData - 所有数据 * @param {Array} nums - 编号数组 * @returns {Array} 筛选后的数据数组 */ filterByNums(allData, nums) { const filtered = []; nums.forEach(num => { if (allData[num]) { // 确保图片URL使用HTTPS协议 const pfp = { ...allData[num] }; if (pfp.src && pfp.src.startsWith('http://')) { pfp.src = pfp.src.replace('http://', 'https://'); } if (pfp.cover && pfp.cover.startsWith('http://')) { pfp.cover = pfp.cover.replace('http://', 'https://'); } filtered.push(pfp); } }); // 按num排序 return filtered.sort((a, b) => a.num - b.num); } /** * 修复图片URL协议(HTTP转HTTPS) * @param {Object} data - PFP数据对象 * @returns {Object} 修复后的数据 */ fixImageProtocol(data) { const fixed = {}; for (const key in data) { const pfp = { ...data[key] }; if (pfp.src && pfp.src.startsWith('http://')) { pfp.src = pfp.src.replace('http://', 'https://'); } if (pfp.cover && pfp.cover.startsWith('http://')) { pfp.cover = pfp.cover.replace('http://', 'https://'); } fixed[key] = pfp; } return fixed; } /** * 格式化特征字符串为数组 * @param {string} featuresStr - 特征字符串 * @returns {Array} 格式化后的特征数组 */ formatFeatures(featuresStr) { if (!featuresStr) return []; return featuresStr.split(',').map(item => { const [key, value] = item.split(':'); if (!key || !value) return null; const [category, name] = key.split('_'); if (!category || !name) return null; return { category: category, name: name, value: value, display: `${category}:${name} (${value})` }; }).filter(item => item !== null); } /** * 获取数据加载状态 * @returns {boolean} 是否已加载数据 */ isDataLoaded() { return this.allData !== null; } /** * 强制刷新数据(清除缓存后重新加载) * @returns {Promise} PFP数据对象 */ async forceRefresh() { this.cache.removeCache('pfp_data'); return await this.loadAllPFP(); } }