50 lines
2.0 KiB
TypeScript
50 lines
2.0 KiB
TypeScript
/**
|
||
* 资源 URL 解析
|
||
*
|
||
* dashboard 后台填写素材地址时支持相对路径(如 /uploads/2026/07/xxx.mp4),
|
||
* www 端渲染时自动拼接资源服务地址(NUXT_PUBLIC_ASSET_BASE_URL,
|
||
* 未配置时默认取 apiBaseUrl 去掉 /api 后缀的 origin)。
|
||
* 完整 URL(http(s)://、//、data: 等)保持原样。
|
||
* 仅解析 /uploads/ 开头的素材路径;其他相对路径(如 /products/luxsin-x8)
|
||
* 是站内路由链接(CTA 按钮等),保持原样由 NuxtLink 消费。
|
||
*/
|
||
|
||
// 匹配 *_url / *_path / url 字段(如 cover_url、file_path、gallery 的 url)
|
||
const ASSET_KEY_RE = /^url$|_(url|path)$/;
|
||
|
||
export function resolveAssetUrl(url?: string | null): string {
|
||
if (!url) return '';
|
||
// 绝对地址(协议开头 / 协议相对 // / data: / blob:)保持原样
|
||
if (/^([a-z][a-z0-9+.-]*:|\/\/)/i.test(url)) return url;
|
||
// 仅解析 /uploads/ 下的素材相对路径;其他 / 开头路径是站内路由链接,不能拼后端基地址
|
||
if (!url.startsWith('/uploads/')) return url;
|
||
|
||
const config = useRuntimeConfig();
|
||
const assetBase =
|
||
(config.public.assetBaseUrl as string) ||
|
||
(config.public.apiBaseUrl as string).replace(/\/api\/?$/, '');
|
||
return assetBase.replace(/\/+$/, '') + url;
|
||
}
|
||
|
||
/**
|
||
* 深度遍历响应数据,将所有 *_url / *_path 字段的相对路径解析为完整地址。
|
||
* 在 useRequest 统一调用,页面/组件无需逐个处理。
|
||
*/
|
||
export function resolveAssetUrls<T>(data: T): T {
|
||
if (!data || typeof data !== 'object') return data;
|
||
if (Array.isArray(data)) {
|
||
return data.map(item => resolveAssetUrls(item)) as unknown as T;
|
||
}
|
||
const result: Record<string, unknown> = {};
|
||
for (const [key, value] of Object.entries(data as Record<string, unknown>)) {
|
||
if (typeof value === 'string' && ASSET_KEY_RE.test(key)) {
|
||
result[key] = resolveAssetUrl(value);
|
||
} else if (value && typeof value === 'object') {
|
||
result[key] = resolveAssetUrls(value);
|
||
} else {
|
||
result[key] = value;
|
||
}
|
||
}
|
||
return result as T;
|
||
}
|