/** * 图片URL处理工具 * 统一处理相对路径和绝对路径的图片URL */ const config = require('../config/index') function getImageBaseUrl() { const apiBaseUrl = String(config?.API_BASE_URL || '').trim() if (!apiBaseUrl) return 'https://ai-c.maimanji.com' try { const parsed = new URL(apiBaseUrl) return parsed.origin } catch (_) { return apiBaseUrl.replace(/\/api\/?$/, '').replace(/\/+$/, '') } } // 获取图片基础URL(只保留 origin) const IMAGE_BASE_URL = getImageBaseUrl() /** * 转换图片URL为完整地址 * @param {string} url - 图片URL(可能是相对路径或绝对路径) * @param {string} defaultImage - 默认图片路径(可选) * @returns {string} 完整的图片URL */ function getFullImageUrl(url, defaultImage = '') { // 如果没有URL,返回默认图片 if (!url) { return defaultImage || '/images/icon-empty.png' } if (url.startsWith('wxfile://')) { return defaultImage || '/images/icon-empty.png' } if (url.startsWith('http://') || url.startsWith('https://') || url.startsWith('data:')) { try { const parsed = new URL(url) if (parsed.pathname.startsWith('/uploads/')) { parsed.pathname = `/api/uploads/${parsed.pathname.slice('/uploads/'.length)}` return parsed.toString() } if (/^\/(avatars|characters|audio|documents|assets|interest-partners|exchange|products|temp)\//.test(parsed.pathname)) { parsed.pathname = `/api/uploads${parsed.pathname}` return parsed.toString() } return url } catch (_) { return url } } // 如果是本地图片路径(/images/开头),直接返回 if (url.startsWith('/images/')) { return url } let processedUrl = url if (processedUrl.startsWith('/uploads/')) { processedUrl = `/api/uploads/${processedUrl.slice('/uploads/'.length)}` } else if (processedUrl.startsWith('uploads/')) { processedUrl = `/api/uploads/${processedUrl.slice('uploads/'.length)}` } else if (/^(\/)?(avatars|characters|audio|documents|assets|interest-partners|exchange|products|temp)\//.test(processedUrl)) { processedUrl = processedUrl.startsWith('/') ? `/api/uploads${processedUrl}` : `/api/uploads/${processedUrl}` } // 其他相对路径,拼接服务器地址 // 确保URL以/开头 const normalizedUrl = processedUrl.startsWith('/') ? processedUrl : '/' + processedUrl return IMAGE_BASE_URL + normalizedUrl } /** * 批量转换图片URL数组 * @param {Array} urls - 图片URL数组 * @returns {Array} 完整的图片URL数组 */ function getFullImageUrls(urls) { if (!Array.isArray(urls)) { return [] } return urls.map(url => getFullImageUrl(url)) } /** * 处理用户头像URL * @param {string} avatar - 头像URL * @returns {string} 完整的头像URL */ function getAvatarUrl(avatar) { return getFullImageUrl(avatar, '/images/default-avatar.svg') } /** * 处理角色头像URL * @param {string} avatar - 角色头像URL * @returns {string} 完整的头像URL */ function getCharacterAvatarUrl(avatar) { return getFullImageUrl(avatar, '/images/character-default.png') } /** * 处理活动封面URL * @param {string} cover - 封面URL * @returns {string} 完整的封面URL */ function getActivityCoverUrl(cover) { return getFullImageUrl(cover, '/images/activity-default.jpg') } module.exports = { getFullImageUrl, getFullImageUrls, getAvatarUrl, getCharacterAvatarUrl, getActivityCoverUrl, IMAGE_BASE_URL }