import { FILE_BASE, API_HOST } from '@/config' const PLACEHOLDER_PATHS = ['/static/logo.png'] const API_PROXY_PREFIX = /^\/(dev-api|prod-api|shop-api)\//i /** 是否外链或 data URL */ export function isExternalUrl(url) { if (!url) return false return /^(https?:|data:|\/\/)/i.test(String(url).trim()) } /** 去掉 /dev-api、/shop-api 等代理前缀,得到后端真实路径 */ function stripApiProxyPrefix(path) { return String(path).replace(/^\/(dev-api|prod-api|shop-api)/, '') || '/' } function isPlaceholderPath(path) { const raw = String(path || '').trim() return PLACEHOLDER_PATHS.includes(raw) } /** * 图片根地址 * - H5 生产:自动取浏览器当前访问的 IP/域名(window.location.origin) * - H5 开发 / 小程序:用 .env 里的 VITE_APP_API_HOST */ export function getFileBase() { // #ifdef H5 if (import.meta.env.PROD && typeof window !== 'undefined') { const origin = window.location?.origin if (origin && origin !== 'null') { return origin.replace(/\/$/, '') } } // #endif return String(FILE_BASE).replace(/\/$/, '') } /** 拼接图片完整 URL */ function joinFileUrlRuntime(path) { const base = getFileBase() if (!path) return base if (/^https?:\/\//i.test(path)) return path const p = path.startsWith('/') ? path : `/${path}` return base + p } /** * 是否已是可直接使用的图片地址(避免重复拼接) */ export function isResolvedFileUrl(url) { if (!url) return false const raw = String(url).trim() if (isExternalUrl(raw)) return true if (raw.startsWith('/static/')) return true const fileBase = getFileBase() if (fileBase && (raw === fileBase || raw.startsWith(`${fileBase}/`))) return true if (API_PROXY_PREFIX.test(raw)) return true const apiHost = String(API_HOST).replace(/\/$/, '') return !!(apiHost && apiHost.startsWith('http') && (raw === apiHost || raw.startsWith(`${apiHost}/`))) } /** * 将后端返回的图片路径转为可展示的 URL(可重复调用) * - H5 生产:http://当前访问IP/profile/upload/xxx.jpg(自动) * - 开发:http://VITE_APP_API_HOST/profile/upload/xxx.jpg */ export function resolveFileUrl(path) { if (path == null || path === '') { return '' } let raw = String(path).split(',')[0].trim() if (!raw || isPlaceholderPath(raw)) { return '' } if (isExternalUrl(raw) || raw.startsWith('/static/')) { return raw } const fileBase = getFileBase() if (fileBase && (raw === fileBase || raw.startsWith(`${fileBase}/`))) { return raw } if (API_PROXY_PREFIX.test(raw)) { return raw } const apiHost = String(API_HOST).replace(/\/$/, '') if (apiHost && apiHost.startsWith('http') && (raw === apiHost || raw.startsWith(`${apiHost}/`))) { return raw } if (API_PROXY_PREFIX.test(raw)) { raw = stripApiProxyPrefix(raw) } const normalized = raw.startsWith('/') ? raw : `/${raw}` return joinFileUrlRuntime(normalized) } /** * 将逗号分隔或数组形式的图片路径转为 URL 列表 */ export function resolveFileUrlList(pathOrList) { if (pathOrList == null || pathOrList === '') return [] if (Array.isArray(pathOrList)) { return pathOrList.map((item) => resolveFileUrl(item)).filter(Boolean) } return String(pathOrList) .split(',') .map((s) => resolveFileUrl(s.trim())) .filter(Boolean) }