122 lines
3.5 KiB
JavaScript
122 lines
3.5 KiB
JavaScript
/**
|
||
* 图片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<string>} urls - 图片URL数组
|
||
* @returns {Array<string>} 完整的图片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
|
||
}
|