'frontendadd'
This commit is contained in:
60
frontend/src/utils/agent.ts
Normal file
60
frontend/src/utils/agent.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { reactive } from "vue";
|
||||
interface ViolationBOType {
|
||||
[key: string]: string;
|
||||
}
|
||||
const Agent: ViolationBOType = reactive({
|
||||
// 1
|
||||
Converter_Group_Admin: "Converter: Converter_Group_Admin",
|
||||
scheme_converter: "Converter: scheme_converter",
|
||||
converter_critic: "Converter: converter_critic",
|
||||
mergrid_ploter: "Converter: mergrid_ploter",
|
||||
scheme_code_writer: "Converter: scheme_code_writer",
|
||||
scheme_code_critic: "Converter: scheme_code_critic",
|
||||
// 2
|
||||
|
||||
expriment_code_writer: "Executor: expriment_code_writer",
|
||||
data_collector: "Executor: data_collector",
|
||||
collector_code_writer: "Executor: collector_code_writer",
|
||||
Inner_Executor_Admin: "Executor: Inner_Executor_Admin",
|
||||
// Inner_Executor_Admin: "Executor: Executor_Group_Admin",
|
||||
// 3
|
||||
Generate_Group_Admin: "Generate: Generate_Group_Admin",
|
||||
structure_scientist: "Generate: structure_scientist",
|
||||
property_scientist: "Generate: property_scientist",
|
||||
application_scientist: "Generate: application_scientist",
|
||||
synthesis_scientist: "Generate: synthesis_scientist",
|
||||
scheme_critic: "Generate: scheme_critic",
|
||||
|
||||
// 4
|
||||
analysis_executor: "Optimize: analysis_executor",
|
||||
analysis_pl_uv: "Optimize: analysis_pl_uv",
|
||||
analysis_picturer: "Optimize: analysis_picturer",
|
||||
Experiment_Optimizer: "Optimize: Experiment_Optimizer",
|
||||
optimizer_critic: "Optimize: optimizer_critic",
|
||||
Analysis_Group_Admin: "Optimize: Analysis_Group_Admin",
|
||||
|
||||
//
|
||||
Outer_Retrieval_Admin: "Retrieval: Outer_Retrieval_Admin",
|
||||
Outer_Converter_Admin: "Converter: Outer_Converter_Admin",
|
||||
Outer_Executor_Admin: "Executor: Outer_Executor_Admin",
|
||||
experiment_executor: "Executor: experiment_executor",
|
||||
Outer_Generate_Admin: "Generate: Outer_Generate_Admin",
|
||||
Outer_Analysis_Admin: "Optimize: Outer_Analysis_Admin",
|
||||
vector_code_executor: "Retrieval: vector_code_executor",
|
||||
graphrag_code_executor: "Retrieval: graphrag_code_executor",
|
||||
web_code_executor: "Retrieval: web_code_executor",
|
||||
web_summary: "Retrieval: web_summary",
|
||||
|
||||
// 5
|
||||
Inner_Retrieval_Admin: "Retrieval: Inner_Retrieval_Admin",
|
||||
// Inner_Retrieval_Admin: "Retrieval: Retrieval_Group_Admin",
|
||||
vector_searcher: "Retrieval: vector_searcher",
|
||||
graphrag_searcher: "Retrieval: graphrag_searcher",
|
||||
web_searcher: "Retrieval: web_searcher",
|
||||
Planer: "Planner",
|
||||
Planner: "Planner",
|
||||
})
|
||||
export function getAgent(data: any) {
|
||||
let rData = Object.keys(Agent).filter(k => k.toLowerCase() === data.toLowerCase())[0]
|
||||
return Agent[rData] || ''
|
||||
}
|
||||
10
frontend/src/utils/i18n.ts
Normal file
10
frontend/src/utils/i18n.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import i18n from "../lang/index"
|
||||
export const generateTitle=(title:string)=>{
|
||||
//i18n.global.te('routers.' + title) 只能在ts文件中用
|
||||
const hasKey = i18n.global.te('routers.' + title)
|
||||
if (hasKey) {
|
||||
const translatedTitle = i18n.global.t('routers.' + title)
|
||||
return translatedTitle
|
||||
}
|
||||
return title
|
||||
}
|
||||
324
frontend/src/utils/request/Axios.ts
Normal file
324
frontend/src/utils/request/Axios.ts
Normal file
@@ -0,0 +1,324 @@
|
||||
import axios, {
|
||||
AxiosError,
|
||||
AxiosInstance,
|
||||
AxiosRequestConfig,
|
||||
AxiosRequestHeaders,
|
||||
AxiosResponse,
|
||||
InternalAxiosRequestConfig
|
||||
} from 'axios'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
import debounce from 'lodash/debounce'
|
||||
import isFunction from 'lodash/isFunction'
|
||||
import throttle from 'lodash/throttle'
|
||||
import { stringify } from 'qs'
|
||||
|
||||
import { ContentTypeEnum } from '../../constants'
|
||||
import { AxiosRequestConfigRetry, RequestOptions, Result } from '../../types/axios'
|
||||
|
||||
import { AxiosCanceler } from './AxiosCancel'
|
||||
import { CreateAxiosOptions } from './AxiosTransform'
|
||||
|
||||
// const store = useSettingStore();
|
||||
// let tokenUpdateing = false;
|
||||
// // 创建一个 axios 实例
|
||||
// const service = axios.create({
|
||||
// timeout: 5000,
|
||||
// });
|
||||
// const reqLists = ref<any>([]);
|
||||
/**
|
||||
* Axios 模块
|
||||
*/
|
||||
export class VAxios {
|
||||
/**
|
||||
* Axios实例句柄
|
||||
* @private
|
||||
*/
|
||||
private instance: AxiosInstance
|
||||
|
||||
/**
|
||||
* Axios配置
|
||||
* @private
|
||||
*/
|
||||
private readonly options: CreateAxiosOptions
|
||||
|
||||
constructor(options: CreateAxiosOptions) {
|
||||
this.options = options
|
||||
this.instance = axios.create(options)
|
||||
this.setupInterceptors()
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建Axios实例
|
||||
* @param config
|
||||
* @private
|
||||
*/
|
||||
private createAxios(config: CreateAxiosOptions): void {
|
||||
this.instance = axios.create(config)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据处理类
|
||||
* @private
|
||||
*/
|
||||
private getTransform() {
|
||||
const { transform } = this.options
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Axios实例
|
||||
*/
|
||||
getAxios(): AxiosInstance {
|
||||
return this.instance
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置Axios
|
||||
* @param config
|
||||
*/
|
||||
configAxios(config: CreateAxiosOptions) {
|
||||
if (!this.instance) return
|
||||
this.createAxios(config)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置公共头部信息
|
||||
* @param headers
|
||||
*/
|
||||
setHeader(headers: Record<string, string>): void {
|
||||
if (!this.instance) return
|
||||
Object.assign(this.instance.defaults.headers, headers)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置拦截器
|
||||
* @private
|
||||
*/
|
||||
private setupInterceptors() {
|
||||
const transform = this.getTransform()
|
||||
if (!transform) return
|
||||
|
||||
const {
|
||||
requestInterceptors,
|
||||
requestInterceptorsCatch,
|
||||
responseInterceptors,
|
||||
responseInterceptorsCatch
|
||||
} = transform
|
||||
const axiosCanceler = new AxiosCanceler()
|
||||
this.instance.defaults.withCredentials = false // 解决内网多api跨越问题
|
||||
// 请求拦截器
|
||||
this.instance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
|
||||
// 如果忽略取消令牌,则不会取消重复的请求
|
||||
// @ts-ignore
|
||||
const { ignoreCancelToken } = config.requestOptions
|
||||
const ignoreCancel = ignoreCancelToken ?? this.options.requestOptions?.ignoreCancelToken
|
||||
if (!ignoreCancel) axiosCanceler.addPending(config)
|
||||
|
||||
if (requestInterceptors && isFunction(requestInterceptors)) {
|
||||
config = requestInterceptors(config, this.options) as InternalAxiosRequestConfig
|
||||
}
|
||||
|
||||
return config
|
||||
}, undefined)
|
||||
|
||||
// 请求错误处理
|
||||
if (requestInterceptorsCatch && isFunction(requestInterceptorsCatch)) {
|
||||
this.instance.interceptors.request.use(undefined, requestInterceptorsCatch)
|
||||
}
|
||||
|
||||
// 响应结果处理
|
||||
this.instance.interceptors.response.use(async (res: AxiosResponse) => {
|
||||
if (res) axiosCanceler.removePending(res.config)
|
||||
if (
|
||||
responseInterceptors &&
|
||||
isFunction(responseInterceptors) &&
|
||||
responseInterceptors(res).data.code
|
||||
) {
|
||||
res = responseInterceptors(res)
|
||||
}
|
||||
return res
|
||||
}, undefined)
|
||||
|
||||
// 响应错误处理
|
||||
if (responseInterceptorsCatch && isFunction(responseInterceptorsCatch)) {
|
||||
this.instance.interceptors.response.use(undefined, (error) =>
|
||||
responseInterceptorsCatch(error, this.instance)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 支持 FormData 请求格式
|
||||
* @param config
|
||||
*/
|
||||
supportFormData(config: AxiosRequestConfig) {
|
||||
const headers = config.headers || (this.options.headers as AxiosRequestHeaders)
|
||||
const contentType = headers?.['Content-Type'] || headers?.['content-type']
|
||||
|
||||
if (
|
||||
contentType !== ContentTypeEnum.FormURLEncoded ||
|
||||
!Reflect.has(config, 'data') ||
|
||||
config.method?.toUpperCase() === 'GET'
|
||||
) {
|
||||
return config
|
||||
}
|
||||
|
||||
return {
|
||||
...config,
|
||||
data: stringify(config.data, { arrayFormat: 'brackets' })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 支持 params 序列化
|
||||
* @param config
|
||||
*/
|
||||
supportParamsStringify(config: AxiosRequestConfig) {
|
||||
const headers = config.headers || this.options.headers
|
||||
const contentType = headers?.['Content-Type'] || headers?.['content-type']
|
||||
|
||||
if (contentType === ContentTypeEnum.FormURLEncoded || !Reflect.has(config, 'params')) {
|
||||
return config
|
||||
}
|
||||
|
||||
return {
|
||||
...config,
|
||||
paramsSerializer: (params: any) => stringify(params, { arrayFormat: 'brackets' })
|
||||
}
|
||||
}
|
||||
|
||||
get<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
|
||||
return this.request({ ...config, method: 'GET' }, options)
|
||||
}
|
||||
|
||||
post<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
|
||||
return this.request({ ...config, method: 'POST' }, options)
|
||||
}
|
||||
|
||||
put<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
|
||||
return this.request({ ...config, method: 'PUT' }, options)
|
||||
}
|
||||
|
||||
delete<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
|
||||
return this.request({ ...config, method: 'DELETE' }, options)
|
||||
}
|
||||
|
||||
patch<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
|
||||
return this.request({ ...config, method: 'PATCH' }, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件封装
|
||||
* @param key 文件所属的key
|
||||
* @param file 文件
|
||||
* @param config 请求配置
|
||||
* @param options
|
||||
*/
|
||||
upload<T = any>(
|
||||
key: string,
|
||||
file: File,
|
||||
config: AxiosRequestConfig,
|
||||
options?: RequestOptions
|
||||
): Promise<T> {
|
||||
const params: FormData = config.params ?? new FormData()
|
||||
params.append(key, file)
|
||||
|
||||
return this.request(
|
||||
{
|
||||
...config,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': ContentTypeEnum.FormData
|
||||
},
|
||||
params
|
||||
},
|
||||
options
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求封装
|
||||
* @param config
|
||||
* @param options
|
||||
*/
|
||||
request<T = any>(config: AxiosRequestConfigRetry, options?: RequestOptions): Promise<T> {
|
||||
const { requestOptions }: any = this.options
|
||||
|
||||
if (requestOptions.throttle !== undefined && requestOptions.debounce !== undefined) {
|
||||
throw new Error('throttle and debounce cannot be set at the same time')
|
||||
}
|
||||
|
||||
if (requestOptions.throttle && requestOptions.throttle.delay !== 0) {
|
||||
return new Promise((resolve) => {
|
||||
throttle(
|
||||
() => resolve(this.synthesisRequest(config, options)),
|
||||
requestOptions.throttle.delay
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
if (requestOptions.debounce && requestOptions.debounce.delay !== 0) {
|
||||
return new Promise((resolve) => {
|
||||
debounce(
|
||||
() => resolve(this.synthesisRequest(config, options)),
|
||||
requestOptions.debounce.delay
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
return this.synthesisRequest(config, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求方法
|
||||
* @private
|
||||
*/
|
||||
private async synthesisRequest<T = any>(
|
||||
config: AxiosRequestConfigRetry,
|
||||
options?: RequestOptions
|
||||
): Promise<T> {
|
||||
let conf: CreateAxiosOptions = cloneDeep(config)
|
||||
const transform = this.getTransform()
|
||||
|
||||
const { requestOptions } = this.options
|
||||
|
||||
const opt: RequestOptions = { ...requestOptions, ...options }
|
||||
|
||||
const { beforeRequestHook, requestCatchHook, transformRequestHook } = transform || {}
|
||||
if (beforeRequestHook && isFunction(beforeRequestHook)) {
|
||||
conf = beforeRequestHook(conf, opt)
|
||||
}
|
||||
conf.requestOptions = opt
|
||||
|
||||
conf = this.supportFormData(conf)
|
||||
// 支持params数组参数格式化,因axios默认的toFormData即为brackets方式,无需配置paramsSerializer为qs,有需要可解除注释,参数参考qs文档
|
||||
// conf = this.supportParamsStringify(conf);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this.instance
|
||||
.request<any, AxiosResponse<Result>>(!config.retryCount ? conf : config)
|
||||
.then((res: AxiosResponse<Result>) => {
|
||||
if (transformRequestHook && isFunction(transformRequestHook)) {
|
||||
try {
|
||||
const ret = transformRequestHook(res, opt)
|
||||
resolve(ret)
|
||||
} catch (err) {
|
||||
reject(err || new Error('请求错误!'))
|
||||
}
|
||||
return
|
||||
}
|
||||
resolve(res as unknown as Promise<T>)
|
||||
})
|
||||
.catch((e: Error | AxiosError) => {
|
||||
if (requestCatchHook && isFunction(requestCatchHook)) {
|
||||
reject(requestCatchHook(e, opt))
|
||||
return
|
||||
}
|
||||
if (axios.isAxiosError(e)) {
|
||||
// 在这里重写Axios的错误信息
|
||||
}
|
||||
reject(e)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
67
frontend/src/utils/request/AxiosCancel.ts
Normal file
67
frontend/src/utils/request/AxiosCancel.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import type { AxiosRequestConfig, Canceler } from 'axios';
|
||||
import axios from 'axios';
|
||||
import isFunction from 'lodash/isFunction';
|
||||
|
||||
// 存储请求与取消令牌的键值对列表
|
||||
let pendingMap = new Map<string, Canceler>();
|
||||
|
||||
/**
|
||||
* 获取请求Url
|
||||
* @param config
|
||||
*/
|
||||
export const getPendingUrl = (config: AxiosRequestConfig) => [config.method, config.url].join('&');
|
||||
|
||||
/**
|
||||
* @description 请求管理器
|
||||
*/
|
||||
export class AxiosCanceler {
|
||||
/**
|
||||
* 添加请求到列表中
|
||||
* @param config
|
||||
*/
|
||||
addPending(config: AxiosRequestConfig) {
|
||||
this.removePending(config);
|
||||
const url = getPendingUrl(config);
|
||||
config.cancelToken =
|
||||
config.cancelToken ||
|
||||
new axios.CancelToken((cancel) => {
|
||||
if (!pendingMap.has(url)) {
|
||||
// 如果当前没有相同请求就添加
|
||||
pendingMap.set(url, cancel);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除现有的所有请求
|
||||
*/
|
||||
removeAllPending() {
|
||||
pendingMap.forEach((cancel) => {
|
||||
if (cancel && isFunction(cancel)) cancel();
|
||||
});
|
||||
pendingMap.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除指定请求
|
||||
* @param config
|
||||
*/
|
||||
removePending(config: AxiosRequestConfig) {
|
||||
const url = getPendingUrl(config);
|
||||
|
||||
if (pendingMap.has(url)) {
|
||||
// If there is a current request identifier in pending,
|
||||
// the current request needs to be cancelled and removed
|
||||
const cancel = pendingMap.get(url);
|
||||
if (cancel) cancel(url);
|
||||
pendingMap.delete(url);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置
|
||||
*/
|
||||
reset() {
|
||||
pendingMap = new Map<string, Canceler>();
|
||||
}
|
||||
}
|
||||
67
frontend/src/utils/request/AxiosTransform.ts
Normal file
67
frontend/src/utils/request/AxiosTransform.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
|
||||
import { AxiosError } from 'axios'
|
||||
|
||||
import type { RequestOptions, Result } from '../../types/axios'
|
||||
|
||||
/**
|
||||
* @description 创建Axios实例配置
|
||||
*/
|
||||
export interface CreateAxiosOptions extends AxiosRequestConfig {
|
||||
/**
|
||||
* 请求验证方案
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes
|
||||
*/
|
||||
authenticationScheme?: string
|
||||
/**
|
||||
* 请求数据处理
|
||||
*/
|
||||
transform?: AxiosTransform
|
||||
/**
|
||||
* 请求配置
|
||||
*/
|
||||
requestOptions?: RequestOptions
|
||||
}
|
||||
|
||||
/**
|
||||
* Axios请求数据处理 抽象类
|
||||
*/
|
||||
export abstract class AxiosTransform {
|
||||
/**
|
||||
* 请求前钩子
|
||||
*/
|
||||
beforeRequestHook?: (config: AxiosRequestConfig, options: RequestOptions) => AxiosRequestConfig
|
||||
|
||||
/**
|
||||
* 数据处理前钩子
|
||||
*/
|
||||
transformRequestHook?: <T = any>(res: AxiosResponse<Result>, options: RequestOptions) => T
|
||||
|
||||
/**
|
||||
* 请求失败钩子
|
||||
*/
|
||||
requestCatchHook?: <T = any>(e: Error | AxiosError, options: RequestOptions) => Promise<T>
|
||||
|
||||
/**
|
||||
* 请求拦截器
|
||||
*/
|
||||
requestInterceptors?: (
|
||||
config: AxiosRequestConfig,
|
||||
options: CreateAxiosOptions
|
||||
) => AxiosRequestConfig
|
||||
|
||||
/**
|
||||
* 响应拦截器
|
||||
*/
|
||||
responseInterceptors?: (res: AxiosResponse) => AxiosResponse
|
||||
|
||||
/**
|
||||
* 请求拦截器错误处理
|
||||
*/
|
||||
requestInterceptorsCatch?: (error: AxiosError) => void
|
||||
|
||||
/**
|
||||
* 响应拦截器错误处理
|
||||
*/
|
||||
responseInterceptorsCatch?: (error: AxiosError, instance: AxiosInstance) => void
|
||||
}
|
||||
222
frontend/src/utils/request/index.ts
Normal file
222
frontend/src/utils/request/index.ts
Normal file
@@ -0,0 +1,222 @@
|
||||
// axios配置 可自行根据项目进行更改,只需更改该文件即可,其他文件可以不动
|
||||
// import type { AxiosInstance } from 'axios'
|
||||
import isString from 'lodash/isString'
|
||||
import merge from 'lodash/merge'
|
||||
|
||||
// import { useRouter } from 'vue-router';
|
||||
// import { UserRefresh } from '@api/userCenter';
|
||||
// import { useUserStore } from '../../store'
|
||||
|
||||
import { VAxios } from './Axios'
|
||||
import type { AxiosTransform, CreateAxiosOptions } from './AxiosTransform'
|
||||
import { formatRequestDate, joinTimestamp, setObjToUrlParams } from './utils'
|
||||
|
||||
// 通用请求头
|
||||
export enum ContentTypeEnum {
|
||||
Json = 'application/json;charset=UTF-8',
|
||||
FormURLEncoded = 'application/x-www-form-urlencoded;charset=UTF-8',
|
||||
FormData = 'multipart/form-data;charset=UTF-8'
|
||||
}
|
||||
|
||||
const env = import.meta.env.MODE || 'development'
|
||||
|
||||
// 如果是mock模式 或 没启用直连代理 就不配置host 会走本地Mock拦截 或 Vite 代理
|
||||
const host =
|
||||
env === 'mock' || import.meta.env.VITE_IS_REQUEST_PROXY === 'true'
|
||||
? ''
|
||||
: import.meta.env.VITE_API_URL
|
||||
// 数据处理,方便区分多种处理方式
|
||||
const transform: AxiosTransform = {
|
||||
// 处理请求数据。如果数据不是预期格式,可直接抛出错误
|
||||
transformRequestHook: (res, options) => {
|
||||
const { isTransformResponse, isReturnNativeResponse } = options
|
||||
|
||||
// 如果204无内容直接返回
|
||||
const method:any = res.config.method?.toLowerCase()
|
||||
if (res.status === 204 && ['put', 'patch', 'delete'].includes(method)) {
|
||||
return res
|
||||
}
|
||||
|
||||
// 是否返回原生响应头 比如:需要获取响应头时使用该属性
|
||||
if (isReturnNativeResponse) {
|
||||
return res
|
||||
}
|
||||
// 不进行任何处理,直接返回
|
||||
// 用于页面代码可能需要直接获取code,data,message这些信息时开启
|
||||
if (!isTransformResponse) {
|
||||
return res.data
|
||||
}
|
||||
|
||||
// 错误的时候返回
|
||||
const { data } = res
|
||||
if (!data) {
|
||||
throw new Error('请求接口错误')
|
||||
}
|
||||
|
||||
// 这里 code为 后台统一的字段,需要在 types.ts内修改为项目自己的接口返回格式
|
||||
const { code } = data
|
||||
// 这里逻辑可以根据项目进行修改
|
||||
const hasSuccess = data && code === 200
|
||||
if (hasSuccess) {
|
||||
return data.data
|
||||
}
|
||||
|
||||
throw new Error(`请求接口错误, 错误码: ${code}`)
|
||||
},
|
||||
|
||||
// 请求前处理配置
|
||||
beforeRequestHook: (config, options) => {
|
||||
const {
|
||||
apiUrl,
|
||||
isJoinPrefix,
|
||||
urlPrefix,
|
||||
joinParamsToUrl,
|
||||
formatDate,
|
||||
joinTime = true
|
||||
} = options
|
||||
// 添加接口前缀
|
||||
if (isJoinPrefix && urlPrefix && isString(urlPrefix)) {
|
||||
let u = urlPrefix
|
||||
config.url = `${u}${config.url}`
|
||||
}
|
||||
// 将baseUrl拼接
|
||||
if (apiUrl && isString(apiUrl)) {
|
||||
config.url = `${apiUrl}${config.url}`
|
||||
}
|
||||
const params = config.params || {}
|
||||
const data = config.data || false
|
||||
|
||||
if (formatDate && data && !isString(data)) {
|
||||
formatRequestDate(data)
|
||||
}
|
||||
if (config.method?.toUpperCase() === 'GET') {
|
||||
if (!isString(params)) {
|
||||
// 给 get 请求加上时间戳参数,避免从缓存中拿数据。
|
||||
config.params = Object.assign(params || {}, joinTimestamp(joinTime, false))
|
||||
} else {
|
||||
// 兼容restful风格
|
||||
config.url = `${config.url + params}${joinTimestamp(joinTime, true)}`
|
||||
config.params = undefined
|
||||
}
|
||||
} else if (!isString(params)) {
|
||||
if (formatDate) {
|
||||
formatRequestDate(params)
|
||||
}
|
||||
if (
|
||||
Reflect.has(config, 'data') &&
|
||||
config.data &&
|
||||
(Object.keys(config.data).length > 0 || data instanceof FormData)
|
||||
) {
|
||||
config.data = data
|
||||
config.params = params
|
||||
} else {
|
||||
// 非GET请求如果没有提供data,则将params视为data
|
||||
config.data = params
|
||||
config.params = undefined
|
||||
}
|
||||
if (joinParamsToUrl) {
|
||||
config.url = setObjToUrlParams(config.url as string, { ...config.params, ...config.data })
|
||||
}
|
||||
} else {
|
||||
// 兼容restful风格
|
||||
config.url += params
|
||||
config.params = undefined
|
||||
}
|
||||
return config
|
||||
},
|
||||
|
||||
// 请求拦截器处理
|
||||
requestInterceptors: (config) => {
|
||||
// 请求之前处理config
|
||||
// const userStore = useUserStore()
|
||||
// const { token } = userStore
|
||||
const token = localStorage.getItem('token')
|
||||
if (token && (config as Recordable)?.requestOptions?.withToken !== false) {
|
||||
;(config as Recordable).headers['x-rtt-login-token'] = token
|
||||
}
|
||||
return config
|
||||
},
|
||||
|
||||
// 响应拦截器处理
|
||||
responseInterceptors: (res) => {
|
||||
return res
|
||||
},
|
||||
|
||||
// 响应错误处理
|
||||
responseInterceptorsCatch: (error: any, instance: any) => {
|
||||
const { config } = error
|
||||
|
||||
if (!config || !config.requestOptions.retry) return Promise.reject(error)
|
||||
|
||||
config.retryCount = config.retryCount || 0
|
||||
|
||||
if (config.retryCount >= config.requestOptions.retry.count) return Promise.reject(error)
|
||||
|
||||
config.retryCount += 1
|
||||
|
||||
const backoff = new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(config)
|
||||
}, config.requestOptions.retry.delay || 1)
|
||||
})
|
||||
config.headers = { ...config.headers, 'Content-Type': ContentTypeEnum.Json }
|
||||
return backoff.then((config) => instance.request(config))
|
||||
}
|
||||
}
|
||||
|
||||
function createAxios(opt?: Partial<CreateAxiosOptions>) {
|
||||
return new VAxios(
|
||||
merge(
|
||||
<CreateAxiosOptions>{
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes
|
||||
// 例如: authenticationScheme: 'Bearer'
|
||||
authenticationScheme: '',
|
||||
// 超时
|
||||
timeout: 10 * 1000,
|
||||
// 携带Cookie
|
||||
withCredentials: true,
|
||||
// 头信息
|
||||
headers: {
|
||||
'Content-Type': ContentTypeEnum.Json,
|
||||
},
|
||||
// 数据处理方式
|
||||
transform,
|
||||
// 配置项,下面的选项都可以在独立的接口请求中覆盖
|
||||
requestOptions: {
|
||||
// 接口地址
|
||||
apiUrl: host,
|
||||
// 是否自动添加接口前缀
|
||||
isJoinPrefix: true,
|
||||
// 接口前缀
|
||||
// 例如: https://www.baidu.com/api
|
||||
// urlPrefix: '/api'
|
||||
urlPrefix: import.meta.env.VITE_API_URL_PREFIX,
|
||||
// 是否返回原生响应头 比如:需要获取响应头时使用该属性
|
||||
isReturnNativeResponse: false,
|
||||
// 需要对返回数据进行处理
|
||||
isTransformResponse: false,
|
||||
// post请求的时候添加参数到url
|
||||
joinParamsToUrl: false,
|
||||
// 格式化提交参数时间
|
||||
formatDate: true,
|
||||
// 是否加入时间戳
|
||||
joinTime: true,
|
||||
// 是否忽略请求取消令牌
|
||||
// 如果启用,则重复请求时不进行处理
|
||||
// 如果禁用,则重复请求时会取消当前请求
|
||||
ignoreCancelToken: true,
|
||||
// 是否携带token
|
||||
withToken: true,
|
||||
externalUrlStatus: 0,
|
||||
// 重试
|
||||
retry: {
|
||||
count: 3,
|
||||
delay: 1000
|
||||
}
|
||||
}
|
||||
},
|
||||
opt || {}
|
||||
)
|
||||
)
|
||||
}
|
||||
export const request = createAxios()
|
||||
57
frontend/src/utils/request/utils.ts
Normal file
57
frontend/src/utils/request/utils.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import isObject from 'lodash/isObject'
|
||||
import isString from 'lodash/isString'
|
||||
|
||||
const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss'
|
||||
|
||||
export function joinTimestamp<T extends boolean>(
|
||||
join: boolean,
|
||||
restful: T
|
||||
): T extends true ? string : object
|
||||
|
||||
export function joinTimestamp(join: boolean, restful = false): string | object {
|
||||
if (!join) {
|
||||
return restful ? '' : {}
|
||||
}
|
||||
const now = new Date().getTime()
|
||||
if (restful) {
|
||||
return `?_t=${now}`
|
||||
}
|
||||
return { _t: now }
|
||||
}
|
||||
|
||||
// 格式化提交参数时间
|
||||
export function formatRequestDate(params: Recordable) {
|
||||
if (Object.prototype.toString.call(params) !== '[object Object]') {
|
||||
return
|
||||
}
|
||||
|
||||
for (const key in params) {
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
if (params[key] && params[key]._isAMomentObject) {
|
||||
params[key] = params[key].format(DATE_TIME_FORMAT)
|
||||
}
|
||||
if (isString(key)) {
|
||||
const value = params[key]
|
||||
if (value) {
|
||||
try {
|
||||
params[key] = isString(value) ? value.trim() : value
|
||||
} catch (error: any) {
|
||||
throw new Error(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isObject(params[key])) {
|
||||
formatRequestDate(params[key])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 将对象转为Url参数
|
||||
export function setObjToUrlParams(baseUrl: string, obj: { [index: string]: any }): string {
|
||||
let parameters = ''
|
||||
for (const key in obj) {
|
||||
parameters += `${key}=${encodeURIComponent(obj[key])}&`
|
||||
}
|
||||
parameters = parameters.replace(/&$/, '')
|
||||
return /\?$/.test(baseUrl) ? baseUrl + parameters : baseUrl.replace(/\/?$/, '?') + parameters
|
||||
}
|
||||
25
frontend/src/utils/websocket.ts
Normal file
25
frontend/src/utils/websocket.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
function useWebsocket(handleMessage: any) {
|
||||
const ws = new WebSocket(import.meta.env.VITE_WB_BASE_URL)
|
||||
const init = () => {
|
||||
bindEvent();
|
||||
}
|
||||
const bindEvent = () => {
|
||||
ws.addEventListener('open',handleOpen,false)
|
||||
ws.addEventListener('close',handleClose,false)
|
||||
ws.addEventListener('error',handleError,false)
|
||||
ws.addEventListener('message',handleMessage,false)
|
||||
}
|
||||
const handleOpen = (e: any) => {
|
||||
console.log('websocket open',e);
|
||||
}
|
||||
const handleClose = (e: any) => {
|
||||
console.log('websocket close',e);
|
||||
}
|
||||
const handleError = (e: any) => {
|
||||
console.log('webscoket error',e)
|
||||
}
|
||||
init();
|
||||
return ws
|
||||
}
|
||||
|
||||
export default useWebsocket
|
||||
Reference in New Issue
Block a user