feat(config): 实现后端配置管理功能
- 添加 ApiUrl 和 theme 配置字段支持 - 新增根据 code 查询应用参数的 API 接口- 实现配置 store 管理网站配置数据 - 支持 API 地址优先级: 后台配置 > 本地配置- 配置数据自动存储到 localStorage 实现持久化- 添加配置管理说明文档 CONFIG_MANAGEMENT.md- 优化请求工具支持动态 API 地址切换- 移除无用的 openNew 工具函数引入 - 实现主题配置自动加载和存储功能
This commit is contained in:
149
CONFIG_MANAGEMENT.md
Normal file
149
CONFIG_MANAGEMENT.md
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
# 后端配置管理说明
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
本项目实现了与小程序端一致的配置管理机制,后端管理端现在也支持优先使用后台配置的API地址。
|
||||||
|
|
||||||
|
## 核心文件
|
||||||
|
|
||||||
|
1. `src/store/modules/config.ts` - 配置状态管理模块
|
||||||
|
2. `src/composables/useConfig.ts` - 配置初始化组合式函数
|
||||||
|
3. `src/views/system/config-demo.vue` - 配置演示页面
|
||||||
|
4. `src/utils/request.ts` - 更新后的请求工具,支持API地址优先级
|
||||||
|
|
||||||
|
## 功能特性
|
||||||
|
|
||||||
|
### 1. API地址优先级
|
||||||
|
- 优先使用后台配置的API地址(存储在config中的ApiUrl字段)
|
||||||
|
- 如果未配置,则回退使用本地配置的API_BASE_URL
|
||||||
|
|
||||||
|
### 2. 配置存储
|
||||||
|
- 使用Pinia进行状态管理
|
||||||
|
- 同时存储在localStorage中,支持持久化
|
||||||
|
- 提供获取、设置、刷新、清除配置的方法
|
||||||
|
|
||||||
|
### 3. 自动初始化
|
||||||
|
- 应用启动时自动加载配置
|
||||||
|
- 支持从缓存中快速恢复配置
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
### 在组件中使用配置store
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { useConfigStore } from '@/store/modules/config';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
setup() {
|
||||||
|
const configStore = useConfigStore();
|
||||||
|
|
||||||
|
// 获取配置
|
||||||
|
const config = configStore.config;
|
||||||
|
|
||||||
|
// 获取API地址
|
||||||
|
const apiUrl = configStore.getApiUrl;
|
||||||
|
|
||||||
|
// 获取网站名称
|
||||||
|
const siteName = configStore.getSiteName;
|
||||||
|
|
||||||
|
// 刷新配置
|
||||||
|
const refreshConfig = async () => {
|
||||||
|
try {
|
||||||
|
await configStore.refetchConfig();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('刷新配置失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
config,
|
||||||
|
apiUrl,
|
||||||
|
siteName,
|
||||||
|
refreshConfig
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 在组合式API中使用
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { useConfigStore } from '@/store/modules/config';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
setup() {
|
||||||
|
const configStore = useConfigStore();
|
||||||
|
|
||||||
|
// 监听配置变化
|
||||||
|
watch(() => configStore.config, (newConfig) => {
|
||||||
|
console.log('配置已更新:', newConfig);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 在请求工具中使用
|
||||||
|
|
||||||
|
请求工具会自动优先使用配置中的API地址:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// src/utils/request.ts
|
||||||
|
const getBaseUrl = (): string => {
|
||||||
|
// 尝试从配置store获取后台配置的API地址
|
||||||
|
try {
|
||||||
|
const configStore = useConfigStore();
|
||||||
|
if (configStore.config && configStore.config.ApiUrl) {
|
||||||
|
return configStore.config.ApiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 回退到localStorage
|
||||||
|
const configStr = localStorage.getItem('config');
|
||||||
|
if (configStr) {
|
||||||
|
const config = typeof configStr === 'string' ? JSON.parse(configStr) : configStr;
|
||||||
|
if (config && config.ApiUrl) {
|
||||||
|
return config.ApiUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('获取后台配置API地址失败:', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 最后回退到本地配置
|
||||||
|
return API_BASE_URL;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## 配置字段说明
|
||||||
|
|
||||||
|
配置对象包含以下字段:
|
||||||
|
|
||||||
|
- `siteName` - 网站名称
|
||||||
|
- `siteLogo` - 网站Logo
|
||||||
|
- `domain` - 域名
|
||||||
|
- `icpNo` - ICP备案号
|
||||||
|
- `copyright` - 版权信息
|
||||||
|
- `loginBgImg` - 登录背景图
|
||||||
|
- `address` - 联系地址
|
||||||
|
- `tel` - 联系电话
|
||||||
|
- `kefu2` - 客服2
|
||||||
|
- `kefu1` - 客服1
|
||||||
|
- `email` - 邮箱
|
||||||
|
- `loginTitle` - 登录标题
|
||||||
|
- `sysLogo` - 系统Logo
|
||||||
|
- `ApiUrl` - API地址(新增)
|
||||||
|
- `theme` - 主题(新增)
|
||||||
|
|
||||||
|
## 菜单配置
|
||||||
|
|
||||||
|
配置演示页面已添加到系统管理菜单中:
|
||||||
|
- 路径:`/system/config-demo`
|
||||||
|
- 组件:`/src/views/system/config-demo.vue`
|
||||||
|
- 图标:`ExperimentOutlined`
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. 配置数据会自动存储在localStorage中,键名为`config`
|
||||||
|
2. 主题配置会存储在localStorage中,键名为`user_theme`
|
||||||
|
3. 如果需要自定义配置字段,需要更新`src/api/cms/cmsWebsiteField/model/index.ts`中的Config接口定义
|
||||||
@@ -105,6 +105,19 @@ export async function getCmsWebsiteField(id: number) {
|
|||||||
return Promise.reject(new Error(res.data.message));
|
return Promise.reject(new Error(res.data.message));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据code查询应用参数
|
||||||
|
*/
|
||||||
|
export async function getCmsWebsiteFieldByCode(code: string) {
|
||||||
|
const res = await request.get<ApiResult<CmsWebsiteField>>(
|
||||||
|
MODULES_API_URL + '/cms/cms-website-field/getByCode/' + code
|
||||||
|
);
|
||||||
|
if (res.data.code === 0 && res.data.data) {
|
||||||
|
return res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 恢复项目参数
|
* 恢复项目参数
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -58,4 +58,8 @@ export interface Config {
|
|||||||
email?: string;
|
email?: string;
|
||||||
loginTitle?: string;
|
loginTitle?: string;
|
||||||
sysLogo?: string;
|
sysLogo?: string;
|
||||||
}
|
// 添加API地址配置项
|
||||||
|
ApiUrl?: string;
|
||||||
|
// 添加主题配置项
|
||||||
|
theme?: string;
|
||||||
|
}
|
||||||
@@ -141,7 +141,7 @@ import {
|
|||||||
FullscreenExitOutlined
|
FullscreenExitOutlined
|
||||||
} from '@ant-design/icons-vue';
|
} from '@ant-design/icons-vue';
|
||||||
import {storeToRefs} from 'pinia';
|
import {storeToRefs} from 'pinia';
|
||||||
import {copyText, openNew, openUrl} from '@/utils/common';
|
import {copyText, openUrl} from '@/utils/common';
|
||||||
import {useThemeStore} from '@/store/modules/theme';
|
import {useThemeStore} from '@/store/modules/theme';
|
||||||
import HeaderNotice from './header-notice.vue';
|
import HeaderNotice from './header-notice.vue';
|
||||||
import PasswordModal from './password-modal.vue';
|
import PasswordModal from './password-modal.vue';
|
||||||
@@ -152,6 +152,8 @@ import {listRoles} from '@/api/system/role';
|
|||||||
import { useSiteStore } from '@/store/modules/site';
|
import { useSiteStore } from '@/store/modules/site';
|
||||||
import Qrcode from "@/components/QrCode/index.vue";
|
import Qrcode from "@/components/QrCode/index.vue";
|
||||||
import {AppInfo} from "@/api/cms/cmsWebsite/model";
|
import {AppInfo} from "@/api/cms/cmsWebsite/model";
|
||||||
|
import {getCmsWebsiteFieldByCode} from "@/api/cms/cmsWebsiteField";
|
||||||
|
import {API_BASE_URL} from "@/config/setting";
|
||||||
|
|
||||||
// 是否开启响应式布局
|
// 是否开启响应式布局
|
||||||
const themeStore = useThemeStore();
|
const themeStore = useThemeStore();
|
||||||
@@ -244,6 +246,15 @@ const reload = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// 检查是否启动自定义接口
|
||||||
|
if(!localStorage.getItem('ApiUrl')){
|
||||||
|
localStorage.setItem('ApiUrl', `${API_BASE_URL}`)
|
||||||
|
getCmsWebsiteFieldByCode('ApiUrl').then(res => {
|
||||||
|
if(res){
|
||||||
|
localStorage.setItem('ApiUrl', `${res.value}`);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
reload();
|
reload();
|
||||||
|
|||||||
119
src/store/modules/template.ts
Normal file
119
src/store/modules/template.ts
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
/**
|
||||||
|
* 网站配置 store
|
||||||
|
*/
|
||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import {configWebsiteField} from '@/api/cms/cmsWebsiteField';
|
||||||
|
import type { Config } from '@/api/cms/cmsWebsiteField/model';
|
||||||
|
|
||||||
|
export interface ConfigState {
|
||||||
|
config: Config | null;
|
||||||
|
loading: boolean;
|
||||||
|
error: Error | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useConfigStore = defineStore({
|
||||||
|
id: 'config',
|
||||||
|
state: (): ConfigState => ({
|
||||||
|
// 网站配置数据
|
||||||
|
config: null,
|
||||||
|
// 加载状态
|
||||||
|
loading: false,
|
||||||
|
// 错误信息
|
||||||
|
error: null
|
||||||
|
}),
|
||||||
|
getters: {
|
||||||
|
/**
|
||||||
|
* 获取网站配置
|
||||||
|
*/
|
||||||
|
getConfig(state): Config | null {
|
||||||
|
return state.config;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取API地址
|
||||||
|
*/
|
||||||
|
getApiUrl(state): string | undefined {
|
||||||
|
return state.config?.ApiUrl;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取网站名称
|
||||||
|
*/
|
||||||
|
getSiteName(state): string | undefined {
|
||||||
|
return state.config?.siteName;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取网站Logo
|
||||||
|
*/
|
||||||
|
getSiteLogo(state): string | undefined {
|
||||||
|
return state.config?.siteLogo;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
/**
|
||||||
|
* 获取网站配置数据
|
||||||
|
*/
|
||||||
|
async fetchConfig() {
|
||||||
|
try {
|
||||||
|
this.loading = true;
|
||||||
|
this.error = null;
|
||||||
|
const data = await configWebsiteField();
|
||||||
|
this.config = data;
|
||||||
|
|
||||||
|
// 保存到localStorage中,供其他地方使用
|
||||||
|
localStorage.setItem('config', JSON.stringify(data));
|
||||||
|
|
||||||
|
// 设置主题
|
||||||
|
if (data.theme && !localStorage.getItem('user_theme')) {
|
||||||
|
localStorage.setItem('user_theme', data.theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
} catch (err) {
|
||||||
|
this.error = err instanceof Error ? err : new Error('获取配置失败');
|
||||||
|
console.error('获取网站配置失败:', err);
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新配置数据
|
||||||
|
*/
|
||||||
|
setConfig(value: Config) {
|
||||||
|
this.config = value;
|
||||||
|
// 同时更新localStorage
|
||||||
|
localStorage.setItem('config', JSON.stringify(value));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重新获取配置数据
|
||||||
|
*/
|
||||||
|
async refetchConfig() {
|
||||||
|
try {
|
||||||
|
this.loading = true;
|
||||||
|
this.error = null;
|
||||||
|
const data = await configWebsiteField();
|
||||||
|
this.config = data;
|
||||||
|
localStorage.setItem('config', JSON.stringify(data));
|
||||||
|
return data;
|
||||||
|
} catch (err) {
|
||||||
|
this.error = err instanceof Error ? err : new Error('获取配置失败');
|
||||||
|
console.error('重新获取网站配置失败:', err);
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除配置数据
|
||||||
|
*/
|
||||||
|
clearConfig() {
|
||||||
|
this.config = null;
|
||||||
|
localStorage.removeItem('config');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* 增强的 API 请求工具
|
* 增强的 API 请求工具
|
||||||
*/
|
*/
|
||||||
import axios, { AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
|
import axios, { AxiosRequestConfig, AxiosError } from 'axios';
|
||||||
import { message } from 'ant-design-vue';
|
|
||||||
import { apiPerformanceMonitor } from './performance';
|
import { apiPerformanceMonitor } from './performance';
|
||||||
import { memoryCache } from './cache-manager';
|
import { memoryCache } from './cache-manager';
|
||||||
import { getToken } from './token-util';
|
import { getToken } from './token-util';
|
||||||
@@ -34,29 +33,29 @@ interface EnhancedRequestConfig extends AxiosRequestConfig {
|
|||||||
// 请求队列管理
|
// 请求队列管理
|
||||||
class RequestQueue {
|
class RequestQueue {
|
||||||
private pendingRequests = new Map<string, Promise<any>>();
|
private pendingRequests = new Map<string, Promise<any>>();
|
||||||
|
|
||||||
// 生成请求键
|
// 生成请求键
|
||||||
private generateKey(config: AxiosRequestConfig): string {
|
private generateKey(config: AxiosRequestConfig): string {
|
||||||
const { method, url, params, data } = config;
|
const { method, url, params, data } = config;
|
||||||
return `${method}_${url}_${JSON.stringify(params)}_${JSON.stringify(data)}`;
|
return `${method}_${url}_${JSON.stringify(params)}_${JSON.stringify(data)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加请求到队列
|
// 添加请求到队列
|
||||||
add<T>(config: AxiosRequestConfig, executor: () => Promise<T>): Promise<T> {
|
add<T>(config: AxiosRequestConfig, executor: () => Promise<T>): Promise<T> {
|
||||||
const key = this.generateKey(config);
|
const key = this.generateKey(config);
|
||||||
|
|
||||||
if (this.pendingRequests.has(key)) {
|
if (this.pendingRequests.has(key)) {
|
||||||
return this.pendingRequests.get(key);
|
return this.pendingRequests.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
const promise = executor().finally(() => {
|
const promise = executor().finally(() => {
|
||||||
this.pendingRequests.delete(key);
|
this.pendingRequests.delete(key);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.pendingRequests.set(key, promise);
|
this.pendingRequests.set(key, promise);
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清除队列
|
// 清除队列
|
||||||
clear(): void {
|
clear(): void {
|
||||||
this.pendingRequests.clear();
|
this.pendingRequests.clear();
|
||||||
@@ -70,13 +69,13 @@ class RetryManager {
|
|||||||
config: { times: number; delay: number; condition?: (error: any) => boolean }
|
config: { times: number; delay: number; condition?: (error: any) => boolean }
|
||||||
): Promise<T> {
|
): Promise<T> {
|
||||||
let lastError: any;
|
let lastError: any;
|
||||||
|
|
||||||
for (let i = 0; i <= config.times; i++) {
|
for (let i = 0; i <= config.times; i++) {
|
||||||
try {
|
try {
|
||||||
return await fn();
|
return await fn();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
lastError = error;
|
lastError = error;
|
||||||
|
|
||||||
// 检查是否应该重试
|
// 检查是否应该重试
|
||||||
if (i < config.times && (!config.condition || config.condition(error as AxiosError))) {
|
if (i < config.times && (!config.condition || config.condition(error as AxiosError))) {
|
||||||
await this.delay(config.delay * Math.pow(2, i)); // 指数退避
|
await this.delay(config.delay * Math.pow(2, i)); // 指数退避
|
||||||
@@ -86,10 +85,10 @@ class RetryManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw lastError;
|
throw lastError;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static delay(ms: number): Promise<void> {
|
private static delay(ms: number): Promise<void> {
|
||||||
return new Promise(resolve => setTimeout(resolve, ms));
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
}
|
}
|
||||||
@@ -101,13 +100,13 @@ export class EnhancedRequest {
|
|||||||
baseURL: API_BASE_URL,
|
baseURL: API_BASE_URL,
|
||||||
timeout: 30000
|
timeout: 30000
|
||||||
});
|
});
|
||||||
|
|
||||||
private requestQueue = new RequestQueue();
|
private requestQueue = new RequestQueue();
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.setupInterceptors();
|
this.setupInterceptors();
|
||||||
}
|
}
|
||||||
|
|
||||||
private setupInterceptors() {
|
private setupInterceptors() {
|
||||||
// 请求拦截器
|
// 请求拦截器
|
||||||
this.instance.interceptors.request.use(
|
this.instance.interceptors.request.use(
|
||||||
@@ -117,17 +116,17 @@ export class EnhancedRequest {
|
|||||||
if (token && config.headers) {
|
if (token && config.headers) {
|
||||||
config.headers[TOKEN_HEADER_NAME] = token;
|
config.headers[TOKEN_HEADER_NAME] = token;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加请求时间戳
|
// 添加请求时间戳
|
||||||
(config as any).startTime = Date.now();
|
(config as any).startTime = Date.now();
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// 响应拦截器
|
// 响应拦截器
|
||||||
this.instance.interceptors.response.use(
|
this.instance.interceptors.response.use(
|
||||||
(response) => {
|
(response) => {
|
||||||
@@ -137,7 +136,7 @@ export class EnhancedRequest {
|
|||||||
const duration = Date.now() - config.startTime;
|
const duration = Date.now() - config.startTime;
|
||||||
apiPerformanceMonitor.recordApiCall(config.url, duration);
|
apiPerformanceMonitor.recordApiCall(config.url, duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
@@ -147,12 +146,12 @@ export class EnhancedRequest {
|
|||||||
const duration = Date.now() - config.startTime;
|
const duration = Date.now() - config.startTime;
|
||||||
apiPerformanceMonitor.recordApiCall(config.url, duration);
|
apiPerformanceMonitor.recordApiCall(config.url, duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通用请求方法
|
// 通用请求方法
|
||||||
async request<T = any>(config: EnhancedRequestConfig): Promise<T> {
|
async request<T = any>(config: EnhancedRequestConfig): Promise<T> {
|
||||||
const {
|
const {
|
||||||
@@ -163,10 +162,10 @@ export class EnhancedRequest {
|
|||||||
timeoutRetry = true,
|
timeoutRetry = true,
|
||||||
...axiosConfig
|
...axiosConfig
|
||||||
} = config;
|
} = config;
|
||||||
|
|
||||||
// 生成缓存键
|
// 生成缓存键
|
||||||
const cacheKey = cache?.key || this.generateCacheKey(axiosConfig);
|
const cacheKey = cache?.key || this.generateCacheKey(axiosConfig);
|
||||||
|
|
||||||
// 尝试从缓存获取
|
// 尝试从缓存获取
|
||||||
if (cache?.enabled) {
|
if (cache?.enabled) {
|
||||||
const cachedData = memoryCache.get<T>(cacheKey);
|
const cachedData = memoryCache.get<T>(cacheKey);
|
||||||
@@ -174,11 +173,11 @@ export class EnhancedRequest {
|
|||||||
return cachedData;
|
return cachedData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 请求执行器
|
// 请求执行器
|
||||||
const executor = async (): Promise<T> => {
|
const executor = async (): Promise<T> => {
|
||||||
const response = await this.instance.request<T>(axiosConfig);
|
const response = await this.instance.request<T>(axiosConfig);
|
||||||
|
|
||||||
// 缓存响应数据
|
// 缓存响应数据
|
||||||
if (cache?.enabled && response.data) {
|
if (cache?.enabled && response.data) {
|
||||||
memoryCache.set(
|
memoryCache.set(
|
||||||
@@ -188,10 +187,10 @@ export class EnhancedRequest {
|
|||||||
cache.tags
|
cache.tags
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 请求去重
|
// 请求去重
|
||||||
if (dedupe) {
|
if (dedupe) {
|
||||||
return this.requestQueue.add(axiosConfig, async () => {
|
return this.requestQueue.add(axiosConfig, async () => {
|
||||||
@@ -202,11 +201,11 @@ export class EnhancedRequest {
|
|||||||
condition: retry.condition || this.shouldRetry
|
condition: retry.condition || this.shouldRetry
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return executor();
|
return executor();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重试机制
|
// 重试机制
|
||||||
if (retry) {
|
if (retry) {
|
||||||
return RetryManager.retry(executor, {
|
return RetryManager.retry(executor, {
|
||||||
@@ -214,10 +213,10 @@ export class EnhancedRequest {
|
|||||||
condition: retry.condition || this.shouldRetry
|
condition: retry.condition || this.shouldRetry
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return executor();
|
return executor();
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET 请求
|
// GET 请求
|
||||||
get<T = any>(url: string, config?: EnhancedRequestConfig): Promise<T> {
|
get<T = any>(url: string, config?: EnhancedRequestConfig): Promise<T> {
|
||||||
return this.request<T>({
|
return this.request<T>({
|
||||||
@@ -226,7 +225,7 @@ export class EnhancedRequest {
|
|||||||
url
|
url
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST 请求
|
// POST 请求
|
||||||
post<T = any>(url: string, data?: any, config?: EnhancedRequestConfig): Promise<T> {
|
post<T = any>(url: string, data?: any, config?: EnhancedRequestConfig): Promise<T> {
|
||||||
return this.request<T>({
|
return this.request<T>({
|
||||||
@@ -236,7 +235,7 @@ export class EnhancedRequest {
|
|||||||
data
|
data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// PUT 请求
|
// PUT 请求
|
||||||
put<T = any>(url: string, data?: any, config?: EnhancedRequestConfig): Promise<T> {
|
put<T = any>(url: string, data?: any, config?: EnhancedRequestConfig): Promise<T> {
|
||||||
return this.request<T>({
|
return this.request<T>({
|
||||||
@@ -246,7 +245,7 @@ export class EnhancedRequest {
|
|||||||
data
|
data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// DELETE 请求
|
// DELETE 请求
|
||||||
delete<T = any>(url: string, config?: EnhancedRequestConfig): Promise<T> {
|
delete<T = any>(url: string, config?: EnhancedRequestConfig): Promise<T> {
|
||||||
return this.request<T>({
|
return this.request<T>({
|
||||||
@@ -255,47 +254,47 @@ export class EnhancedRequest {
|
|||||||
url
|
url
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 批量请求
|
// 批量请求
|
||||||
async batch<T = any>(requests: EnhancedRequestConfig[]): Promise<T[]> {
|
async batch<T = any>(requests: EnhancedRequestConfig[]): Promise<T[]> {
|
||||||
const promises = requests.map(config => this.request<T>(config));
|
const promises = requests.map(config => this.request<T>(config));
|
||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 并发控制请求
|
// 并发控制请求
|
||||||
async concurrent<T = any>(
|
async concurrent<T = any>(
|
||||||
requests: EnhancedRequestConfig[],
|
requests: EnhancedRequestConfig[],
|
||||||
limit: number = 5
|
limit: number = 5
|
||||||
): Promise<T[]> {
|
): Promise<T[]> {
|
||||||
const results: T[] = [];
|
const results: T[] = [];
|
||||||
|
|
||||||
for (let i = 0; i < requests.length; i += limit) {
|
for (let i = 0; i < requests.length; i += limit) {
|
||||||
const batch = requests.slice(i, i + limit);
|
const batch = requests.slice(i, i + limit);
|
||||||
const batchResults = await this.batch<T>(batch);
|
const batchResults = await this.batch<T>(batch);
|
||||||
results.push(...batchResults);
|
results.push(...batchResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成缓存键
|
// 生成缓存键
|
||||||
private generateCacheKey(config: AxiosRequestConfig): string {
|
private generateCacheKey(config: AxiosRequestConfig): string {
|
||||||
const { method, url, params, data } = config;
|
const { method, url, params, data } = config;
|
||||||
return `api_${method}_${url}_${JSON.stringify(params)}_${JSON.stringify(data)}`;
|
return `api_${method}_${url}_${JSON.stringify(params)}_${JSON.stringify(data)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断是否应该重试
|
// 判断是否应该重试
|
||||||
private shouldRetry(error: AxiosError): boolean {
|
private shouldRetry(error: AxiosError): boolean {
|
||||||
// 网络错误或超时错误重试
|
// 网络错误或超时错误重试
|
||||||
if (!error.response) {
|
if (!error.response) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5xx 服务器错误重试
|
// 5xx 服务器错误重试
|
||||||
const status = error.response.status;
|
const status = error.response.status;
|
||||||
return status >= 500 && status < 600;
|
return status >= 500 && status < 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清除缓存
|
// 清除缓存
|
||||||
clearCache(tags?: string[]): void {
|
clearCache(tags?: string[]): void {
|
||||||
if (tags) {
|
if (tags) {
|
||||||
@@ -304,7 +303,7 @@ export class EnhancedRequest {
|
|||||||
memoryCache.clear();
|
memoryCache.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 取消所有请求
|
// 取消所有请求
|
||||||
cancelAll(): void {
|
cancelAll(): void {
|
||||||
this.requestQueue.clear();
|
this.requestQueue.clear();
|
||||||
@@ -326,7 +325,7 @@ export function cachedGet<T = any>(
|
|||||||
}
|
}
|
||||||
): Promise<T> {
|
): Promise<T> {
|
||||||
const { expiry = 5 * 60 * 1000, tags, ...restConfig } = config || {};
|
const { expiry = 5 * 60 * 1000, tags, ...restConfig } = config || {};
|
||||||
|
|
||||||
return enhancedRequest.get<T>(url, {
|
return enhancedRequest.get<T>(url, {
|
||||||
...restConfig,
|
...restConfig,
|
||||||
cache: {
|
cache: {
|
||||||
|
|||||||
@@ -13,8 +13,26 @@ import type { ApiResult } from '@/api';
|
|||||||
import { getHostname, getTenantId } from '@/utils/domain';
|
import { getHostname, getTenantId } from '@/utils/domain';
|
||||||
import { getMerchantId } from "@/utils/merchant";
|
import { getMerchantId } from "@/utils/merchant";
|
||||||
|
|
||||||
|
// 获取API基础地址的函数
|
||||||
|
const getBaseUrl = (): string => {
|
||||||
|
// 尝试从配置store获取后台配置的API地址
|
||||||
|
try {
|
||||||
|
// 如果store中没有,则尝试从localStorage获取
|
||||||
|
const ApiUrl = localStorage.getItem('ApiUrl');
|
||||||
|
if (ApiUrl) {
|
||||||
|
return ApiUrl;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('获取后台配置API地址失败:', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果后台没有配置API地址,则使用本地配置
|
||||||
|
console.log('使用本地配置的API地址:', API_BASE_URL);
|
||||||
|
return API_BASE_URL;
|
||||||
|
};
|
||||||
|
|
||||||
const service = axios.create({
|
const service = axios.create({
|
||||||
baseURL: API_BASE_URL
|
baseURL: getBaseUrl()
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -284,7 +284,6 @@ import {Config} from '@/api/cms/cmsWebsiteField/model';
|
|||||||
import {phoneReg} from 'ele-admin-pro';
|
import {phoneReg} from 'ele-admin-pro';
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
import {listAdminsByPhoneAll} from "@/api/system/user";
|
import {listAdminsByPhoneAll} from "@/api/system/user";
|
||||||
import {getUserInfo} from "@/api/layout";
|
|
||||||
import {QrCodeStatusResponse} from "@/api/passport/qrLogin";
|
import {QrCodeStatusResponse} from "@/api/passport/qrLogin";
|
||||||
|
|
||||||
const useForm = Form.useForm;
|
const useForm = Form.useForm;
|
||||||
|
|||||||
Reference in New Issue
Block a user