request.ts 2.18 KB
import axios, { type AxiosInstance, type InternalAxiosRequestConfig } from "axios";
import { ElMessage } from "element-plus";
import { useUserStore } from "@/stores/user";

const TOKEN_KEY = "daocheng_admin_token";

export function getToken(): string {
  return localStorage.getItem(TOKEN_KEY) || "";
}

export function setToken(t: string): void {
  localStorage.setItem(TOKEN_KEY, t);
}

export function clearToken(): void {
  localStorage.removeItem(TOKEN_KEY);
}

function baseURL(): string {
  const v = import.meta.env.VITE_API_BASE;
  if (typeof v === "string" && v.trim()) {
    return v.trim().replace(/\/+$/, "");
  }
  return "";
}

const service: AxiosInstance = axios.create({
  baseURL: baseURL(),
  timeout: 30000,
});

service.interceptors.request.use((config: InternalAxiosRequestConfig) => {
  const token = getToken();
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  // multipart 必须由浏览器自动带 boundary;若残留 application/json 会导致 PHP 收不到 file
  if (config.data instanceof FormData) {
    const h = config.headers;
    if (h && typeof (h as { delete?: (key: string) => void }).delete === "function") {
      (h as { delete: (key: string) => void }).delete("Content-Type");
    } else if (h && typeof h === "object") {
      delete (h as Record<string, unknown>)["Content-Type"];
      delete (h as Record<string, unknown>)["content-type"];
    }
  }
  return config;
});

service.interceptors.response.use(
  (res) => {
    const data = res.data;
    if (data && typeof data.code === "number") {
      if (data.code === 0) {
        return data;
      }
      if (data.code === 401) {
        clearToken();
        useUserStore().clearProfile();
        if (!window.location.pathname.includes("/login")) {
          window.location.href = "/login";
        }
      }
      ElMessage.error(data.msg || "请求失败");
      return Promise.reject(new Error(data.msg || "请求失败"));
    }
    return data;
  },
  (err) => {
    const msg = err.response?.data?.msg || err.message || "网络错误";
    ElMessage.error(msg);
    return Promise.reject(err);
  }
);

export default service;

export type ApiEnvelope<T> = { code: number; msg: string; data: T };