init: 整合项目(dashboard + www + docs)
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
import { request } from '../request';
|
||||
|
||||
/**
|
||||
* Login
|
||||
*
|
||||
* @param userName User name
|
||||
* @param password Password
|
||||
*/
|
||||
export function fetchLogin(userName: string, password: string) {
|
||||
return request<Api.Auth.LoginResult>({
|
||||
url: '/auth/login',
|
||||
method: 'post',
|
||||
data: {
|
||||
username: userName,
|
||||
password
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Get current user info */
|
||||
export function fetchGetUserInfo() {
|
||||
return request<Api.Auth.DashboardUser>({ url: '/auth/me' });
|
||||
}
|
||||
|
||||
/**
|
||||
* Change password
|
||||
*
|
||||
* @param oldPassword Old password
|
||||
* @param newPassword New password
|
||||
*/
|
||||
export function fetchChangePassword(oldPassword: string, newPassword: string) {
|
||||
return request({
|
||||
url: '/auth/password',
|
||||
method: 'put',
|
||||
data: {
|
||||
old_password: oldPassword,
|
||||
new_password: newPassword
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { request } from '../request';
|
||||
import type { PageParams } from './brand';
|
||||
|
||||
export function fetchGetBlackList(
|
||||
params?: PageParams & {
|
||||
ota_id?: number;
|
||||
model?: string;
|
||||
mac?: string;
|
||||
}
|
||||
) {
|
||||
return request<Api.Common.PageResult<Api.Blacklist.Item>>({
|
||||
url: '/blacklist/',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchCreateBlackList(data: { ota_id: number; mac: string }) {
|
||||
return request<Api.Blacklist.Item>({
|
||||
url: '/blacklist/',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchUpdateBlackList(id: number, data: Record<string, unknown>) {
|
||||
return request<Api.Blacklist.Item>({
|
||||
url: `/blacklist/${id}`,
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchDeleteBlackList(id: number) {
|
||||
return request({
|
||||
url: `/blacklist/${id}`,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { request } from '../request';
|
||||
|
||||
/** Page list params used by dashboard list APIs */
|
||||
export interface PageParams {
|
||||
skip?: number;
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
export function fetchGetBrands(params?: PageParams & { name?: string }) {
|
||||
return request<Api.Common.PageResult<Api.Brand.Brand>>({
|
||||
url: '/brands/',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchGetBrand(id: number) {
|
||||
return request<Api.Brand.Brand>({
|
||||
url: `/brands/${id}`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchCreateBrand(data: Api.Brand.BrandPayload) {
|
||||
return request<Api.Brand.Brand>({
|
||||
url: '/brands/',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchUpdateBrand(data: Api.Brand.BrandPayload & { id: number }) {
|
||||
return request<Api.Brand.Brand>({
|
||||
url: `/brands/${data.id}`,
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchDeleteBrand(id: number) {
|
||||
return request({
|
||||
url: `/brands/${id}`,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import { request } from '../request';
|
||||
|
||||
export function fetchGetDashboardToday() {
|
||||
return request<Api.Dashboard.TodayStats>({
|
||||
url: '/dashboard/today',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchGetDeviceDaily(days: number = 30) {
|
||||
return request<Api.Dashboard.DeviceDailyStats>({
|
||||
url: '/dashboard/device-daily',
|
||||
method: 'get',
|
||||
params: { days }
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchGetActiveDaily(days: number = 30) {
|
||||
return request<Api.Dashboard.ActiveDailyStats>({
|
||||
url: '/dashboard/active-daily',
|
||||
method: 'get',
|
||||
params: { days }
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
export * from './auth';
|
||||
export * from './route';
|
||||
export * from './brand';
|
||||
export * from './dashboard';
|
||||
export * from './user';
|
||||
export * from './ota';
|
||||
export * from './blacklist';
|
||||
export * from './ota-target-device';
|
||||
export * from './share-code-log';
|
||||
export * from './model';
|
||||
@@ -0,0 +1,131 @@
|
||||
import { request } from '../request';
|
||||
import type { PageParams } from './brand';
|
||||
|
||||
export function fetchGetModels(
|
||||
params?: PageParams & {
|
||||
brand_name?: string;
|
||||
name?: string;
|
||||
sort_by?: string;
|
||||
sort_order?: string;
|
||||
}
|
||||
) {
|
||||
return request<Api.Common.PageResult<Api.Model.ModelItem>>({
|
||||
url: '/models/',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchGetModel(id: number) {
|
||||
return request<Api.Model.ModelItem>({
|
||||
url: `/models/${id}`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchCreateModel(data: FormData | Record<string, unknown>, isFormData = false) {
|
||||
return request<Api.Model.ModelItem>({
|
||||
url: '/models/',
|
||||
method: 'post',
|
||||
data,
|
||||
headers: isFormData ? { 'Content-Type': 'multipart/form-data' } : {}
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchUpdateModel(id: number, data: FormData | Record<string, unknown>, isFormData = false) {
|
||||
return request<Api.Model.ModelItem>({
|
||||
url: `/models/${id}`,
|
||||
method: 'put',
|
||||
data,
|
||||
headers: isFormData ? { 'Content-Type': 'multipart/form-data' } : {}
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchDeleteModel(id: number) {
|
||||
return request({
|
||||
url: `/models/${id}`,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchGetModelEqCache(id: number) {
|
||||
return request({
|
||||
url: `/models/${id}/eq-cache`,
|
||||
method: 'get',
|
||||
timeout: 30000
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchGetModelEqCacheField(id: number, fieldKey: string) {
|
||||
return request({
|
||||
url: `/models/${id}/eq-cache/field`,
|
||||
method: 'get',
|
||||
params: { key: fieldKey },
|
||||
timeout: 30000
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchGetModelMeilisearch(id: number) {
|
||||
return request({
|
||||
url: `/models/${id}/meilisearch`,
|
||||
method: 'get',
|
||||
timeout: 30000
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchGetModelMeasurement(id: number) {
|
||||
return request({
|
||||
url: `/models/${id}/measurement`,
|
||||
method: 'get',
|
||||
timeout: 30000
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchValidatePushToMeilisearch(modelIds: number[]) {
|
||||
return request({
|
||||
url: '/models/push-to-search/validate',
|
||||
method: 'post',
|
||||
data: { model_ids: modelIds },
|
||||
timeout: 120000,
|
||||
// @ts-expect-error custom flag consumed by request onError
|
||||
skipErrorToast: true
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchPushToMeilisearch(modelIds: number[]) {
|
||||
return request({
|
||||
url: '/models/push-to-search',
|
||||
method: 'post',
|
||||
data: { model_ids: modelIds },
|
||||
timeout: 60000,
|
||||
// @ts-expect-error custom flag consumed by request onError
|
||||
skipErrorToast: true
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchBatchUpdateModels(data: {
|
||||
ids: number[];
|
||||
brand_name?: string;
|
||||
form?: string;
|
||||
source?: string;
|
||||
rig?: string;
|
||||
}) {
|
||||
return request<{
|
||||
updated_count: number;
|
||||
updated_ids: number[];
|
||||
errors: Array<{ id: number; brand_name: string; name: string; error: string }>;
|
||||
}>({
|
||||
url: '/models/batch-update',
|
||||
method: 'patch',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchFromSquigLink(shareUrl: string, selectedFile?: string) {
|
||||
return request({
|
||||
url: '/models/squiglink-fetch',
|
||||
method: 'post',
|
||||
data: { share_url: shareUrl, selected_file: selectedFile },
|
||||
timeout: 30000
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { request } from '../request';
|
||||
import type { PageParams } from './brand';
|
||||
|
||||
export function fetchGetOtaTargetDeviceList(
|
||||
params?: PageParams & {
|
||||
ota_id?: number;
|
||||
model?: string;
|
||||
mac_addr?: string;
|
||||
}
|
||||
) {
|
||||
return request<Api.Common.PageResult<Api.OtaTargetDevice.Item>>({
|
||||
url: '/ota-target-device/',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchCreateOtaTargetDevice(data: { ota_id: number; mac_addr: string }) {
|
||||
return request<Api.OtaTargetDevice.Item>({
|
||||
url: '/ota-target-device/',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchUpdateOtaTargetDevice(id: number, data: Record<string, unknown>) {
|
||||
return request<Api.OtaTargetDevice.Item>({
|
||||
url: `/ota-target-device/${id}`,
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchDeleteOtaTargetDevice(id: number) {
|
||||
return request({
|
||||
url: `/ota-target-device/${id}`,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import { request } from '../request';
|
||||
import type { PageParams } from './brand';
|
||||
|
||||
export function fetchGetOtaList(
|
||||
params?: PageParams & {
|
||||
verCode?: number;
|
||||
verName?: string;
|
||||
model?: string;
|
||||
status?: number;
|
||||
beta?: number;
|
||||
}
|
||||
) {
|
||||
return request<Api.Common.PageResult<Api.Ota.OtaItem>>({
|
||||
url: '/ota/',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchGetOta(id: number) {
|
||||
return request<Api.Ota.OtaItem>({
|
||||
url: `/ota/${id}`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchCreateOta(data: Record<string, unknown>) {
|
||||
return request<Api.Ota.OtaItem>({
|
||||
url: '/ota/',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchUpdateOta(id: number, data: Record<string, unknown>) {
|
||||
return request<Api.Ota.OtaItem>({
|
||||
url: `/ota/${id}`,
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchDeleteOta(id: number) {
|
||||
return request({
|
||||
url: `/ota/${id}`,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchUploadOtaPackage(file: File, model: string) {
|
||||
const formData = new FormData();
|
||||
formData.append('package_file', file);
|
||||
formData.append('model', model);
|
||||
return request({
|
||||
url: '/ota/upload-package',
|
||||
method: 'post',
|
||||
data: formData,
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
timeout: 300000
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { request } from '../request';
|
||||
|
||||
/** get constant routes */
|
||||
export function fetchGetConstantRoutes() {
|
||||
return request<Api.Route.MenuRoute[]>({ url: '/route/getConstantRoutes' });
|
||||
}
|
||||
|
||||
/** get user routes */
|
||||
export function fetchGetUserRoutes() {
|
||||
return request<Api.Route.UserRoute>({ url: '/route/getUserRoutes' });
|
||||
}
|
||||
|
||||
/**
|
||||
* whether the route is exist
|
||||
*
|
||||
* @param routeName route name
|
||||
*/
|
||||
export function fetchIsRouteExist(routeName: string) {
|
||||
return request<boolean>({ url: '/route/isRouteExist', params: { routeName } });
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { request } from '../request';
|
||||
import type { PageParams } from './brand';
|
||||
|
||||
export function fetchGetShareCodeLogs(
|
||||
params?: PageParams & {
|
||||
mac_addr?: string;
|
||||
share_code?: string;
|
||||
action?: 'export' | 'import';
|
||||
ip_addr?: string;
|
||||
start_at?: string;
|
||||
end_at?: string;
|
||||
sort_by?: 'id' | 'create_at';
|
||||
sort_order?: 'asc' | 'desc';
|
||||
}
|
||||
) {
|
||||
return request<Api.Common.PageResult<Api.ShareCodeLog.Item>>({
|
||||
url: '/share-code/logs',
|
||||
method: 'get',
|
||||
params,
|
||||
timeout: 30000
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { request } from '../request';
|
||||
import type { PageParams } from './brand';
|
||||
|
||||
export function fetchGetUsers(params?: PageParams & { username?: string }) {
|
||||
return request<Api.Common.PageResult<Api.User.User>>({
|
||||
url: '/users/',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchCreateUser(data: Api.User.CreatePayload) {
|
||||
return request<Api.User.User>({
|
||||
url: '/users/',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchUpdateUser(id: number, data: Api.User.UpdatePayload) {
|
||||
return request<Api.User.User>({
|
||||
url: `/users/${id}`,
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchDeleteUser(id: number) {
|
||||
return request({
|
||||
url: `/users/${id}`,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
import type { AxiosResponse } from 'axios';
|
||||
import { BACKEND_ERROR_CODE, createFlatRequest, createRequest } from '@sa/axios';
|
||||
import { useAuthStore } from '@/store/modules/auth';
|
||||
import { localStg } from '@/utils/storage';
|
||||
import { getServiceBaseURL } from '@/utils/service';
|
||||
import { $t } from '@/locales';
|
||||
import { getAuthorization, handleExpiredRequest, showErrorMsg } from './shared';
|
||||
import type { RequestInstanceState } from './type';
|
||||
|
||||
const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y';
|
||||
const { baseURL, otherBaseURL } = getServiceBaseURL(import.meta.env, isHttpProxy);
|
||||
|
||||
/** Dashboard backend treats code 1 as success and code 2 as "no data" (still ok). */
|
||||
function isDashboardSuccessCode(code: unknown) {
|
||||
const value = String(code);
|
||||
const successCode = String(import.meta.env.VITE_SERVICE_SUCCESS_CODE || '1');
|
||||
return value === successCode || value === '2';
|
||||
}
|
||||
|
||||
export const request = createFlatRequest(
|
||||
{
|
||||
baseURL,
|
||||
timeout: 30000
|
||||
},
|
||||
{
|
||||
defaultState: {
|
||||
errMsgStack: [],
|
||||
refreshTokenPromise: null
|
||||
} as RequestInstanceState,
|
||||
transform(response: AxiosResponse<App.Service.Response<any>>) {
|
||||
return response.data.data;
|
||||
},
|
||||
async onRequest(config) {
|
||||
const Authorization = getAuthorization();
|
||||
Object.assign(config.headers, { Authorization });
|
||||
|
||||
return config;
|
||||
},
|
||||
isBackendSuccess(response) {
|
||||
return isDashboardSuccessCode(response.data.code);
|
||||
},
|
||||
async onBackendFail(response, instance) {
|
||||
const authStore = useAuthStore();
|
||||
const responseCode = String(response.data.code);
|
||||
|
||||
function handleLogout() {
|
||||
authStore.resetStore();
|
||||
}
|
||||
|
||||
function logoutAndCleanup() {
|
||||
handleLogout();
|
||||
window.removeEventListener('beforeunload', handleLogout);
|
||||
|
||||
request.state.errMsgStack = request.state.errMsgStack.filter(msg => msg !== response.data.msg);
|
||||
}
|
||||
|
||||
const logoutCodes = import.meta.env.VITE_SERVICE_LOGOUT_CODES?.split(',').filter(Boolean) || [];
|
||||
if (logoutCodes.includes(responseCode)) {
|
||||
handleLogout();
|
||||
return null;
|
||||
}
|
||||
|
||||
const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',').filter(Boolean) || [];
|
||||
if (modalLogoutCodes.includes(responseCode) && !request.state.errMsgStack?.includes(response.data.msg)) {
|
||||
request.state.errMsgStack = [...(request.state.errMsgStack || []), response.data.msg];
|
||||
|
||||
window.addEventListener('beforeunload', handleLogout);
|
||||
|
||||
window.$dialog?.error({
|
||||
title: $t('common.error'),
|
||||
content: response.data.msg,
|
||||
positiveText: $t('common.confirm'),
|
||||
maskClosable: false,
|
||||
closeOnEsc: false,
|
||||
onPositiveClick() {
|
||||
logoutAndCleanup();
|
||||
},
|
||||
onClose() {
|
||||
logoutAndCleanup();
|
||||
}
|
||||
});
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const expiredTokenCodes = import.meta.env.VITE_SERVICE_EXPIRED_TOKEN_CODES?.split(',').filter(Boolean) || [];
|
||||
if (expiredTokenCodes.includes(responseCode)) {
|
||||
const success = await handleExpiredRequest(request.state);
|
||||
if (success) {
|
||||
const Authorization = getAuthorization();
|
||||
Object.assign(response.config.headers, { Authorization });
|
||||
|
||||
return instance.request(response.config) as Promise<AxiosResponse>;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
onError(error) {
|
||||
const status = error.response?.status;
|
||||
|
||||
// HTTP 401 from dashboard auth middleware
|
||||
if (status === 401) {
|
||||
const authStore = useAuthStore();
|
||||
authStore.resetStore();
|
||||
const detail = (error.response?.data as { detail?: string } | undefined)?.detail;
|
||||
if (detail) {
|
||||
showErrorMsg(request.state, typeof detail === 'string' ? detail : $t('request.logoutMsg'));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (status === 403) {
|
||||
const detail = (error.response?.data as { detail?: string } | undefined)?.detail;
|
||||
showErrorMsg(request.state, typeof detail === 'string' ? detail : '无权限执行此操作');
|
||||
return;
|
||||
}
|
||||
|
||||
let message = error.message;
|
||||
let backendErrorCode = '';
|
||||
|
||||
if (error.code === BACKEND_ERROR_CODE) {
|
||||
message = error.response?.data?.msg || message;
|
||||
backendErrorCode = String(error.response?.data?.code || '');
|
||||
}
|
||||
|
||||
const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',').filter(Boolean) || [];
|
||||
if (modalLogoutCodes.includes(backendErrorCode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const expiredTokenCodes = import.meta.env.VITE_SERVICE_EXPIRED_TOKEN_CODES?.split(',').filter(Boolean) || [];
|
||||
if (expiredTokenCodes.includes(backendErrorCode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Allow callers to suppress toast (e.g. model push progress dialog)
|
||||
const cfg = error.config as (typeof error.config & { skipErrorToast?: boolean }) | undefined;
|
||||
if (cfg?.skipErrorToast) {
|
||||
return;
|
||||
}
|
||||
|
||||
showErrorMsg(request.state, message);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const demoRequest = createRequest(
|
||||
{
|
||||
baseURL: otherBaseURL.demo
|
||||
},
|
||||
{
|
||||
transform(response: AxiosResponse<App.Service.DemoResponse>) {
|
||||
return response.data.result;
|
||||
},
|
||||
async onRequest(config) {
|
||||
const { headers } = config;
|
||||
|
||||
const token = localStg.get('token');
|
||||
const Authorization = token ? `Bearer ${token}` : null;
|
||||
Object.assign(headers, { Authorization });
|
||||
|
||||
return config;
|
||||
},
|
||||
isBackendSuccess(response) {
|
||||
return response.data.status === '200';
|
||||
},
|
||||
async onBackendFail(_response) {
|
||||
// noop
|
||||
},
|
||||
onError(error) {
|
||||
let message = error.message;
|
||||
|
||||
if (error.code === BACKEND_ERROR_CODE) {
|
||||
message = error.response?.data?.message || message;
|
||||
}
|
||||
|
||||
window.$message?.error(message);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,53 @@
|
||||
import { useAuthStore } from '@/store/modules/auth';
|
||||
import { localStg } from '@/utils/storage';
|
||||
import type { RequestInstanceState } from './type';
|
||||
|
||||
export function getAuthorization() {
|
||||
const token = localStg.get('token');
|
||||
const Authorization = token ? `Bearer ${token}` : null;
|
||||
|
||||
return Authorization;
|
||||
}
|
||||
|
||||
/** Dashboard backend has no refresh-token API; always fail and logout. */
|
||||
async function handleRefreshToken() {
|
||||
const { resetStore } = useAuthStore();
|
||||
resetStore();
|
||||
return false;
|
||||
}
|
||||
|
||||
export async function handleExpiredRequest(state: RequestInstanceState) {
|
||||
if (!state.refreshTokenPromise) {
|
||||
state.refreshTokenPromise = handleRefreshToken();
|
||||
}
|
||||
|
||||
const success = await state.refreshTokenPromise;
|
||||
|
||||
setTimeout(() => {
|
||||
state.refreshTokenPromise = null;
|
||||
}, 1000);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
export function showErrorMsg(state: RequestInstanceState, message: string) {
|
||||
if (!state.errMsgStack?.length) {
|
||||
state.errMsgStack = [];
|
||||
}
|
||||
|
||||
const isExist = state.errMsgStack.includes(message);
|
||||
|
||||
if (!isExist) {
|
||||
state.errMsgStack.push(message);
|
||||
|
||||
window.$message?.error(message, {
|
||||
onLeave: () => {
|
||||
state.errMsgStack = state.errMsgStack.filter(msg => msg !== message);
|
||||
|
||||
setTimeout(() => {
|
||||
state.errMsgStack = [];
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export interface RequestInstanceState {
|
||||
/** the promise of refreshing token */
|
||||
refreshTokenPromise: Promise<boolean> | null;
|
||||
/** the request error message stack */
|
||||
errMsgStack: string[];
|
||||
[key: string]: unknown;
|
||||
}
|
||||
Reference in New Issue
Block a user