195 lines
5.2 KiB
TypeScript
195 lines
5.2 KiB
TypeScript
import { authApi } from './auth';
|
||
import { get, post, put, del } from './request';
|
||
import type { ApiResponse, PaginatedResponse } from '@/types/common';
|
||
// 设置token到localStorage
|
||
export const setToken = (token: string) => {
|
||
if (typeof window !== 'undefined') {
|
||
localStorage.setItem('token', token);
|
||
}
|
||
};
|
||
|
||
// 获取token
|
||
export const getToken = (): string | null => {
|
||
if (typeof window !== 'undefined') {
|
||
return localStorage.getItem('token');
|
||
}
|
||
return null;
|
||
};
|
||
|
||
// 清除token
|
||
export const clearToken = () => {
|
||
if (typeof window !== 'undefined') {
|
||
localStorage.removeItem('token');
|
||
localStorage.removeItem('userInfo');
|
||
localStorage.removeItem('token_expired');
|
||
localStorage.removeItem('s2_accountId');
|
||
}
|
||
};
|
||
|
||
// 验证token是否有效
|
||
export const validateToken = async (): Promise<boolean> => {
|
||
try {
|
||
const response = await authApi.getUserInfo();
|
||
return response.code === 200;
|
||
} catch (error) {
|
||
console.error('Token验证失败:', error);
|
||
return false;
|
||
}
|
||
};
|
||
|
||
// 刷新令牌
|
||
export const refreshAuthToken = async (): Promise<boolean> => {
|
||
if (typeof window === 'undefined') {
|
||
return false;
|
||
}
|
||
|
||
try {
|
||
const response = await authApi.refreshToken();
|
||
if (response.code === 200 && response.data?.token) {
|
||
setToken(response.data.token);
|
||
// 更新过期时间
|
||
if (response.data.token_expired) {
|
||
localStorage.setItem('token_expired', response.data.token_expired);
|
||
}
|
||
return true;
|
||
}
|
||
return false;
|
||
} catch (error) {
|
||
console.error('刷新Token失败:', error);
|
||
return false;
|
||
}
|
||
};
|
||
|
||
// 检查token是否即将过期
|
||
export const isTokenExpiringSoon = (): boolean => {
|
||
if (typeof window === 'undefined') {
|
||
return false;
|
||
}
|
||
|
||
const tokenExpired = localStorage.getItem('token_expired');
|
||
if (!tokenExpired) return true;
|
||
|
||
try {
|
||
const expiredTime = new Date(tokenExpired).getTime();
|
||
const currentTime = new Date().getTime();
|
||
// 提前10分钟认为即将过期
|
||
return currentTime >= (expiredTime - 10 * 60 * 1000);
|
||
} catch (error) {
|
||
console.error('解析token过期时间失败:', error);
|
||
return true;
|
||
}
|
||
};
|
||
|
||
// 检查token是否已过期
|
||
export const isTokenExpired = (): boolean => {
|
||
if (typeof window === 'undefined') {
|
||
return false;
|
||
}
|
||
|
||
const tokenExpired = localStorage.getItem('token_expired');
|
||
if (!tokenExpired) return true;
|
||
|
||
try {
|
||
const expiredTime = new Date(tokenExpired).getTime();
|
||
const currentTime = new Date().getTime();
|
||
// 提前5分钟认为过期,给刷新留出时间
|
||
return currentTime >= (expiredTime - 5 * 60 * 1000);
|
||
} catch (error) {
|
||
console.error('解析token过期时间失败:', error);
|
||
return true;
|
||
}
|
||
};
|
||
|
||
// 请求去重器
|
||
class RequestDeduplicator {
|
||
private pendingRequests = new Map<string, Promise<any>>();
|
||
|
||
async deduplicate<T>(key: string, requestFn: () => Promise<T>): Promise<T> {
|
||
if (this.pendingRequests.has(key)) {
|
||
return this.pendingRequests.get(key)!;
|
||
}
|
||
|
||
const promise = requestFn();
|
||
this.pendingRequests.set(key, promise);
|
||
|
||
try {
|
||
const result = await promise;
|
||
return result;
|
||
} finally {
|
||
this.pendingRequests.delete(key);
|
||
}
|
||
}
|
||
|
||
getPendingCount(): number {
|
||
return this.pendingRequests.size;
|
||
}
|
||
|
||
clear(): void {
|
||
this.pendingRequests.clear();
|
||
}
|
||
}
|
||
|
||
// 请求取消管理器
|
||
class RequestCancelManager {
|
||
private abortControllers = new Map<string, AbortController>();
|
||
|
||
createController(key: string): AbortController {
|
||
// 取消之前的请求
|
||
this.cancelRequest(key);
|
||
|
||
const controller = new AbortController();
|
||
this.abortControllers.set(key, controller);
|
||
return controller;
|
||
}
|
||
|
||
cancelRequest(key: string): void {
|
||
const controller = this.abortControllers.get(key);
|
||
if (controller) {
|
||
controller.abort();
|
||
this.abortControllers.delete(key);
|
||
}
|
||
}
|
||
|
||
cancelAllRequests(): void {
|
||
this.abortControllers.forEach(controller => controller.abort());
|
||
this.abortControllers.clear();
|
||
}
|
||
|
||
getController(key: string): AbortController | undefined {
|
||
return this.abortControllers.get(key);
|
||
}
|
||
}
|
||
|
||
// 导出单例实例
|
||
export const requestDeduplicator = new RequestDeduplicator();
|
||
export const requestCancelManager = new RequestCancelManager();
|
||
|
||
/**
|
||
* 通用文件上传方法(支持图片、文件)
|
||
* @param {File} file - 要上传的文件对象
|
||
* @param {string} [uploadUrl='/v1/attachment/upload'] - 上传接口地址
|
||
* @returns {Promise<string>} - 上传成功后返回文件url
|
||
*/
|
||
export async function uploadFile(file: File, uploadUrl: string = '/v1/attachment/upload'): Promise<string> {
|
||
try {
|
||
// 创建 FormData 对象用于文件上传
|
||
const formData = new FormData();
|
||
formData.append('file', file);
|
||
|
||
// 使用 post 方法上传文件,设置正确的 Content-Type
|
||
const res = await post(uploadUrl, formData, {
|
||
headers: {
|
||
'Content-Type': 'multipart/form-data',
|
||
},
|
||
});
|
||
|
||
// 检查响应结果
|
||
if (res?.code === 200 && res?.data?.url) {
|
||
return res.data.url;
|
||
} else {
|
||
throw new Error(res?.msg || '文件上传失败');
|
||
}
|
||
} catch (e: any) {
|
||
throw new Error(e?.message || '文件上传失败');
|
||
}
|
||
}
|