import { getConfigApp } from '@/utils/config' import { baseURL as fallbackBaseURL } from '@/themeConfig' import type {AxiosRequestConfig, AxiosResponse} from 'axios' import axios from 'axios' import {getToken, removeToken} from "@/utils"; import { findStoredAuthToken } from '@/utils/authToken'; import router from "@/router"; import {get} from 'lodash' import {message} from "ant-design-vue"; interface Meta { errorMessage?: 'message' | 'notification' | 'toast' | 'none' } interface MyAxiosRequestConfig extends AxiosRequestConfig { meta?: Meta } const headers = { 'Content-Type': 'application/json', Accept: 'application/json', } const _axios = axios.create({ baseURL: fallbackBaseURL, headers, }) let sessionVerifyTimer: ReturnType | null = null let sessionVerifyInFlight = false function requestPath(config: { url?: string; baseURL?: string } | undefined): string { const raw = String(config?.url ?? '') if (raw.startsWith('http')) { try { return new URL(raw).pathname } catch { return raw } } return raw } async function logoutToLogin() { removeToken() if (router.currentRoute.value.name !== 'login') { await router.push({ name: 'login' }) } } function scheduleSessionVerify() { if (sessionVerifyTimer) { return } sessionVerifyTimer = setTimeout(async () => { sessionVerifyTimer = null if (sessionVerifyInFlight) { return } const token = findStoredAuthToken() if (!token) { return } sessionVerifyInFlight = true try { await _axios.get('/customer/me', { headers: { Authorization: `Bearer ${token}` }, meta: { errorMessage: 'none' }, }) } catch { await logoutToLogin() } finally { sessionVerifyInFlight = false } }, 2000) } _axios.interceptors.request.use( (config) => { const runtimeBaseURL = getConfigApp('node_server') if (runtimeBaseURL) { config.baseURL = runtimeBaseURL } if (config.headers) { const token = getToken() if (token) { //@ts-ignore config.headers['Authorization'] = 'Bearer ' + token } } return config }, (error) => { //console.log('this is error on interceptors.request', error) Promise.reject(error) }, ) _axios.interceptors.response.use( (response) => { //console.log('this is response') // Any status code that lie within the range of 2xx cause this function to trigger // Do something with response data //console.log('this is fulfilled on interceptors.response', response.data) return response.data }, async function (error) { const response = error.response const config = error.config as MyAxiosRequestConfig | undefined if (response?.status === 401) { const hadAuth = Boolean(config?.headers?.Authorization) if (hadAuth) { const path = requestPath(config) if (path.includes('/customer/me')) { await logoutToLogin() } else { scheduleSessionVerify() } } return Promise.reject(error) } if (!shouldShowApiError(config)) { return Promise.reject(error) } const apiMessage = extractApiErrorMessage(response?.data) if (response?.status === 403) { showApiError(apiMessage || 'شما دسترسی لازم برای انجام این عملیات را ندارید', config) return Promise.reject(error) } if (response?.status === 422) { if (apiMessage) { showApiError(apiMessage, config) } return Promise.reject(error) } if (response) { showApiError(apiMessage || DEFAULT_LOAD_ERROR, config) return Promise.reject(error) } showApiError(DEFAULT_LOAD_ERROR, config) return Promise.reject(error) }) const DEFAULT_LOAD_ERROR = 'خطا در بارگذاری اطلاعات' function extractApiErrorMessage(data: unknown): string { if (!data || typeof data !== 'object') { return '' } const record = data as Record const rawMessage = record.message if (typeof rawMessage === 'string' && rawMessage.trim()) { return rawMessage.trim() } if (typeof rawMessage === 'number') { return String(rawMessage) } const rawError = record.error if (typeof rawError === 'string' && rawError.trim()) { return rawError.trim() } const errors = record.errors if (errors && typeof errors === 'object') { for (const value of Object.values(errors as Record)) { if (Array.isArray(value) && typeof value[0] === 'string' && value[0].trim()) { return value[0].trim() } if (typeof value === 'string' && value.trim()) { return value.trim() } } } return '' } function shouldShowApiError(config: MyAxiosRequestConfig | undefined): boolean { return get(config, 'meta.errorMessage', 'message') !== 'none' } function showApiError(msg: string, config: MyAxiosRequestConfig | undefined) { if (!shouldShowApiError(config)) { return } message.error(msg) } const myAxios = { //AxiosResponse post( url: string, data?: D, config?: MyAxiosRequestConfig, ): Promise { return _axios.post(url, data, config) }, request, D = any>(config: MyAxiosRequestConfig): Promise { return _axios.request(config) }, //AxiosResponse get(url: string, config?: MyAxiosRequestConfig): Promise { return _axios.get(url, config) }, //AxiosResponse delete(url: string, config?: MyAxiosRequestConfig): Promise { return _axios.delete(url, config) }, //AxiosResponse head(url: string, config?: MyAxiosRequestConfig): Promise { return _axios.head(url, config) }, //AxiosResponse options(url: string, config?: MyAxiosRequestConfig): Promise { return _axios.options(url, config) }, //AxiosResponse put( url: string, data?: D, config?: MyAxiosRequestConfig, ): Promise { return _axios.put(url, data, config) }, //AxiosResponse patch( url: string, data?: D, config?: MyAxiosRequestConfig, ): Promise { return _axios.patch(url, data, config) }, //AxiosResponse postForm( url: string, data?: D, config?: MyAxiosRequestConfig, ): Promise { return _axios.postForm(url, data, config) }, //AxiosResponse putForm( url: string, data?: D, config?: MyAxiosRequestConfig, ): Promise { return _axios.putForm(url, data, config) }, //AxiosResponse patchForm( url: string, data?: D, config?: MyAxiosRequestConfig, ): Promise { return _axios.patchForm(url, data, config) }, } export default myAxios export {_axios}