mediaUrl.ts 2.35 KB
function adminApiBase(): string {
  const env = import.meta.env.VITE_API_BASE;
  const envBase = typeof env === "string" ? env.trim().replace(/\/+$/, "") : "";
  return envBase;
}

/**
 * 管理后台下载/水印打包用:经后端 admin/v1/uploads/raw 拉取二进制,避免前端页与静态资源跨域时 fetch 被 CORS 拦截。
 * 展示用仍用 {@link resolveAdminMediaUrl}(img 标签不受同源策略限制)。
 */
export function resolveAdminUploadBlobFetchUrl(displayUrl: string): string {
  const raw = typeof displayUrl === "string" ? displayUrl.trim() : "";
  if (!raw) return "";
  let path = "";
  try {
    if (raw.startsWith("http://") || raw.startsWith("https://")) {
      path = new URL(raw).pathname;
    } else if (raw.startsWith("/uploads/")) {
      path = raw.split("?")[0] ?? raw;
    }
  } catch {
    return raw;
  }
  if (!path.startsWith("/uploads/")) {
    return raw;
  }
  const base = adminApiBase();
  if (!base) {
    return raw;
  }
  return `${base}/admin/v1/uploads/raw?path=${encodeURIComponent(path)}`;
}

/**
 * 管理后台展示用:将 /uploads/... 转为浏览器可请求的绝对地址。
 * 未配置 VITE_API_BASE 时使用当前页面 origin(开发环境由 Vite 代理 /uploads)。
 */
export function resolveAdminMediaUrl(path: string | null | undefined): string {
  const raw = typeof path === "string" ? path.trim() : "";
  if (!raw) return "";
  if (raw.startsWith("blob:") || raw.startsWith("data:")) {
    return "";
  }
  if (raw.startsWith("http://") || raw.startsWith("https://")) {
    return raw;
  }
  const uploads = raw.startsWith("/uploads/")
    ? raw
    : raw.startsWith("uploads/")
      ? `/${raw}`
      : "";
  if (uploads) {
    const envBase = adminApiBase();
    const base =
      envBase ||
      (typeof window !== "undefined" && window.location?.origin
        ? window.location.origin.replace(/\/+$/, "")
        : "");
    return base ? `${base}${uploads}` : uploads;
  }
  if (raw.startsWith("/") && typeof window !== "undefined" && window.location?.origin) {
    return `${window.location.origin.replace(/\/+$/, "")}${raw}`;
  }
  return raw;
}

/** 持久化字段:去掉浏览器临时地址,避免写入数据库 */
export function sanitizeAvatarForSave(path: string): string {
  const t = path.trim();
  if (!t || t.startsWith("blob:") || t.startsWith("data:")) {
    return "";
  }
  return t;
}