feat: 本次提交更新内容如下
优化
This commit is contained in:
44
nkebao/src/api/devices.ts
Normal file
44
nkebao/src/api/devices.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import request from "./request";
|
||||
|
||||
// 获取设备列表
|
||||
export const fetchDeviceList = (params: {
|
||||
page?: number;
|
||||
limit?: number;
|
||||
keyword?: string;
|
||||
}) => request("/v1/devices", params, "GET");
|
||||
|
||||
// 获取设备详情
|
||||
export const fetchDeviceDetail = (id: string | number) =>
|
||||
request(`/v1/devices/${id}`);
|
||||
|
||||
// 获取设备关联微信账号
|
||||
export const fetchDeviceRelatedAccounts = (id: string | number) =>
|
||||
request(`/v1/wechats/related-device/${id}`);
|
||||
|
||||
// 获取设备操作日志
|
||||
export const fetchDeviceHandleLogs = (
|
||||
id: string | number,
|
||||
page = 1,
|
||||
limit = 10
|
||||
) => request(`/v1/devices/${id}/handle-logs`, { page, limit }, "GET");
|
||||
|
||||
// 更新设备任务配置
|
||||
export const updateDeviceTaskConfig = (config: {
|
||||
deviceId: string | number;
|
||||
autoAddFriend?: boolean;
|
||||
autoReply?: boolean;
|
||||
momentsSync?: boolean;
|
||||
aiChat?: boolean;
|
||||
}) => request("/v1/devices/task-config", config, "POST");
|
||||
|
||||
// 删除设备
|
||||
export const deleteDevice = (id: number) =>
|
||||
request(`/v1/devices/${id}`, undefined, "DELETE");
|
||||
|
||||
// 获取设备二维码
|
||||
export const fetchDeviceQRCode = (accountId: string) =>
|
||||
request("/v1/api/device/add", { accountId }, "POST");
|
||||
|
||||
// 通过IMEI添加设备
|
||||
export const addDeviceByImei = (imei: string, name: string) =>
|
||||
request("/v1/api/device/add-by-imei", { imei, name }, "POST");
|
||||
@@ -1,22 +1,35 @@
|
||||
import axios, { AxiosInstance, AxiosRequestConfig, Method, AxiosResponse } from 'axios';
|
||||
import { Toast } from 'antd-mobile';
|
||||
import axios, {
|
||||
AxiosInstance,
|
||||
AxiosRequestConfig,
|
||||
Method,
|
||||
AxiosResponse,
|
||||
} from "axios";
|
||||
import { Toast } from "antd-mobile";
|
||||
|
||||
const DEFAULT_DEBOUNCE_GAP = 1000;
|
||||
const debounceMap = new Map<string, number>();
|
||||
|
||||
// 死循环请求拦截配置
|
||||
const FAIL_LIMIT = 3;
|
||||
const BLOCK_TIME = 30 * 1000; // 30秒
|
||||
const failMap = new Map<
|
||||
string,
|
||||
{ count: number; lastFail: number; blockedUntil?: number }
|
||||
>();
|
||||
|
||||
const instance: AxiosInstance = axios.create({
|
||||
baseURL: (import.meta as any).env?.VITE_API_BASE_URL || '/api',
|
||||
baseURL: (import.meta as any).env?.VITE_API_BASE_URL || "/api",
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
instance.interceptors.request.use(config => {
|
||||
const token = localStorage.getItem('token');
|
||||
instance.interceptors.request.use((config) => {
|
||||
const token = localStorage.getItem("token");
|
||||
if (token) {
|
||||
config.headers = config.headers || {};
|
||||
config.headers['Authorization'] = `Bearer ${token}`;
|
||||
config.headers["Authorization"] = `Bearer ${token}`;
|
||||
}
|
||||
return config;
|
||||
});
|
||||
@@ -27,20 +40,20 @@ instance.interceptors.response.use(
|
||||
if (code === 200 || success) {
|
||||
return res.data.data ?? res.data;
|
||||
}
|
||||
Toast.show({ content: msg || '接口错误', position: 'top' });
|
||||
Toast.show({ content: msg || "接口错误", position: "top" });
|
||||
if (code === 401) {
|
||||
localStorage.removeItem('token');
|
||||
localStorage.removeItem("token");
|
||||
const currentPath = window.location.pathname + window.location.search;
|
||||
if (currentPath === '/login') {
|
||||
window.location.href = '/login';
|
||||
if (currentPath === "/login") {
|
||||
window.location.href = "/login";
|
||||
} else {
|
||||
window.location.href = `/login?redirect=${encodeURIComponent(currentPath)}`;
|
||||
}
|
||||
}
|
||||
return Promise.reject(msg || '接口错误');
|
||||
return Promise.reject(msg || "接口错误");
|
||||
},
|
||||
err => {
|
||||
Toast.show({ content: err.message || '网络异常', position: 'top' });
|
||||
(err) => {
|
||||
Toast.show({ content: err.message || "网络异常", position: "top" });
|
||||
return Promise.reject(err);
|
||||
}
|
||||
);
|
||||
@@ -48,17 +61,26 @@ instance.interceptors.response.use(
|
||||
export function request(
|
||||
url: string,
|
||||
data?: any,
|
||||
method: Method = 'GET',
|
||||
method: Method = "GET",
|
||||
config?: AxiosRequestConfig,
|
||||
debounceGap?: number
|
||||
): Promise<any> {
|
||||
const gap = typeof debounceGap === 'number' ? debounceGap : DEFAULT_DEBOUNCE_GAP;
|
||||
const gap =
|
||||
typeof debounceGap === "number" ? debounceGap : DEFAULT_DEBOUNCE_GAP;
|
||||
const key = `${method}_${url}_${JSON.stringify(data)}`;
|
||||
const now = Date.now();
|
||||
const last = debounceMap.get(key) || 0;
|
||||
|
||||
// 死循环拦截:如果被block,直接拒绝
|
||||
const failInfo = failMap.get(key);
|
||||
if (failInfo && failInfo.blockedUntil && now < failInfo.blockedUntil) {
|
||||
Toast.show({ content: "请求失败过多,请稍后再试", position: "top" });
|
||||
return Promise.reject("请求失败过多,请稍后再试");
|
||||
}
|
||||
|
||||
if (gap > 0 && now - last < gap) {
|
||||
Toast.show({ content: '请求过于频繁,请稍后再试', position: 'top' });
|
||||
return Promise.reject('请求过于频繁,请稍后再试');
|
||||
Toast.show({ content: "请求过于频繁,请稍后再试", position: "top" });
|
||||
return Promise.reject("请求过于频繁,请稍后再试");
|
||||
}
|
||||
debounceMap.set(key, now);
|
||||
|
||||
@@ -67,12 +89,33 @@ export function request(
|
||||
method,
|
||||
...config,
|
||||
};
|
||||
if (method.toUpperCase() === 'GET') {
|
||||
if (method.toUpperCase() === "GET") {
|
||||
axiosConfig.params = data;
|
||||
} else {
|
||||
axiosConfig.data = data;
|
||||
}
|
||||
return instance(axiosConfig);
|
||||
return instance(axiosConfig)
|
||||
.then((res) => {
|
||||
// 成功则清除失败计数
|
||||
failMap.delete(key);
|
||||
return res;
|
||||
})
|
||||
.catch((err) => {
|
||||
debounceMap.delete(key);
|
||||
// 失败计数
|
||||
const fail = failMap.get(key) || { count: 0, lastFail: 0 };
|
||||
const newCount = now - fail.lastFail < BLOCK_TIME ? fail.count + 1 : 1;
|
||||
if (newCount >= FAIL_LIMIT) {
|
||||
failMap.set(key, {
|
||||
count: newCount,
|
||||
lastFail: now,
|
||||
blockedUntil: now + BLOCK_TIME,
|
||||
});
|
||||
} else {
|
||||
failMap.set(key, { count: newCount, lastFail: now });
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
export default request;
|
||||
|
||||
Reference in New Issue
Block a user