feat: 本次提交更新内容如下

定版本转移2025年7月17日
This commit is contained in:
笔记本里的永平
2025-07-17 10:22:38 +08:00
parent 0f860d01e4
commit 92a3d407a7
645 changed files with 30755 additions and 118800 deletions

195
Cunkebao/src/api/utils.ts Normal file
View File

@@ -0,0 +1,195 @@
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 || '文件上传失败');
}
}