Commit caaa83061ac8aecac288580ea76bc8270b14b920
Committed by
xp.Huang
1 parent
c2ad5966
feat(src/packages): 大屏自定义请求新增第三方接口动态获取Token功能
Showing
16 changed files
with
666 additions
and
303 deletions
1 | -import type { AxiosResponse } from 'axios'; | |
2 | -import type { RequestOptions, Result } from '/#/external/axios'; | |
3 | -import type { AxiosTransform, CreateAxiosOptions } from '@/utils/external/http/axios/axiosTransform'; | |
4 | -import { useGlobSetting } from '@/hooks/external/setting'; | |
5 | -import { RequestEnum, ContentTypeEnum } from '@/enums/external/httpEnum'; | |
6 | -import { isString } from '@/utils/external/is'; | |
7 | -import { getJwtToken, getShareJwtToken } from '@/utils/external/auth'; | |
8 | -import { setObjToUrlParams, deepMerge } from '@/utils/external'; | |
9 | -import { formatRequestDate, joinTimestamp } from '@/utils/external/http/axios/helper'; | |
10 | -import { VAxios } from '@/utils/external/http/axios/Axios'; | |
11 | -import { checkStatus } from './checkStatus'; | |
1 | +import type { AxiosResponse } from 'axios' | |
2 | +import type { RequestOptions, Result } from '/#/external/axios' | |
3 | +import type { AxiosTransform, CreateAxiosOptions } from '@/utils/external/http/axios/axiosTransform' | |
4 | +import { useGlobSetting } from '@/hooks/external/setting' | |
5 | +import { RequestEnum, ContentTypeEnum } from '@/enums/external/httpEnum' | |
6 | +import { isString } from '@/utils/external/is' | |
7 | +import { getJwtToken, getShareJwtToken } from '@/utils/external/auth' | |
8 | +import { setObjToUrlParams, deepMerge } from '@/utils/external' | |
9 | +import { formatRequestDate, joinTimestamp } from '@/utils/external/http/axios/helper' | |
10 | +import { VAxios } from '@/utils/external/http/axios/Axios' | |
11 | +import { checkStatus } from './checkStatus' | |
12 | 12 | |
13 | -const globSetting = useGlobSetting(); | |
14 | -const urlPrefix = globSetting.urlPrefix; | |
13 | +const globSetting = useGlobSetting() | |
14 | +const urlPrefix = globSetting.urlPrefix | |
15 | 15 | |
16 | 16 | /** |
17 | 17 | * @description: 数据处理,方便区分多种处理方式 |
... | ... | @@ -21,62 +21,59 @@ const transform: AxiosTransform = { |
21 | 21 | * @description: 处理请求数据。如果数据不是预期格式,可直接抛出错误 |
22 | 22 | */ |
23 | 23 | transformRequestHook: (res: AxiosResponse<Result>, options: RequestOptions) => { |
24 | - const { isReturnNativeResponse } = options; | |
24 | + const { isReturnNativeResponse } = options | |
25 | 25 | // 是否返回原生响应头 比如:需要获取响应头时使用该属性 |
26 | 26 | if (isReturnNativeResponse) { |
27 | - return res; | |
27 | + return res | |
28 | 28 | } |
29 | - return res.data; | |
29 | + return res.data | |
30 | 30 | }, |
31 | 31 | |
32 | 32 | // 请求之前处理config |
33 | 33 | beforeRequestHook: (config, options) => { |
34 | - const { apiUrl, joinPrefix, joinParamsToUrl, formatDate, joinTime = true } = options; | |
34 | + const { apiUrl, joinPrefix, joinParamsToUrl, formatDate, joinTime = true } = options | |
35 | 35 | |
36 | 36 | if (joinPrefix) { |
37 | - config.url = `${urlPrefix}${config.url}`; | |
37 | + config.url = `${urlPrefix}${config.url}` | |
38 | 38 | } |
39 | 39 | |
40 | 40 | if (apiUrl && isString(apiUrl)) { |
41 | - config.url = `${apiUrl}${config.url}`; | |
41 | + config.url = `${apiUrl}${config.url}` | |
42 | 42 | } |
43 | 43 | |
44 | - const params = config.params || {}; | |
45 | - const data = config.data || false; | |
46 | - formatDate && data && !isString(data) && formatRequestDate(data); | |
44 | + const params = config.params || {} | |
45 | + const data = config.data || false | |
46 | + formatDate && data && !isString(data) && formatRequestDate(data) | |
47 | 47 | if (config.method?.toUpperCase() === RequestEnum.GET) { |
48 | 48 | if (!isString(params)) { |
49 | 49 | // 给 get 请求加上时间戳参数,避免从缓存中拿数据。 |
50 | - config.params = Object.assign(params || {}, joinTimestamp(joinTime, false)); | |
50 | + config.params = Object.assign(params || {}, joinTimestamp(joinTime, false)) | |
51 | 51 | } else { |
52 | 52 | // 兼容restful风格 |
53 | - config.url = config.url + params + `${joinTimestamp(joinTime, true)}`; | |
54 | - config.params = undefined; | |
53 | + config.url = config.url + params + `${joinTimestamp(joinTime, true)}` | |
54 | + config.params = undefined | |
55 | 55 | } |
56 | 56 | } else { |
57 | 57 | if (!isString(params)) { |
58 | - formatDate && formatRequestDate(params); | |
58 | + formatDate && formatRequestDate(params) | |
59 | 59 | if (Reflect.has(config, 'data') && config.data && Object.keys(config.data).length > 0) { |
60 | - config.data = data; | |
61 | - config.params = params; | |
60 | + config.data = data | |
61 | + config.params = params | |
62 | 62 | } else { |
63 | 63 | // 非GET请求如果没有提供data,则将params视为data |
64 | - config.data = params; | |
65 | - config.params = undefined; | |
64 | + config.data = params | |
65 | + config.params = undefined | |
66 | 66 | } |
67 | 67 | if (joinParamsToUrl) { |
68 | - config.url = setObjToUrlParams( | |
69 | - config.url as string, | |
70 | - Object.assign({}, config.params, config.data) | |
71 | - ); | |
68 | + config.url = setObjToUrlParams(config.url as string, Object.assign({}, config.params, config.data)) | |
72 | 69 | } |
73 | 70 | } else { |
74 | 71 | // 兼容restful风格 |
75 | - config.url = config.url + params; | |
76 | - config.params = undefined; | |
72 | + config.url = config.url + params | |
73 | + config.params = undefined | |
77 | 74 | } |
78 | 75 | } |
79 | - return config; | |
76 | + return config | |
80 | 77 | }, |
81 | 78 | |
82 | 79 | /** |
... | ... | @@ -84,21 +81,32 @@ const transform: AxiosTransform = { |
84 | 81 | */ |
85 | 82 | requestInterceptors: (config, options) => { |
86 | 83 | // 请求之前处理config |
87 | - const { requestOptions } = config; | |
88 | - const { withShareToken } = requestOptions || {}; | |
89 | - const { requestOptions: { withToken } = {} } = options; | |
84 | + const { requestOptions } = config | |
85 | + const { withShareToken } = requestOptions || {} | |
86 | + const { requestOptions: { withToken } = {} } = options | |
87 | + const { withThirdTokenPrefix, withThirdTokenKey, withThirdTokenString } = config.requestOptions as Recordable | |
90 | 88 | if (withToken !== false) { |
91 | - const shareToken = getShareJwtToken(); | |
89 | + const shareToken = getShareJwtToken() | |
92 | 90 | if (withShareToken && shareToken) { |
93 | 91 | config.headers!['X-Authorization'] = options.authenticationScheme |
94 | 92 | ? `${options.authenticationScheme} ${shareToken}` |
95 | - : shareToken; | |
93 | + : shareToken | |
96 | 94 | } else { |
97 | - const token = getJwtToken(); | |
98 | - if (token) { | |
99 | - config.headers!['X-Authorization'] = options.authenticationScheme | |
100 | - ? `${options.authenticationScheme} ${token}` | |
101 | - : token; | |
95 | + const token = getJwtToken() | |
96 | + if (!withThirdTokenString) { | |
97 | + // 则是此平台 | |
98 | + if (token) { | |
99 | + config.headers!['X-Authorization'] = options.authenticationScheme | |
100 | + ? `${options.authenticationScheme} ${token}` | |
101 | + : token | |
102 | + } | |
103 | + } else { | |
104 | + // 第三方接口 | |
105 | + const authenticationScheme = withThirdTokenPrefix ? withThirdTokenPrefix : null | |
106 | + const tokenKey = withThirdTokenKey ? withThirdTokenKey : null | |
107 | + config.headers![tokenKey!] = withThirdTokenPrefix | |
108 | + ? `${authenticationScheme} ${withThirdTokenString}` | |
109 | + : `${withThirdTokenString}` | |
102 | 110 | } |
103 | 111 | } |
104 | 112 | } |
... | ... | @@ -109,25 +117,22 @@ const transform: AxiosTransform = { |
109 | 117 | * @description: 响应拦截器处理 |
110 | 118 | */ |
111 | 119 | responseInterceptors: (res: AxiosResponse<any>) => { |
112 | - return res; | |
120 | + return res | |
113 | 121 | }, |
114 | 122 | |
115 | 123 | /** |
116 | 124 | * @description: 响应错误处理 |
117 | 125 | */ |
118 | 126 | responseInterceptorsCatch: (error: any) => { |
127 | + const { response, config } = error || {} | |
128 | + const errorMessageMode = config?.requestOptions?.errorMessageMode || 'none' | |
129 | + const errorMsgIsObj = typeof response?.data === 'object' | |
130 | + const msg: string = errorMsgIsObj ? response?.data?.message || response?.data?.msg : response?.data | |
119 | 131 | |
120 | - const { response, config } = error || {}; | |
121 | - const errorMessageMode = config?.requestOptions?.errorMessageMode || 'none'; | |
122 | - const errorMsgIsObj = typeof response?.data === 'object'; | |
123 | - const msg: string = errorMsgIsObj | |
124 | - ? response?.data?.message || response?.data?.msg | |
125 | - : response?.data; | |
126 | - | |
127 | - const flag = checkStatus(error?.response?.status, msg, errorMessageMode); | |
128 | - return Promise.reject(response?.data); | |
129 | - }, | |
130 | -}; | |
132 | + const flag = checkStatus(error?.response?.status, msg, errorMessageMode) | |
133 | + return Promise.reject(response?.data) | |
134 | + } | |
135 | +} | |
131 | 136 | |
132 | 137 | function createAxios(opt?: Partial<CreateAxiosOptions>) { |
133 | 138 | return new VAxios( |
... | ... | @@ -169,11 +174,11 @@ function createAxios(opt?: Partial<CreateAxiosOptions>) { |
169 | 174 | ignoreCancelToken: true, |
170 | 175 | // 是否携带token |
171 | 176 | withToken: true |
172 | - }, | |
177 | + } | |
173 | 178 | }, |
174 | 179 | opt || {} |
175 | 180 | ) |
176 | - ); | |
181 | + ) | |
177 | 182 | } |
178 | -export const customHttp = createAxios(); | |
179 | 183 | |
184 | +export const customHttp = createAxios() | ... | ... |
1 | -import { RequestBodyEnum, RequestHttpEnum, RequestParams } from "@/enums/httpEnum" | |
2 | -import { ExtraRequestConfigType } from "@/store/external/modules/extraComponentInfo.d" | |
3 | -import { RequestConfigType } from "@/store/modules/chartEditStore/chartEditStore.d" | |
4 | -import { isShareMode } from "@/views/share/hook" | |
5 | -import { customHttp } from "./http" | |
6 | -import { SelectTimeAggregationFieldEnum } from "@/views/chart/ContentConfigurations/components/ChartData/external/components/SelectTImeAggregation" | |
1 | +import { RequestBodyEnum, RequestHttpEnum, RequestParams, RequestParamsObjType } from '@/enums/httpEnum' | |
2 | +import { ExtraRequestConfigType } from '@/store/external/modules/extraComponentInfo.d' | |
3 | +import { RequestConfigType } from '@/store/modules/chartEditStore/chartEditStore.d' | |
4 | +import { isShareMode } from '@/views/share/hook' | |
5 | +import { customHttp } from './http' | |
6 | +import { SelectTimeAggregationFieldEnum } from '@/views/chart/ContentConfigurations/components/ChartData/external/components/SelectTImeAggregation' | |
7 | 7 | |
8 | 8 | export enum ParamsType { |
9 | 9 | REQUIRED, |
... | ... | @@ -20,7 +20,7 @@ const regDynamicParams = /(?={).+?(?<=})/g |
20 | 20 | |
21 | 21 | /** |
22 | 22 | * @description 判断是否是动态参数 |
23 | - * @param url | |
23 | + * @param url | |
24 | 24 | */ |
25 | 25 | export const isDynamicUrl = (url: string) => { |
26 | 26 | regDynamicParams.lastIndex = 0 |
... | ... | @@ -29,7 +29,7 @@ export const isDynamicUrl = (url: string) => { |
29 | 29 | |
30 | 30 | /** |
31 | 31 | * @description 解析动态参数 |
32 | - * @param url | |
32 | + * @param url | |
33 | 33 | */ |
34 | 34 | export const decomposeDynamicParams = (url: string) => { |
35 | 35 | regDynamicParams.lastIndex = 0 |
... | ... | @@ -46,8 +46,8 @@ export const decomposeDynamicParams = (url: string) => { |
46 | 46 | |
47 | 47 | /** |
48 | 48 | * @description 正则替换url中的动态参数 |
49 | - * @param requestUrl | |
50 | - * @param Params | |
49 | + * @param requestUrl | |
50 | + * @param Params | |
51 | 51 | */ |
52 | 52 | const getDynamicRequestUrl = (requestUrl = '', Params: Recordable) => { |
53 | 53 | requestUrl = decodeURI(requestUrl || '') |
... | ... | @@ -101,9 +101,9 @@ const handleParams = (Params: Recordable) => { |
101 | 101 | * 源代码 Params.keys = (Params.keys || [] as any).join(',') |
102 | 102 | */ |
103 | 103 | if (!Array.isArray(Params.keys)) { |
104 | - Params.keys = ([Params.keys] || [] as any).join(',') | |
104 | + Params.keys = ([Params.keys] || ([] as any)).join(',') | |
105 | 105 | } else { |
106 | - Params.keys = (Params.keys || [] as any).join(',') | |
106 | + Params.keys = (Params.keys || ([] as any)).join(',') | |
107 | 107 | } |
108 | 108 | //ft |
109 | 109 | } |
... | ... | @@ -115,27 +115,37 @@ const handleParams = (Params: Recordable) => { |
115 | 115 | Reflect.deleteProperty(Params, SelectTimeAggregationFieldEnum.TIME_PERIOD) |
116 | 116 | } |
117 | 117 | |
118 | - return Object.keys(Params).filter(Boolean).reduce((prev, next) => ({ ...prev, [next]: Params[next] }), {}) | |
118 | + return Object.keys(Params) | |
119 | + .filter(Boolean) | |
120 | + .reduce((prev, next) => ({ ...prev, [next]: Params[next] }), {}) | |
119 | 121 | } |
120 | 122 | |
121 | 123 | //post请求动态追加query参数 |
122 | 124 | const objConvertQuery = (data: Recordable) => { |
123 | - const _result = []; | |
125 | + const _result = [] | |
124 | 126 | for (const key in data) { |
125 | - const value = data[key]; | |
127 | + const value = data[key] | |
126 | 128 | if (value.constructor == Array) { |
127 | 129 | value.forEach(function (_value) { |
128 | - _result.push(key + "=" + _value); | |
129 | - }); | |
130 | + _result.push(key + '=' + _value) | |
131 | + }) | |
130 | 132 | } else { |
131 | - _result.push(key + '=' + value); | |
133 | + _result.push(key + '=' + value) | |
132 | 134 | } |
133 | 135 | } |
134 | - return _result.join('&'); | |
136 | + return _result.join('&') | |
135 | 137 | } |
136 | 138 | |
137 | 139 | export const customRequest = async (request: RequestConfigType) => { |
138 | - const { requestHttpType, requestParams, requestParamsBodyType, requestOriginUrl } = request as ExtraRequestConfigType | |
140 | + const { | |
141 | + requestHttpType, | |
142 | + requestParams, | |
143 | + requestParamsBodyType, | |
144 | + requestOriginUrl, | |
145 | + requestVerificationToken, | |
146 | + requestTokenKey, | |
147 | + requestTokenSuffix | |
148 | + } = request as ExtraRequestConfigType | |
139 | 149 | let { requestUrl } = request as ExtraRequestConfigType |
140 | 150 | const { Header, Body } = requestParams |
141 | 151 | let { Params } = requestParams |
... | ... | @@ -155,18 +165,47 @@ export const customRequest = async (request: RequestConfigType) => { |
155 | 165 | * 修改后代码 requestHttpType === RequestHttpEnum.GET.toUpperCase() ? requestUrl: `${requestUrl}?${objConvertQuery(Params)} |
156 | 166 | */ |
157 | 167 | Params = handleParams(Params) |
158 | - | |
159 | - return customHttp.request<any>({ | |
160 | - url: requestHttpType === RequestHttpEnum.GET.toUpperCase() ? requestUrl : `${requestUrl}?${objConvertQuery(Params)}`, | |
161 | - baseURL: getOriginUrl(requestOriginUrl!), | |
162 | - method: requestHttpType, | |
163 | - params: requestHttpType === RequestHttpEnum.GET.toUpperCase() ? Params : null, | |
164 | - data: body, | |
165 | - headers: extraValue(Header) | |
166 | - }, { | |
167 | - joinPrefix: false, | |
168 | - apiUrl: '', | |
169 | - withShareToken: isShareMode() | |
170 | - }) | |
168 | + return customHttp.request<any>( | |
169 | + { | |
170 | + url: | |
171 | + requestHttpType === RequestHttpEnum.GET.toUpperCase() ? requestUrl : `${requestUrl}?${objConvertQuery(Params)}`, | |
172 | + baseURL: requestVerificationToken ? '' : getOriginUrl(requestOriginUrl!), // 如果是第三方接口,则无需添加baseURL | |
173 | + method: requestHttpType, | |
174 | + params: requestHttpType === RequestHttpEnum.GET.toUpperCase() ? Params : null, | |
175 | + data: body, | |
176 | + headers: extraValue(Header) | |
177 | + }, | |
178 | + { | |
179 | + joinPrefix: false, | |
180 | + apiUrl: '', | |
181 | + withShareToken: isShareMode(), | |
182 | + withThirdTokenString: requestVerificationToken, | |
183 | + withThirdTokenKey: requestTokenKey, | |
184 | + withThirdTokenPrefix: requestTokenSuffix | |
185 | + } | |
186 | + ) | |
171 | 187 | //ft |
172 | 188 | } |
189 | + | |
190 | +export interface thirdInterfaceRequest { | |
191 | + requestOriginUrl: string | |
192 | + body: RequestParamsObjType | |
193 | +} | |
194 | + | |
195 | +//特殊处理第三方接口,一般获取token是POST请求,暂定POST | |
196 | +export const customThirdInterfaceRequest = async (request: thirdInterfaceRequest) => { | |
197 | + const { body, requestOriginUrl } = request | |
198 | + | |
199 | + return customHttp.request<any>( | |
200 | + { | |
201 | + url: requestOriginUrl, | |
202 | + method: RequestHttpEnum.POST, | |
203 | + data: body | |
204 | + }, | |
205 | + { | |
206 | + joinPrefix: false, | |
207 | + apiUrl: '', | |
208 | + withToken: false | |
209 | + } | |
210 | + ) | |
211 | +} | ... | ... |
src/enums/external/dataTypeEnum.ts
0 → 100644
src/enums/external/tokenEnum.ts
0 → 100644
... | ... | @@ -23,7 +23,7 @@ export enum EditCanvasTypeEnum { |
23 | 23 | IS_CREATE = 'isCreate', |
24 | 24 | IS_DRAG = 'isDrag', |
25 | 25 | IS_SELECT = 'isSelect', |
26 | - IS_CODE_EDIT = "isCodeEdit" | |
26 | + IS_CODE_EDIT = 'isCodeEdit' | |
27 | 27 | } |
28 | 28 | |
29 | 29 | // 编辑区域 |
... | ... | @@ -61,10 +61,9 @@ export enum EditCanvasConfigEnum { |
61 | 61 | BACKGROUND_IMAGE = 'backgroundImage', |
62 | 62 | SELECT_COLOR = 'selectColor', |
63 | 63 | PREVIEW_SCALE_TYPE = 'previewScaleType', |
64 | - ANIMATION_STYLE_CONFIG = 'animationsStyleConfig', | |
64 | + ANIMATION_STYLE_CONFIG = 'animationsStyleConfig' | |
65 | 65 | } |
66 | 66 | |
67 | - | |
68 | 67 | export interface EditCanvasConfigType { |
69 | 68 | // 滤镜-启用 |
70 | 69 | [FilterEnum.FILTERS_SHOW]: boolean |
... | ... | @@ -176,8 +175,8 @@ type RequestPublicConfigType = { |
176 | 175 | |
177 | 176 | // 数据池项类型 |
178 | 177 | export type RequestDataPondItemType = { |
179 | - dataPondId: string, | |
180 | - dataPondName: string, | |
178 | + dataPondId: string | |
179 | + dataPondName: string | |
181 | 180 | dataPondRequestConfig: RequestConfigType |
182 | 181 | } |
183 | 182 | |
... | ... | @@ -189,6 +188,14 @@ export interface RequestGlobalConfigType extends RequestPublicConfigType { |
189 | 188 | requestOriginUrl?: string |
190 | 189 | // 公共数据池 |
191 | 190 | requestDataPond: RequestDataPondItemType[] |
191 | + // 验证方式 | |
192 | + requestVerificationMethods?: TokenEnum | |
193 | + // 全局Token | |
194 | + requestVerificationToken?: string | |
195 | + // 请求头里的Token键 | |
196 | + requestTokenKey?: string | |
197 | + // 请求头里的Token前缀 | |
198 | + requestTokenSuffix?: string, | |
192 | 199 | } |
193 | 200 | |
194 | 201 | // 单个图表请求配置 |
... | ... | @@ -211,6 +218,12 @@ export interface RequestConfigType extends RequestPublicConfigType { |
211 | 218 | requestSQLContent: { |
212 | 219 | sql: string |
213 | 220 | } |
221 | + // Token | |
222 | + requestVerificationToken?: string | |
223 | + // 请求头里的Token键 | |
224 | + requestTokenKey?: string | |
225 | + // 请求头里的Token前缀 | |
226 | + requestTokenSuffix?: string | |
214 | 227 | } |
215 | 228 | |
216 | 229 | // Store 类型 | ... | ... |
... | ... | @@ -135,7 +135,9 @@ function createNewPageItem(id: string = getUUID(), title = '页面'): PageChartE |
135 | 135 | }, |
136 | 136 | Header: {}, |
137 | 137 | Params: {} |
138 | - } | |
138 | + }, | |
139 | + requestVerificationMethods: 'Token', | |
140 | + requestVerificationToken: '', | |
139 | 141 | }, |
140 | 142 | // 图表数组(需存储给后端) |
141 | 143 | componentList: [] | ... | ... |
... | ... | @@ -119,7 +119,16 @@ export class VAxios { |
119 | 119 | if (userStore) { |
120 | 120 | try { |
121 | 121 | const { requestOptions = {} } = config |
122 | - const { withShareToken, withToken } = requestOptions | |
122 | + const { withShareToken, withToken, withThirdTokenString } = requestOptions | |
123 | + if (withThirdTokenString) { | |
124 | + //三方平台逻辑 | |
125 | + const res = jwt_decode(withThirdTokenString) as Recordable; | |
126 | + const currentTime = (new Date().getTime() + (config.timeout || 0)) / 1000; | |
127 | + if (currentTime >= res?.exp) { | |
128 | + window['$message'].warning('第三方平台Token已经失效,请您重新返回设计页面点击执行请求获取最新Token') | |
129 | + } | |
130 | + } else { | |
131 | + //此平台逻辑 | |
123 | 132 | const token = withShareToken && withToken ? userStore.shareJwtToken : userStore.jwtToken |
124 | 133 | const doRefresh = withShareToken && withToken ? userStore.doShareRefresh : userStore.doRefresh |
125 | 134 | if (token) { |
... | ... | @@ -129,7 +138,8 @@ export class VAxios { |
129 | 138 | await this.refreshTokenBeforeReq(doRefresh); |
130 | 139 | } |
131 | 140 | } |
132 | - | |
141 | + // | |
142 | + } | |
133 | 143 | } catch (error) { |
134 | 144 | userStore.logout(); |
135 | 145 | } | ... | ... |
... | ... | @@ -38,3 +38,30 @@ export const parseWebUrl = (str = window.location.search) => { |
38 | 38 | str.replace(reg, (_, k, v) => (params[k] = v)) |
39 | 39 | return params |
40 | 40 | } |
41 | + | |
42 | +//嵌套对象转换为级联选择器数据格式 | |
43 | +interface cascadingData { | |
44 | + label: string | |
45 | + value: string | cascadingData[] | number | |
46 | + children: cascadingData[] | null | |
47 | +} | |
48 | +export const convertToCascadingData = (obj: Recordable): cascadingData[] => { | |
49 | + const result: cascadingData[] = [] | |
50 | + for (const key in obj) { | |
51 | + // eslint-disable-next-line no-prototype-builtins | |
52 | + if (obj.hasOwnProperty(key)) { | |
53 | + let value: cascadingData[] | string | number | |
54 | + if (typeof obj[key] === 'object' && obj[key] !== null) { | |
55 | + value = convertToCascadingData(obj[key]) | |
56 | + } else { | |
57 | + value = String(obj[key]) | |
58 | + } | |
59 | + result.push({ | |
60 | + label: key, | |
61 | + value, | |
62 | + children: Array.isArray(value) ? value : null | |
63 | + }) | |
64 | + } | |
65 | + } | |
66 | + return result | |
67 | +} | ... | ... |
... | ... | @@ -166,6 +166,20 @@ const closeFilter = () => { |
166 | 166 | showModal.value = false |
167 | 167 | } |
168 | 168 | |
169 | +// 发送请求 | |
170 | +const sendHandle = async () => { | |
171 | + try { | |
172 | + const res = await fetchHandle() | |
173 | + if (res) { | |
174 | + const { value } = useFilterFn(targetData.value.filter, res) | |
175 | + targetData.value.option.dataset = value | |
176 | + return | |
177 | + } | |
178 | + } catch(e) { | |
179 | + console.error(e) | |
180 | + } | |
181 | +} | |
182 | + | |
169 | 183 | // 新增过滤器 |
170 | 184 | const saveFilter = () => { |
171 | 185 | if (errorFlag.value) { |
... | ... | @@ -174,6 +188,7 @@ const saveFilter = () => { |
174 | 188 | } |
175 | 189 | targetData.value.filter = filter.value |
176 | 190 | closeFilter() |
191 | + sendHandle() | |
177 | 192 | } |
178 | 193 | |
179 | 194 | watch( | ... | ... |
... | ... | @@ -14,21 +14,18 @@ import { RequestDataTypeEnum } from '@/enums/external/httpEnum' |
14 | 14 | |
15 | 15 | const { HelpOutlineIcon, FlashIcon } = icon.ionicons5 |
16 | 16 | const { targetData } = useTargetData() |
17 | - | |
18 | - | |
19 | 17 | |
20 | 18 | const requestModal = ref<InstanceType<typeof RequestModal>>() |
21 | 19 | |
22 | 20 | const designStore = useDesignStore() |
23 | 21 | |
24 | - | |
25 | 22 | /** |
26 | - * ft 修改在公共接口下拉框里默认选择公共接口 | |
27 | - * 修改后的代码在注释之间,并标注好源代码和修改后代码,方便回溯 | |
28 | - * 源代码 const selectedRequestType = ref(targetData.value.request.requestDataType || RequestDataTypeEnum.AJAX) | |
29 | - * 修改后的代码 const selectedRequestType = ref(targetData.value.request.requestDataType || RequestDataTypeEnum.Pond) | |
30 | - * 修改后代码在//ft之间 | |
31 | - */ | |
23 | + * ft 修改在公共接口下拉框里默认选择公共接口 | |
24 | + * 修改后的代码在注释之间,并标注好源代码和修改后代码,方便回溯 | |
25 | + * 源代码 const selectedRequestType = ref(targetData.value.request.requestDataType || RequestDataTypeEnum.AJAX) | |
26 | + * 修改后的代码 const selectedRequestType = ref(targetData.value.request.requestDataType || RequestDataTypeEnum.Pond) | |
27 | + * 修改后代码在//ft之间 | |
28 | + */ | |
32 | 29 | const selectedRequestType = ref(targetData.value.request.requestDataType || RequestDataTypeEnum.Pond) |
33 | 30 | |
34 | 31 | const getApiRequestType: SelectOption[] = [ |
... | ... | @@ -43,7 +40,7 @@ const showMatching = ref(false) |
43 | 40 | let firstFocus = 0 |
44 | 41 | let lastFilter: any = undefined |
45 | 42 | |
46 | -const { fetchTargetData, } = useFetchTargetData() | |
43 | +const { fetchTargetData } = useFetchTargetData() | |
47 | 44 | |
48 | 45 | // 发送请求 |
49 | 46 | const sendHandle = async () => { |
... | ... | @@ -63,9 +60,9 @@ const sendHandle = async () => { |
63 | 60 | } finally { |
64 | 61 | loading.value = false |
65 | 62 | } |
66 | - | |
67 | 63 | } |
68 | 64 | |
65 | + | |
69 | 66 | // 颜色 |
70 | 67 | const themeColor = computed(() => { |
71 | 68 | return designStore.getAppTheme |
... | ... | @@ -73,6 +70,9 @@ const themeColor = computed(() => { |
73 | 70 | |
74 | 71 | const handleClickPanel = () => { |
75 | 72 | unref(requestModal as any)?.openModal?.(true, unref(selectedRequestType)) |
73 | + if (selectedRequestType.value === RequestDataTypeEnum.AJAX) { | |
74 | + targetData.value.request.requestDataType = RequestDataTypeEnum.AJAX | |
75 | + } | |
76 | 76 | } |
77 | 77 | |
78 | 78 | // TODO socket 请求时会触发 |
... | ... | @@ -81,7 +81,7 @@ watchEffect(() => { |
81 | 81 | /** |
82 | 82 | * FT 修改 |
83 | 83 | */ |
84 | - if(!filter) return | |
84 | + if (!filter) return | |
85 | 85 | //ft |
86 | 86 | if (lastFilter !== filter && firstFocus) { |
87 | 87 | lastFilter = filter |
... | ... | @@ -93,8 +93,6 @@ watchEffect(() => { |
93 | 93 | onBeforeUnmount(() => { |
94 | 94 | lastFilter = null |
95 | 95 | }) |
96 | - | |
97 | - | |
98 | 96 | </script> |
99 | 97 | |
100 | 98 | <template> |
... | ... | @@ -137,8 +135,6 @@ onBeforeUnmount(() => { |
137 | 135 | </div> |
138 | 136 | </template> |
139 | 137 | |
140 | - | |
141 | - | |
142 | 138 | <style lang="scss" scoped> |
143 | 139 | @include thingsKit('chart-configurations-data-ajax') { |
144 | 140 | .n-card-shallow { |
... | ... | @@ -174,4 +170,4 @@ onBeforeUnmount(() => { |
174 | 170 | } |
175 | 171 | } |
176 | 172 | } |
177 | -</style> | |
173 | +</style> | ... | ... |
1 | 1 | <script setup lang="ts"> |
2 | -import { NInput, NInputNumber, NInputGroup, NButton, NSelect, SelectOption, NTabs, NTabPane, NSpace } from 'naive-ui' | |
2 | +import { NInput, NInputNumber, NInputGroup, NSelect, SelectOption, NTabs, NTabPane } from 'naive-ui' | |
3 | 3 | import { SettingItem, SettingItemBox } from '@/components/Pages/ChartItemSetting'; |
4 | 4 | import { selectTimeOptions, selectTypeOptions } from '../../../index.d'; |
5 | 5 | import { RequestBodyEnum, RequestContentTypeEnum, RequestDataTypeEnum, RequestHttpEnum, RequestHttpIntervalEnum, RequestParams } from '@/enums/httpEnum'; |
... | ... | @@ -7,9 +7,6 @@ import { ref, unref } from 'vue'; |
7 | 7 | import DefaultRequestContent from './DefaultRequestContent.vue'; |
8 | 8 | import SqlConfiguration from './SqlConfiguration.vue'; |
9 | 9 | import { RequestConfigType } from '@/store/modules/chartEditStore/chartEditStore.d'; |
10 | -import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'; | |
11 | - | |
12 | -const chartEditStore = useChartEditStore() | |
13 | 10 | |
14 | 11 | const requestContentTypeRef = ref(RequestContentTypeEnum.DEFAULT) |
15 | 12 | |
... | ... | @@ -39,7 +36,7 @@ const getConfigurationData = (): RequestConfigType => { |
39 | 36 | sql: unref(requestSQLContentRef) |
40 | 37 | }, |
41 | 38 | requestParams: unref(requestParamsRef), |
42 | - requestUrl: `${chartEditStore.getRequestGlobalConfig.requestOriginUrl}${unref(requestUrlRef)}` | |
39 | + requestUrl: `${unref(requestUrlRef)}` | |
43 | 40 | } |
44 | 41 | } |
45 | 42 | |
... | ... | @@ -53,7 +50,7 @@ const setConfigurationData = (request: RequestConfigType) => { |
53 | 50 | requestParamsBodyTypeRef.value = requestParamsBodyType |
54 | 51 | requestSQLContentRef.value = requestSQLContent.sql |
55 | 52 | requestParamsRef.value = requestParams |
56 | - requestUrlRef.value = !requestUrl ? ``: 'h' + requestUrl?.split('h')[1] | |
53 | + requestUrlRef.value = requestUrl | |
57 | 54 | } |
58 | 55 | |
59 | 56 | defineExpose({ | ... | ... |
1 | 1 | <script lang="ts" setup> |
2 | -import { RequestBodyEnum, RequestParams, RequestParamsTypeEnum } from '@/enums/httpEnum'; | |
3 | -import { NTabPane, NTabs } from 'naive-ui'; | |
4 | -import { ref } from 'vue'; | |
5 | -import ParamsTable from './ParamsTable.vue'; | |
6 | -import RequestBody from './RequestBody.vue'; | |
2 | +import { RequestBodyEnum, RequestParams, RequestParamsTypeEnum } from '@/enums/httpEnum' | |
3 | +import { NTabPane, NTabs } from 'naive-ui' | |
4 | +import { ref } from 'vue' | |
5 | +import ParamsTable from './ParamsTable.vue' | |
6 | +import RequestBody from './RequestBody.vue' | |
7 | 7 | |
8 | 8 | const props = defineProps<{ |
9 | 9 | value: RequestParams |
... | ... | @@ -21,7 +21,6 @@ const handleSyncRequestParamsBodyType = (value: RequestBodyEnum) => { |
21 | 21 | const handleUpdate = (key: RequestParamsTypeEnum, value: Recordable) => { |
22 | 22 | emit('update:value', { ...props.value, [key]: value }) |
23 | 23 | } |
24 | - | |
25 | 24 | </script> |
26 | 25 | |
27 | 26 | <template> |
... | ... | @@ -30,24 +29,29 @@ const handleUpdate = (key: RequestParamsTypeEnum, value: Recordable) => { |
30 | 29 | <NTabPane v-for="item in RequestParamsTypeEnum" :name="item" :key="item"></NTabPane> |
31 | 30 | </NTabs> |
32 | 31 | <section v-if="tabValue === RequestParamsTypeEnum.PARAMS"> |
33 | - <ParamsTable :value="value[RequestParamsTypeEnum.PARAMS]" | |
34 | - @update:value="(value: Recordable) => handleUpdate(RequestParamsTypeEnum.PARAMS, value)" /> | |
32 | + <ParamsTable | |
33 | + :value="value[RequestParamsTypeEnum.PARAMS]" | |
34 | + @update:value="(value: Recordable) => handleUpdate(RequestParamsTypeEnum.PARAMS, value)" | |
35 | + /> | |
35 | 36 | </section> |
36 | 37 | |
37 | - <RequestBody :value="value" @update:value="(value: Recordable) => handleUpdate(RequestParamsTypeEnum.BODY, value)" | |
38 | - @update:requestParamsBodyType="handleSyncRequestParamsBodyType" :requestParamsBodyType="requestParamsBodyType" | |
39 | - v-if="tabValue === RequestParamsTypeEnum.BODY" /> | |
40 | - | |
41 | - <ParamsTable v-if="tabValue === RequestParamsTypeEnum.HEADER" :value="value.Header" | |
42 | - @update:value="(value: Recordable) => handleUpdate(RequestParamsTypeEnum.HEADER, value)" /> | |
38 | + <RequestBody | |
39 | + :value="value" | |
40 | + @update:value="(value: Recordable) => handleUpdate(RequestParamsTypeEnum.BODY, value)" | |
41 | + @update:requestParamsBodyType="handleSyncRequestParamsBodyType" | |
42 | + :requestParamsBodyType="requestParamsBodyType" | |
43 | + v-if="tabValue === RequestParamsTypeEnum.BODY" | |
44 | + /> | |
45 | + | |
46 | + <ParamsTable | |
47 | + v-if="tabValue === RequestParamsTypeEnum.HEADER" | |
48 | + :value="value.Header" | |
49 | + @update:value="(value: Recordable) => handleUpdate(RequestParamsTypeEnum.HEADER, value)" | |
50 | + /> | |
43 | 51 | </section> |
44 | 52 | </template> |
45 | 53 | |
46 | 54 | <style lang="scss" scoped> |
47 | -.container { | |
48 | - width: 600px; | |
49 | -} | |
50 | - | |
51 | 55 | .body-container { |
52 | 56 | margin-top: 20px; |
53 | 57 | } | ... | ... |
1 | 1 | <script lang="ts" setup> |
2 | -import { SettingItem, SettingItemBox } from '@/components/Pages/ChartItemSetting'; | |
3 | -import { icon } from '@/plugins'; | |
4 | -import { NButton, NCard, NCollapseTransition, NIcon, NInput, NInputGroup, NInputNumber, NSelect, NSpace, NTag, NTooltip, SelectOption } from 'naive-ui'; | |
5 | -import { computed, ref, unref } from 'vue'; | |
2 | +import { SettingItem, SettingItemBox } from '@/components/Pages/ChartItemSetting' | |
3 | +import { icon } from '@/plugins' | |
4 | +import { | |
5 | + NButton, | |
6 | + NCard, | |
7 | + NCollapseTransition, | |
8 | + NIcon, | |
9 | + NInput, | |
10 | + NInputGroup, | |
11 | + NInputNumber, | |
12 | + NSelect, | |
13 | + NSpace, | |
14 | + NTag, | |
15 | + NTooltip, | |
16 | + SelectOption, | |
17 | + NCascader | |
18 | +} from 'naive-ui' | |
19 | +import { computed, ref, unref, onMounted, reactive } from 'vue' | |
6 | 20 | import GlobalParamsConfiguration from './GlobalParamsConfiguration.vue' |
7 | 21 | import { ChevronDown, ChevronUp } from '@vicons/carbon' |
8 | -import { useDesignStore } from '@/store/modules/designStore/designStore'; | |
9 | -import { selectTimeOptions } from '../../../index.d'; | |
10 | -import { useTargetData } from '../../../../hooks/useTargetData.hook'; | |
11 | -import { RequestHttpIntervalEnum } from '@/enums/httpEnum'; | |
22 | +import { useDesignStore } from '@/store/modules/designStore/designStore' | |
23 | +import { selectTimeOptions } from '../../../index.d' | |
24 | +import { useTargetData } from '../../../../hooks/useTargetData.hook' | |
25 | +import { RequestDataTypeEnum, RequestHttpIntervalEnum } from '@/enums/httpEnum' | |
26 | +import { TokenNameEnum, TokenEnum } from '@/enums/external/tokenEnum' | |
27 | +import { customThirdInterfaceRequest, thirdInterfaceRequest } from '@/api/external/customRequest' | |
28 | +import { CascaderOption } from 'naive-ui' | |
29 | +import { convertToCascadingData } from '@/utils/external/utils' | |
12 | 30 | |
13 | 31 | const { PencilIcon } = icon.ionicons5 |
14 | 32 | const designStore = useDesignStore() |
15 | 33 | const editDisabled = ref(false) |
16 | 34 | const collapseHeaderTable = ref(false) |
17 | 35 | |
18 | -const { chartEditStore } = useTargetData() | |
36 | +const { targetData, chartEditStore } = useTargetData() | |
19 | 37 | |
20 | 38 | const handleCollapse = () => { |
21 | 39 | collapseHeaderTable.value = !unref(collapseHeaderTable) |
22 | 40 | } |
23 | 41 | |
24 | - | |
25 | 42 | // 颜色 |
26 | 43 | const themeColor = computed(() => { |
27 | 44 | return designStore.getAppTheme |
28 | 45 | }) |
29 | 46 | |
47 | +//第三方接口相关代码 | |
48 | +const verifiationValue = ref(TokenEnum.DEFAULT_TOKEN) | |
49 | + | |
50 | +const tokenString = ref('') | |
51 | + | |
52 | +const getTokenString = ref() | |
53 | + | |
54 | +const resOptions = ref<CascaderOption[]>([]) | |
55 | + | |
56 | +const resValue = ref() | |
57 | + | |
58 | +const cascaderConfig = reactive({ | |
59 | + hoverTrigger: true, | |
60 | + checkStrategyIsChild: true, | |
61 | + filterable: false, | |
62 | + showPath: true | |
63 | +}) | |
64 | + | |
65 | +const requestTokenSuffix = ref('Bearer') | |
66 | + | |
67 | +const requestTokenKey = ref('Token') | |
68 | + | |
69 | +//验证方式 | |
70 | +const verificationMethods = [ | |
71 | + { | |
72 | + label: TokenNameEnum.DEFAULT_TOKEN, | |
73 | + value: TokenEnum.DEFAULT_TOKEN | |
74 | + }, | |
75 | + { | |
76 | + label: TokenNameEnum.TOKEN_STRING, | |
77 | + value: TokenEnum.TOKEN_STRING | |
78 | + }, | |
79 | + { | |
80 | + label: TokenNameEnum.NO_VERIFICATION, | |
81 | + value: TokenEnum.NO_VERIFICATION | |
82 | + } | |
83 | +] | |
84 | + | |
85 | +const hasDefaultToken = (value: string[]) => value.includes(TokenEnum.DEFAULT_TOKEN) | |
86 | + | |
87 | +const hasTokenString = (value: string[]) => value.includes(TokenEnum.TOKEN_STRING) | |
30 | 88 | |
89 | +const handleVerificationUpdate = (value: string) => { | |
90 | + chartEditStore.getRequestGlobalConfig.requestVerificationMethods = value | |
91 | + hasTokenString([value]) | |
92 | + hasDefaultToken([value]) | |
93 | + resValue.value = null | |
94 | + resOptions.value = [] | |
95 | + getTokenString.value = '' | |
96 | + requestTokenKey.value = '' | |
97 | + requestTokenSuffix.value = '' | |
98 | +} | |
99 | + | |
100 | +const handleResCascader = (value: string | number) => { | |
101 | + getTokenString.value = value as string | number | |
102 | + chartEditStore.getRequestGlobalConfig.requestVerificationToken = value as string | |
103 | + targetData.value.request.requestVerificationToken = value as string | |
104 | + targetData.value.request.requestDataType = RequestDataTypeEnum.AJAX | |
105 | +} | |
31 | 106 | |
107 | +//执行请求获取三方Token | |
108 | +const handleExecuteRequest = async () => { | |
109 | + try { | |
110 | + const request = { | |
111 | + requestOriginUrl: chartEditStore.getRequestGlobalConfig.requestOriginUrl, | |
112 | + body: chartEditStore.getRequestGlobalConfig.requestParams.Header | |
113 | + } | |
114 | + const res = await customThirdInterfaceRequest(request as thirdInterfaceRequest) | |
115 | + resOptions.value = convertToCascadingData(res) as unknown as CascaderOption[] | |
116 | + chartEditStore.getRequestGlobalConfig.requestVerificationMethods = verifiationValue.value | |
117 | + chartEditStore.getRequestGlobalConfig.requestVerificationToken = resValue.value as string | |
118 | + chartEditStore.getRequestGlobalConfig.requestTokenKey = requestTokenKey.value | |
119 | + chartEditStore.getRequestGlobalConfig.requestTokenSuffix = requestTokenSuffix.value | |
120 | + //存储到当前组件的请求对象里 | |
121 | + targetData.value.request.requestTokenSuffix = requestTokenSuffix.value | |
122 | + targetData.value.request.requestTokenKey = requestTokenKey.value | |
123 | + } catch (e) { | |
124 | + getTokenString.value = JSON.stringify(e) as string | |
125 | + } | |
126 | +} | |
127 | + | |
128 | +onMounted(() => { | |
129 | + getTokenString.value = chartEditStore.getRequestGlobalConfig.requestVerificationToken | |
130 | + verifiationValue.value = chartEditStore.getRequestGlobalConfig.requestVerificationMethods || TokenEnum.DEFAULT_TOKEN | |
131 | + requestTokenKey.value = chartEditStore.getRequestGlobalConfig.requestTokenKey! | |
132 | + requestTokenSuffix.value = chartEditStore.getRequestGlobalConfig.requestTokenSuffix! | |
133 | +}) | |
134 | +// | |
32 | 135 | </script> |
33 | 136 | |
34 | 137 | <template> |
... | ... | @@ -37,23 +140,43 @@ const themeColor = computed(() => { |
37 | 140 | <NTag type="info">全局公共配置</NTag> |
38 | 141 | </template> |
39 | 142 | <NSpace vertical> |
40 | - <SettingItemBox name="服务" :itemRightStyle="{ | |
41 | - gridTemplateColumns: '5fr 2fr 1fr' | |
42 | - }"> | |
143 | + <SettingItemBox | |
144 | + name="服务" | |
145 | + :itemRightStyle="{ | |
146 | + gridTemplateColumns: '5fr 2fr 1fr' | |
147 | + }" | |
148 | + > | |
43 | 149 | <!-- 源地址 --> |
44 | 150 | <SettingItem name="前置 URL"> |
45 | - <NInput v-model:value="chartEditStore.getRequestGlobalConfig.requestOriginUrl" default-value="http://127.0.0.1" :disabled="editDisabled" | |
46 | - size="small" placeholder="例:http://127.0.0.1"></NInput> | |
151 | + <NInput | |
152 | + v-model:value="chartEditStore.getRequestGlobalConfig.requestOriginUrl" | |
153 | + default-value="http://127.0.0.1" | |
154 | + :disabled="editDisabled" | |
155 | + size="small" | |
156 | + placeholder="例:http://127.0.0.1" | |
157 | + ></NInput> | |
47 | 158 | </SettingItem> |
48 | 159 | <SettingItem name="更新间隔,为 0 只会初始化"> |
49 | 160 | <NInputGroup> |
50 | - <NInputNumber v-model:value="chartEditStore.getRequestGlobalConfig.requestInterval" class="select-time-number" | |
51 | - size="small" min="0" :show-button="false" :disabled="editDisabled" placeholder="请输入数字"> | |
161 | + <NInputNumber | |
162 | + v-model:value="chartEditStore.getRequestGlobalConfig.requestInterval" | |
163 | + class="select-time-number" | |
164 | + size="small" | |
165 | + min="0" | |
166 | + :show-button="false" | |
167 | + :disabled="editDisabled" | |
168 | + placeholder="请输入数字" | |
169 | + > | |
52 | 170 | </NInputNumber> |
53 | 171 | <!-- 单位 --> |
54 | - <NSelect v-model:value="chartEditStore.getRequestGlobalConfig.requestIntervalUnit" class="select-time-options" | |
55 | - size="small" :default-value="RequestHttpIntervalEnum.SECOND" :options="selectTimeOptions as SelectOption[]" | |
56 | - :disabled="editDisabled" /> | |
172 | + <NSelect | |
173 | + v-model:value="chartEditStore.getRequestGlobalConfig.requestIntervalUnit" | |
174 | + class="select-time-options" | |
175 | + size="small" | |
176 | + :default-value="RequestHttpIntervalEnum.SECOND" | |
177 | + :options="selectTimeOptions as SelectOption[]" | |
178 | + :disabled="editDisabled" | |
179 | + /> | |
57 | 180 | </NInputGroup> |
58 | 181 | </SettingItem> |
59 | 182 | <NButton v-show="editDisabled" type="primary" ghost @click="editDisabled = false"> |
... | ... | @@ -65,8 +188,67 @@ const themeColor = computed(() => { |
65 | 188 | 编辑配置 |
66 | 189 | </NButton> |
67 | 190 | </SettingItemBox> |
191 | + <!-- 针对第三方接口 --> | |
192 | + <SettingItemBox | |
193 | + name="验证方式" | |
194 | + :itemRightStyle="{ | |
195 | + gridTemplateColumns: '5fr 2fr 1fr' | |
196 | + }" | |
197 | + > | |
198 | + <n-radio-group v-model:value="verifiationValue" name="radiogroup" @update:value="handleVerificationUpdate"> | |
199 | + <n-space> | |
200 | + <n-radio | |
201 | + v-for="verificationItem in verificationMethods" | |
202 | + :key="verificationItem.value" | |
203 | + :value="verificationItem.value" | |
204 | + > | |
205 | + {{ verificationItem.label }} | |
206 | + </n-radio> | |
207 | + </n-space> | |
208 | + </n-radio-group> | |
209 | + </SettingItemBox> | |
210 | + <SettingItemBox v-if="hasDefaultToken([verifiationValue])" name="配置"> | |
211 | + <SettingItem name="Token前缀"> | |
212 | + <n-input v-model:value.trim="requestTokenSuffix" type="text" placeholder="例如:Bearer" /> | |
213 | + </SettingItem> | |
214 | + <SettingItem name="Token键"> | |
215 | + <n-input v-model:value.trim="requestTokenKey" type="text" placeholder="例如:X-Authorization" /> | |
216 | + </SettingItem> | |
217 | + </SettingItemBox> | |
68 | 218 | <NCollapseTransition :show="collapseHeaderTable"> |
69 | - <GlobalParamsConfiguration /> | |
219 | + <GlobalParamsConfiguration v-if="hasDefaultToken([verifiationValue])" /> | |
220 | + <n-input | |
221 | + v-else-if="hasTokenString([verifiationValue])" | |
222 | + v-model:value="tokenString" | |
223 | + type="text" | |
224 | + placeholder="请输入令牌字符串" | |
225 | + /> | |
226 | + <n-empty v-else description="无"> </n-empty> | |
227 | + <div style="margin-top: 10px"> | |
228 | + <n-space vertical> | |
229 | + <n-button type="primary" @click="handleExecuteRequest">执行请求</n-button> | |
230 | + <NCascader | |
231 | + v-model:value="resValue" | |
232 | + @update:value="handleResCascader" | |
233 | + :expand-trigger="cascaderConfig.hoverTrigger ? 'hover' : 'click'" | |
234 | + :check-strategy="cascaderConfig.checkStrategyIsChild ? 'child' : 'all'" | |
235 | + :show-path="cascaderConfig.showPath" | |
236 | + :filterable="cascaderConfig.filterable" | |
237 | + placeholder="请选择" | |
238 | + :options="resOptions" | |
239 | + /> | |
240 | + <n-input | |
241 | + :autosize="{ | |
242 | + minRows: 3, | |
243 | + maxRows: 9 | |
244 | + }" | |
245 | + v-model:value="getTokenString" | |
246 | + type="textarea" | |
247 | + placeholder="Token:" | |
248 | + /> | |
249 | + </n-space> | |
250 | + </div> | |
251 | + <!-- 针对第三方接口 --> | |
70 | 252 | </NCollapseTransition> |
71 | 253 | <section class="arrow"> |
72 | 254 | <NTooltip> |
... | ... | @@ -83,7 +265,6 @@ const themeColor = computed(() => { |
83 | 265 | </NCard> |
84 | 266 | </template> |
85 | 267 | |
86 | - | |
87 | 268 | <style lang="scss" scoped> |
88 | 269 | .arrow { |
89 | 270 | display: flex; |
... | ... | @@ -93,7 +274,6 @@ const themeColor = computed(() => { |
93 | 274 | |
94 | 275 | &:hover { |
95 | 276 | color: v-bind('themeColor'); |
96 | - | |
97 | 277 | } |
98 | 278 | } |
99 | 279 | </style> | ... | ... |
1 | -<script setup lang="ts" > | |
2 | -import { getUUID } from '@/utils'; | |
3 | -import { ButtonProps, DataTableColumns, InputProps, NButton, NDataTable, NIcon, NInput, NSpace, NTag, NTooltip, TagProps } from 'naive-ui'; | |
4 | -import { computed, h, ref, unref, watch } from 'vue'; | |
1 | +<script setup lang="ts"> | |
2 | +import { getUUID } from '@/utils' | |
3 | +import { | |
4 | + ButtonProps, | |
5 | + DataTableColumns, | |
6 | + InputProps, | |
7 | + NButton, | |
8 | + NDataTable, | |
9 | + NIcon, | |
10 | + NInput, | |
11 | + NSpace, | |
12 | + NTooltip, | |
13 | + NSelect, | |
14 | + SelectProps, | |
15 | + NDatePicker, | |
16 | + DatePickerProps | |
17 | +} from 'naive-ui' | |
18 | +import { computed, h, ref, unref, watch } from 'vue' | |
5 | 19 | import { Subtract, Add } from '@vicons/carbon' |
6 | -import { isObject } from '@/utils/external/is'; | |
20 | +import { isArray, isObject } from '@/utils/external/is' | |
21 | +import { DataTypeEnum, DataTypeNameEnum } from '@/enums/external/dataTypeEnum' | |
22 | +import { Recordable } from 'vite-plugin-mock' | |
7 | 23 | |
8 | 24 | interface DataSource { |
9 | 25 | id: string |
10 | 26 | value?: string |
11 | 27 | keyName?: string |
28 | + indexName?: number | |
29 | + typeName?: string | |
30 | + dateRange?: number[] | null | |
12 | 31 | result?: boolean |
13 | 32 | } |
14 | 33 | |
... | ... | @@ -17,99 +36,126 @@ const columns: DataTableColumns<DataSource> = [ |
17 | 36 | title: '序号', |
18 | 37 | key: 'index', |
19 | 38 | render: (_, index) => index + 1, |
20 | - width: 50, | |
39 | + width: 50 | |
40 | + }, | |
41 | + { | |
42 | + title: 'Type', | |
43 | + key: 'typeName', | |
44 | + render: (row, index) => { | |
45 | + return h(NSelect, { | |
46 | + value: row.typeName, | |
47 | + options: [ | |
48 | + { | |
49 | + label: DataTypeNameEnum.DATA_RANGE, | |
50 | + value: DataTypeEnum.DATA_RANGE | |
51 | + }, | |
52 | + { | |
53 | + label: DataTypeNameEnum.DATA_INPUT, | |
54 | + value: DataTypeEnum.DATA_INPUT | |
55 | + } | |
56 | + ], | |
57 | + onUpdateValue: (value: string) => { | |
58 | + unref(dataSource)[index].typeName = value | |
59 | + unref(dataSource)[index].indexName = index | |
60 | + }, | |
61 | + size: 'small', | |
62 | + disabled: props.disabled | |
63 | + } as SelectProps) | |
64 | + }, | |
65 | + width: 120 | |
21 | 66 | }, |
22 | 67 | { |
23 | 68 | title: 'Key', |
24 | 69 | key: 'keyName', |
25 | 70 | render: (row, index) => { |
26 | - return h( | |
27 | - NInput, | |
28 | - { | |
29 | - value: row.keyName, | |
30 | - onBlur: () => handleInputBlur(row), | |
31 | - onUpdateValue: (value: string) => unref(dataSource)[index].keyName = value, | |
32 | - size: 'small', | |
33 | - disabled: props.disabled | |
34 | - } as InputProps | |
35 | - ) | |
36 | - } | |
71 | + return h(NInput, { | |
72 | + value: row.keyName, | |
73 | + onBlur: () => handleInputBlur(), | |
74 | + onUpdateValue: (value: string) => (unref(dataSource)[index].keyName = value), | |
75 | + size: 'small', | |
76 | + disabled: props.disabled | |
77 | + } as InputProps) | |
78 | + }, | |
79 | + width: 120 | |
37 | 80 | }, |
38 | 81 | { |
39 | 82 | title: 'Value', |
40 | 83 | key: 'value', |
41 | 84 | render: (row, index) => { |
42 | - return h( | |
43 | - NInput, | |
44 | - { | |
45 | - value: row.value, | |
46 | - onBlur: () => handleInputBlur(row), | |
47 | - onUpdateValue: (value: string) => unref(dataSource)[index].value = value, | |
48 | - size: 'small', | |
49 | - disabled: props.disabled | |
50 | - } as InputProps | |
51 | - ) | |
52 | - } | |
85 | + const findIndexName = unref(dataSource).find(item => item.indexName === index) | |
86 | + return findIndexName?.indexName === index && findIndexName.typeName === DataTypeEnum.DATA_INPUT | |
87 | + ? h(NInput, { | |
88 | + value: row.value, | |
89 | + onBlur: () => handleInputBlur(), | |
90 | + onUpdateValue: (value: string) => (unref(dataSource)[index].value = value), | |
91 | + size: 'small', | |
92 | + disabled: props.disabled | |
93 | + } as InputProps) | |
94 | + : '' | |
95 | + }, | |
96 | + width: 120 | |
53 | 97 | }, |
54 | 98 | { |
55 | - title: '操作', | |
56 | - key: 'actions', | |
57 | - render: (row) => { | |
58 | - return h( | |
59 | - NSpace, | |
60 | - () => [ | |
61 | - h( | |
62 | - NTooltip, | |
63 | - null, | |
64 | - { | |
65 | - trigger: () => h( | |
66 | - NButton, | |
67 | - { | |
68 | - type: 'success', | |
69 | - size: 'small', | |
70 | - ghost: true, | |
71 | - onClick: () => handleAddRow(row), | |
72 | - disabled: props.disabled || !unref(canAddRow) | |
73 | - } as ButtonProps, | |
74 | - { | |
75 | - default: () => h(NIcon, () => h(Add)) | |
76 | - } | |
77 | - ), | |
78 | - default: () => '插入行' | |
79 | - } | |
80 | - ), | |
81 | - h( | |
82 | - NTooltip, | |
83 | - null, | |
84 | - { | |
85 | - trigger: () => h( | |
86 | - NButton, | |
87 | - { | |
88 | - type: 'warning', | |
89 | - size: 'small', | |
90 | - ghost: true, | |
91 | - onClick: () => handleSubtractRow(row), | |
92 | - // disabled: props.disabled || !unref(canDeleteRow) | |
93 | - } as ButtonProps, | |
94 | - { | |
95 | - default: () => h(NIcon, () => h(Subtract)) | |
96 | - } | |
97 | - ), | |
98 | - default: () => '删除行' | |
99 | - } | |
100 | - ) | |
101 | - ] | |
102 | - ) | |
99 | + title: 'Date', | |
100 | + key: 'dateRange', | |
101 | + render: (row, index) => { | |
102 | + const findIndexName = unref(dataSource).find(item => item.indexName === index) | |
103 | + return findIndexName?.indexName === index && findIndexName.typeName === DataTypeEnum.DATA_RANGE | |
104 | + ? h(NDatePicker, { | |
105 | + value: row.value, | |
106 | + size: 'small', | |
107 | + type: 'datetimerange', | |
108 | + onBlur: () => handleInputBlur(), | |
109 | + onUpdateValue: (value: number[]) => { | |
110 | + unref(dataSource)[index].dateRange = value | |
111 | + }, | |
112 | + disabled: props.disabled | |
113 | + } as DatePickerProps) | |
114 | + : '' | |
103 | 115 | }, |
104 | - width: 100, | |
116 | + width: 200 | |
105 | 117 | }, |
106 | 118 | { |
107 | - title: '结果', | |
108 | - key: 'result', | |
109 | - render: (row) => { | |
110 | - return h(NTag, { type: row.result ? 'success' : 'error' } as TagProps, () => `${row.result ? '' : '未'}通过`) | |
119 | + title: '操作', | |
120 | + key: 'actions', | |
121 | + render: row => { | |
122 | + return h(NSpace, () => [ | |
123 | + h(NTooltip, null, { | |
124 | + trigger: () => | |
125 | + h( | |
126 | + NButton, | |
127 | + { | |
128 | + type: 'success', | |
129 | + size: 'small', | |
130 | + ghost: true, | |
131 | + onClick: () => handleAddRow(row), | |
132 | + disabled: props.disabled || !unref(canAddRow) | |
133 | + } as ButtonProps, | |
134 | + { | |
135 | + default: () => h(NIcon, () => h(Add)) | |
136 | + } | |
137 | + ), | |
138 | + default: () => '插入行' | |
139 | + }), | |
140 | + h(NTooltip, null, { | |
141 | + trigger: () => | |
142 | + h( | |
143 | + NButton, | |
144 | + { | |
145 | + type: 'warning', | |
146 | + size: 'small', | |
147 | + ghost: true, | |
148 | + onClick: () => handleSubtractRow(row) | |
149 | + } as ButtonProps, | |
150 | + { | |
151 | + default: () => h(NIcon, () => h(Subtract)) | |
152 | + } | |
153 | + ), | |
154 | + default: () => '删除行' | |
155 | + }) | |
156 | + ]) | |
111 | 157 | }, |
112 | - width: 80 | |
158 | + width: 120 | |
113 | 159 | } |
114 | 160 | ] |
115 | 161 | |
... | ... | @@ -121,29 +167,33 @@ const props = withDefaults( |
121 | 167 | }>(), |
122 | 168 | { |
123 | 169 | disabled: false, |
124 | - maxRow: 50, | |
170 | + maxRow: 50 | |
125 | 171 | } |
126 | 172 | ) |
127 | 173 | |
128 | - | |
129 | 174 | const emit = defineEmits(['update:value']) |
130 | 175 | |
131 | 176 | const createNewRow = () => { |
132 | 177 | return { id: getUUID(), result: true } as DataSource |
133 | 178 | } |
134 | 179 | |
135 | -const dataSource = ref<DataSource[]>([ | |
136 | - createNewRow() | |
137 | -]) | |
180 | +const dataSource = ref<DataSource[]>([createNewRow()]) | |
181 | + | |
182 | +const blurFlag = ref(false) | |
138 | 183 | |
139 | 184 | watch( |
140 | 185 | () => props.value, |
141 | - (target) => { | |
186 | + (target: Recordable) => { | |
142 | 187 | if (target && isObject(target) && Object.keys(target).length) { |
143 | - dataSource.value = Object.keys(props.value || {}).map(keyName => ({ ...createNewRow(), keyName, value: Reflect.get(props.value || {}, keyName) })) | |
144 | - } else { | |
145 | - dataSource.value = [createNewRow()] | |
146 | - } | |
188 | + if (blurFlag.value) return | |
189 | + dataSource.value = Object.keys(props.value || {}).map((keyName, keyIndex) => ({ | |
190 | + ...createNewRow(), | |
191 | + keyName, | |
192 | + indexName: keyIndex, | |
193 | + typeName: isArray(props.value![keyName]) ? DataTypeEnum.DATA_RANGE : DataTypeEnum.DATA_INPUT, | |
194 | + value: Reflect.get(props.value || {}, keyName) | |
195 | + })) | |
196 | + } | |
147 | 197 | }, |
148 | 198 | { |
149 | 199 | immediate: true, |
... | ... | @@ -151,10 +201,6 @@ watch( |
151 | 201 | } |
152 | 202 | ) |
153 | 203 | |
154 | -const canDeleteRow = computed(() => { | |
155 | - return unref(dataSource).length >= 2 | |
156 | -}) | |
157 | - | |
158 | 204 | const canAddRow = computed(() => { |
159 | 205 | return unref(dataSource).length < props.maxRow |
160 | 206 | }) |
... | ... | @@ -174,23 +220,19 @@ const handleSubtractRow = (record: DataSource) => { |
174 | 220 | } |
175 | 221 | } |
176 | 222 | |
177 | - | |
178 | -const handleInputBlur = (record: DataSource) => { | |
179 | - const { keyName, value } = record | |
180 | - record.result = !!(keyName && value) | |
181 | - if (unref(dataSource).every(item => item.result)) { | |
182 | - emit('update:value', getHeaderConfiguration()) | |
183 | - } | |
223 | +const handleInputBlur = () => { | |
224 | + blurFlag.value = true | |
225 | + emit('update:value', getHeaderConfiguration()) | |
184 | 226 | } |
185 | 227 | |
186 | 228 | const getHeaderConfiguration = () => { |
187 | 229 | return unref(dataSource).reduce((prev, next) => { |
188 | - const { result, value, keyName } = next | |
189 | - const header = result && value && keyName ? { [keyName]: value } : {} | |
230 | + const { value, keyName, dateRange } = next | |
231 | + const header = keyName ? { [keyName as unknown as string]: dateRange && isArray(dateRange) ? dateRange: value } : {} | |
232 | + for (let item in header) if (!Reflect.get(header, item)) Reflect.deleteProperty(header, item) | |
190 | 233 | return { ...prev, ...header } |
191 | 234 | }, {} as Recordable) |
192 | 235 | } |
193 | - | |
194 | 236 | </script> |
195 | 237 | |
196 | 238 | <template> | ... | ... |
1 | 1 | <script lang="ts" setup> |
2 | -import { RequestDataTypeEnum, RequestDataTypeNameEnum } from '@/enums/external/httpEnum'; | |
3 | -import { useDesign } from '@/hooks/external/useDesign'; | |
4 | -import { CreateComponentType } from '@/packages/index.d'; | |
5 | -import { CreateComponentGroupType } from '@/packages/index.d'; | |
6 | -import { RequestConfigType } from '@/store/modules/chartEditStore/chartEditStore.d'; | |
7 | -import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'; | |
8 | -import { NButton, NDivider, NModal, NSpace, NTag } from 'naive-ui'; | |
9 | -import { ref, unref, computed, nextTick } from 'vue'; | |
10 | -import { PublicInterfaceForm } from '../PublicInterfaceForm'; | |
11 | -import ComponentConfiguration from './ComponentConfiguration.vue'; | |
12 | -import GlobalPublicConfiguration from './GlobalPublicConfiguration.vue'; | |
13 | -import { createRequestModalContext } from './useRequestModalContext'; | |
14 | -import { useTargetData } from '../../../../hooks/useTargetData.hook'; | |
15 | -import { useFetchTargetData } from '@/hooks/external/useFetchTargetData'; | |
16 | -import { useFilterFn } from '@/hooks/external/useFilterFn'; | |
17 | - | |
2 | +import { RequestDataTypeEnum, RequestDataTypeNameEnum } from '@/enums/external/httpEnum' | |
3 | +import { useDesign } from '@/hooks/external/useDesign' | |
4 | +import { CreateComponentType } from '@/packages/index.d' | |
5 | +import { CreateComponentGroupType } from '@/packages/index.d' | |
6 | +import { RequestConfigType } from '@/store/modules/chartEditStore/chartEditStore.d' | |
7 | +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' | |
8 | +import { NButton, NDivider, NModal, NSpace, NTag } from 'naive-ui' | |
9 | +import { ref, unref, computed, nextTick } from 'vue' | |
10 | +import { PublicInterfaceForm } from '../PublicInterfaceForm' | |
11 | +import ComponentConfiguration from './ComponentConfiguration.vue' | |
12 | +import GlobalPublicConfiguration from './GlobalPublicConfiguration.vue' | |
13 | +import { createRequestModalContext } from './useRequestModalContext' | |
14 | +import { useTargetData } from '../../../../hooks/useTargetData.hook' | |
15 | +import { useFetchTargetData } from '@/hooks/external/useFetchTargetData' | |
16 | +import { useFilterFn } from '@/hooks/external/useFilterFn' | |
18 | 17 | |
19 | 18 | const requestDataType = ref<RequestDataTypeEnum>(RequestDataTypeEnum.AJAX) |
20 | 19 | |
... | ... | @@ -84,12 +83,22 @@ const sendHandle = async () => { |
84 | 83 | targetData.value.option.dataset = value |
85 | 84 | return |
86 | 85 | } |
86 | +} | |
87 | 87 | |
88 | +const setRequestKey = (value: Recordable, key: string) => { | |
89 | + value[key] = | |
90 | + targetData.value.request.requestDataType === RequestDataTypeEnum.AJAX | |
91 | + ? (targetData.value.request as unknown as Recordable)[key] || | |
92 | + (chartEditStore.getRequestGlobalConfig as unknown as Recordable)[key] | |
93 | + : null | |
88 | 94 | } |
89 | 95 | |
90 | 96 | const handleSaveAction = async () => { |
91 | 97 | if (!(await validate())) return |
92 | 98 | const value = getResult() |
99 | + setRequestKey(value, 'requestTokenSuffix') | |
100 | + setRequestKey(value, 'requestTokenKey') | |
101 | + setRequestKey(value, 'requestVerificationToken') | |
93 | 102 | if (unref(selectTarget)) { |
94 | 103 | chartEditStore.updateComponentList(chartEditStore.fetchTargetIndex(), { |
95 | 104 | ...unref(selectTarget)!, |
... | ... | @@ -105,26 +114,29 @@ createRequestModalContext({ |
105 | 114 | }) |
106 | 115 | |
107 | 116 | defineExpose({ |
108 | - openModal, | |
117 | + openModal | |
109 | 118 | }) |
110 | - | |
111 | 119 | </script> |
112 | 120 | |
113 | 121 | <template> |
114 | - <NModal :class="prefixCls" v-model:show="showModal" preset="card" style="width: 1000px;" title="请求配置"> | |
122 | + <NModal :class="prefixCls" v-model:show="showModal" preset="card" style="width: 1000px" title="请求配置"> | |
115 | 123 | <GlobalPublicConfiguration v-if="requestDataType === RequestDataTypeEnum.AJAX" /> |
116 | 124 | <NDivider v-if="requestDataType === RequestDataTypeEnum.AJAX" /> |
117 | 125 | <ComponentConfiguration v-if="requestDataType === RequestDataTypeEnum.AJAX" ref="componentConfigurationEl" /> |
118 | 126 | <PublicInterfaceForm v-if="requestDataType === RequestDataTypeEnum.Pond" ref="publicInterfaceFormEl" /> |
119 | 127 | <template #action> |
120 | - <NSpace justify="space-between"> | |
121 | - <div style="display: flex;flex-direction: column;"> | |
122 | - <NTag type="info">当公共接口选择“实时轨迹或者获取设备经纬度历史数据”时,属性选择则选择经纬度即可(longitude,latitude)</NTag> | |
123 | - <div style="height:5px"></div> | |
124 | - <NTag type="info">如果是结构体属性的话,选择对应结构体属性即可,里面的经纬度,平台已经通过接口里面的过滤函数进行处理</NTag> | |
125 | - <div style="display: flex; align-items: center; margin-top:10px"> | |
128 | + <NSpace justify="space-between"> | |
129 | + <div style="display: flex; flex-direction: column"> | |
130 | + <NTag type="info" | |
131 | + >当公共接口选择“实时轨迹或者获取设备经纬度历史数据”时,属性选择则选择经纬度即可(longitude,latitude)</NTag | |
132 | + > | |
133 | + <div style="height: 5px"></div> | |
134 | + <NTag type="info" | |
135 | + >如果是结构体属性的话,选择对应结构体属性即可,里面的经纬度,平台已经通过接口里面的过滤函数进行处理</NTag | |
136 | + > | |
137 | + <div style="display: flex; align-items: center; margin-top: 10px"> | |
126 | 138 | <span>「 更多 」</span> |
127 | - <span style="margin-right: 5px;">——</span> | |
139 | + <span style="margin-right: 5px">——</span> | |
128 | 140 | <NTag type="info">{{ getRequestTypeName }}</NTag> |
129 | 141 | </div> |
130 | 142 | </div> |
... | ... | @@ -134,10 +146,8 @@ defineExpose({ |
134 | 146 | </NModal> |
135 | 147 | </template> |
136 | 148 | |
137 | - | |
138 | -<style lang="scss" > | |
149 | +<style lang="scss"> | |
139 | 150 | @include thingsKit('chart-data-request') { |
140 | - | |
141 | 151 | &.n-card.n-modal, |
142 | 152 | .n-card { |
143 | 153 | @extend .go-background-filter; |
... | ... | @@ -148,7 +158,7 @@ defineExpose({ |
148 | 158 | } |
149 | 159 | |
150 | 160 | @include deep() { |
151 | - &>.n-card__content { | |
161 | + & > .n-card__content { | |
152 | 162 | padding-right: 0; |
153 | 163 | } |
154 | 164 | ... | ... |
... | ... | @@ -23,6 +23,9 @@ export interface RequestOptions { |
23 | 23 | withToken?: boolean; |
24 | 24 | // Carry and share token 携带分享的访问令牌 |
25 | 25 | withShareToken?: boolean |
26 | + withThirdTokenString?: string; | |
27 | + withThirdTokenKey?: string; | |
28 | + withThirdTokenPrefix?: string; | |
26 | 29 | } |
27 | 30 | |
28 | 31 | export interface Result<T = any> { | ... | ... |