verce-vue-test 0.0.30 → 0.0.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/mini2.0-main/src/core/mxApi/index.ts +107 -46
- package/mini2.0-main/src/core/request/index.ts +239 -25
- package/package.json +1 -1
- package/src/views/FundCockpitView.vue +242 -361
|
@@ -10,19 +10,23 @@
|
|
|
10
10
|
// ============================================================
|
|
11
11
|
|
|
12
12
|
/** 原生 AJAX 请求参数 */
|
|
13
|
-
interface MXAjaxParams {
|
|
13
|
+
export interface MXAjaxParams {
|
|
14
14
|
type: 'GET' | 'POST' | 'PUT' | 'DELETE'
|
|
15
15
|
url: string
|
|
16
|
-
|
|
16
|
+
dataType?: string
|
|
17
17
|
async?: boolean
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
data?: unknown
|
|
19
|
+
headers?: Record<string, string>
|
|
20
|
+
complete?: () => void
|
|
21
|
+
success?: (data: unknown, status?: number, xhr?: unknown) => void
|
|
22
|
+
error?: (data: unknown, status?: number, xhr?: unknown) => void
|
|
20
23
|
}
|
|
21
24
|
|
|
22
25
|
/** 原生 AJAX 响应 */
|
|
23
26
|
export interface MXAjaxResponse<T = unknown> {
|
|
24
27
|
data: T
|
|
25
|
-
status
|
|
28
|
+
status?: number
|
|
29
|
+
xhr?: unknown
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
/** 用户信息 */
|
|
@@ -47,7 +51,7 @@ interface MXApiCallbacks {
|
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
/** 原生接口命名空间 */
|
|
50
|
-
type MXNamespace = 'MXCommon' | 'MXWebui' | 'MXContacts'
|
|
54
|
+
type MXNamespace = 'MXCommon' | 'NXCommon' | 'MXWebui' | 'MXContacts'
|
|
51
55
|
|
|
52
56
|
// ============================================================
|
|
53
57
|
// 声明全局原生接口
|
|
@@ -60,6 +64,9 @@ declare global {
|
|
|
60
64
|
getEncryptString: (callback: (secret: string) => void) => void
|
|
61
65
|
ajax: (params: MXAjaxParams) => void
|
|
62
66
|
}
|
|
67
|
+
NXCommon?: {
|
|
68
|
+
ajax: (params: MXAjaxParams) => void
|
|
69
|
+
}
|
|
63
70
|
MXWebui?: {
|
|
64
71
|
hideWebViewTitle: () => void
|
|
65
72
|
showOptionMenu: () => void
|
|
@@ -144,6 +151,7 @@ const makeApi =
|
|
|
144
151
|
applyApi(namespace, api, args)
|
|
145
152
|
|
|
146
153
|
const MXCommon = makeApi('MXCommon')
|
|
154
|
+
const NXCommon = makeApi('NXCommon')
|
|
147
155
|
const MXWebui = makeApi('MXWebui')
|
|
148
156
|
const MXContacts = makeApi('MXContacts')
|
|
149
157
|
|
|
@@ -217,58 +225,111 @@ export const MXSelectUsers = (
|
|
|
217
225
|
* 原生 AJAX 请求
|
|
218
226
|
*
|
|
219
227
|
* 使用原生应用的 HTTP 客户端发起请求,绕过浏览器同源策略限制。
|
|
220
|
-
* ajax
|
|
228
|
+
* NXCommon.ajax 只支持回调,不返回 Promise。
|
|
221
229
|
*/
|
|
222
|
-
export const ajax =
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const timeout = new Promise<MXAjaxResponse<T>>((_, reject) =>
|
|
240
|
-
setTimeout(() => reject(new Error(`[MX] ajax ${params.type} ${params.url} 超时`)), 15000),
|
|
241
|
-
)
|
|
230
|
+
export const ajax = (params: MXAjaxParams): void => {
|
|
231
|
+
const requestParams: MXAjaxParams = {
|
|
232
|
+
...params,
|
|
233
|
+
url: normalizeAjaxUrl(params.url),
|
|
234
|
+
async: params.async ?? true,
|
|
235
|
+
dataType: params.dataType ?? 'text',
|
|
236
|
+
complete() {
|
|
237
|
+
params.complete?.()
|
|
238
|
+
},
|
|
239
|
+
success(data, status, xhr) {
|
|
240
|
+
params.success?.(data, status, xhr)
|
|
241
|
+
},
|
|
242
|
+
error(data, status, xhr) {
|
|
243
|
+
params.error?.(data, status, xhr)
|
|
244
|
+
},
|
|
245
|
+
}
|
|
242
246
|
|
|
243
|
-
|
|
247
|
+
callNativeAjax(requestParams)
|
|
244
248
|
}
|
|
245
249
|
|
|
246
250
|
/** 原生 GET 请求 */
|
|
247
|
-
export const ajaxGet =
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
return ajax<T>({
|
|
251
|
+
export const ajaxGet = (
|
|
252
|
+
url: string,
|
|
253
|
+
query?: Record<string, unknown>,
|
|
254
|
+
options?: Pick<MXAjaxParams, 'headers' | 'complete' | 'dataType' | 'success' | 'error'>,
|
|
255
|
+
): void =>
|
|
256
|
+
ajax({
|
|
257
|
+
...options,
|
|
256
258
|
type: 'GET',
|
|
257
|
-
url:
|
|
259
|
+
url: appendQuery(url, query),
|
|
258
260
|
})
|
|
259
|
-
}
|
|
260
261
|
|
|
261
262
|
/** 原生 POST 请求 */
|
|
262
|
-
export const ajaxPost =
|
|
263
|
-
|
|
263
|
+
export const ajaxPost = (
|
|
264
|
+
url: string,
|
|
265
|
+
data?: unknown,
|
|
266
|
+
options?: Pick<MXAjaxParams, 'headers' | 'complete' | 'dataType' | 'success' | 'error'>,
|
|
267
|
+
): void =>
|
|
268
|
+
ajax({ ...options, type: 'POST', url, data })
|
|
264
269
|
|
|
265
270
|
/** 原生 PUT 请求 */
|
|
266
|
-
export const ajaxPut =
|
|
267
|
-
|
|
271
|
+
export const ajaxPut = (
|
|
272
|
+
url: string,
|
|
273
|
+
data?: unknown,
|
|
274
|
+
options?: Pick<MXAjaxParams, 'headers' | 'complete' | 'dataType' | 'success' | 'error'>,
|
|
275
|
+
): void =>
|
|
276
|
+
ajax({ ...options, type: 'PUT', url, data })
|
|
268
277
|
|
|
269
278
|
/** 原生 DELETE 请求 */
|
|
270
|
-
export const ajaxDelete =
|
|
271
|
-
|
|
279
|
+
export const ajaxDelete = (
|
|
280
|
+
url: string,
|
|
281
|
+
data?: unknown,
|
|
282
|
+
options?: Pick<MXAjaxParams, 'headers' | 'complete' | 'dataType' | 'success' | 'error'>,
|
|
283
|
+
): void =>
|
|
284
|
+
ajax({
|
|
285
|
+
...options,
|
|
286
|
+
type: 'DELETE',
|
|
287
|
+
url: typeof data === 'string' || typeof data === 'number'
|
|
288
|
+
? `${url.replace(/\/+$/, '')}/${encodeURIComponent(String(data))}`
|
|
289
|
+
: url,
|
|
290
|
+
data: typeof data === 'string' || typeof data === 'number' ? undefined : data,
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
function callNativeAjax(params: MXAjaxParams): void {
|
|
294
|
+
if (window.NXCommon?.ajax) {
|
|
295
|
+
NXCommon('ajax', params)
|
|
296
|
+
return
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
MXCommon('ajax', params)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function normalizeAjaxUrl(url: string): string {
|
|
303
|
+
if (/^[a-z][a-z\d+\-.]*:\/\//i.test(url)) return url
|
|
304
|
+
|
|
305
|
+
const baseURL = import.meta.env.VITE_API_BASE_URL || ''
|
|
306
|
+
if (!baseURL) return url
|
|
307
|
+
|
|
308
|
+
return `${baseURL.replace(/\/+$/, '')}/${url.replace(/^\/+/, '')}`
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function appendQuery(url: string, query?: Record<string, unknown>): string {
|
|
312
|
+
if (!query) return url
|
|
313
|
+
|
|
314
|
+
const searchParams = new URLSearchParams()
|
|
315
|
+
Object.entries(query).forEach(([key, value]) => {
|
|
316
|
+
if (value === undefined || value === null) return
|
|
317
|
+
if (Array.isArray(value)) {
|
|
318
|
+
value.forEach((item) => {
|
|
319
|
+
if (item !== undefined && item !== null) {
|
|
320
|
+
searchParams.append(key, String(item))
|
|
321
|
+
}
|
|
322
|
+
})
|
|
323
|
+
return
|
|
324
|
+
}
|
|
325
|
+
searchParams.append(key, String(value))
|
|
326
|
+
})
|
|
327
|
+
|
|
328
|
+
const queryString = searchParams.toString()
|
|
329
|
+
if (!queryString) return url
|
|
330
|
+
|
|
331
|
+
return `${url}${url.includes('?') ? '&' : '?'}${queryString}`
|
|
332
|
+
}
|
|
272
333
|
|
|
273
334
|
let nativeReady = false
|
|
274
335
|
let resolveNativeReady: (() => void) | null = null
|
|
@@ -299,4 +360,4 @@ export const whenNativeReady = (): Promise<boolean> => {
|
|
|
299
360
|
|
|
300
361
|
/** 检测是否在原生环境(需在 deviceready 之后调用才准确) */
|
|
301
362
|
export const isNativeApp = (): boolean =>
|
|
302
|
-
typeof window.MXCommon !== 'undefined'
|
|
363
|
+
typeof window.MXCommon !== 'undefined' || typeof window.NXCommon !== 'undefined'
|
|
@@ -5,10 +5,13 @@
|
|
|
5
5
|
* 根据环境自动选择 axios 或原生 AJAX
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { isNativeApp,
|
|
9
|
-
import type { MXAjaxResponse } from '@/core/mxApi'
|
|
8
|
+
import { isNativeApp, ajax } from '@/core/mxApi'
|
|
9
|
+
import type { MXAjaxParams, MXAjaxResponse } from '@/core/mxApi'
|
|
10
10
|
import { request as axiosRequest } from '@/utils/request'
|
|
11
11
|
import type { ApiResponse } from '@/types/api'
|
|
12
|
+
import { showToast } from 'vant'
|
|
13
|
+
import NProgress from 'nprogress'
|
|
14
|
+
import router from '@/router'
|
|
12
15
|
|
|
13
16
|
// ============================================================
|
|
14
17
|
// Token 管理
|
|
@@ -79,6 +82,10 @@ export async function request<R = unknown, T = unknown>(
|
|
|
79
82
|
...customHeaders,
|
|
80
83
|
}
|
|
81
84
|
|
|
85
|
+
if (auth && !headers.Authorization) {
|
|
86
|
+
headers.Authorization = `Basic ${window.btoa(`${auth.username}:${auth.password}`)}`
|
|
87
|
+
}
|
|
88
|
+
|
|
82
89
|
|
|
83
90
|
if (isNativeApp()) {
|
|
84
91
|
return await nativeRequest<R, T>({ url, method, data, params, headers })
|
|
@@ -98,32 +105,239 @@ export async function request<R = unknown, T = unknown>(
|
|
|
98
105
|
async function nativeRequest<R, T>(
|
|
99
106
|
config: RequestConfig<T>
|
|
100
107
|
): Promise<ApiResponse<R>> {
|
|
101
|
-
const { url, method, data, params } = config
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
108
|
+
const { url, method, data, params, headers } = config
|
|
109
|
+
|
|
110
|
+
NProgress.start()
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
const options = { headers, dataType: 'text' }
|
|
114
|
+
let response: MXAjaxResponse<ApiResponse<R>>
|
|
115
|
+
|
|
116
|
+
switch (method) {
|
|
117
|
+
case 'GET':
|
|
118
|
+
response = await nativeAjax<ApiResponse<R>>({
|
|
119
|
+
...options,
|
|
120
|
+
type: 'GET',
|
|
121
|
+
url: appendQuery(url, params),
|
|
122
|
+
})
|
|
123
|
+
break
|
|
124
|
+
case 'POST':
|
|
125
|
+
response = await nativeAjax<ApiResponse<R>>({
|
|
126
|
+
...options,
|
|
127
|
+
type: 'POST',
|
|
128
|
+
url,
|
|
129
|
+
data,
|
|
130
|
+
})
|
|
131
|
+
break
|
|
132
|
+
case 'PUT':
|
|
133
|
+
response = await nativeAjax<ApiResponse<R>>({
|
|
134
|
+
...options,
|
|
135
|
+
type: 'PUT',
|
|
136
|
+
url,
|
|
137
|
+
data,
|
|
138
|
+
})
|
|
139
|
+
break
|
|
140
|
+
case 'DELETE':
|
|
141
|
+
response = await nativeAjax<ApiResponse<R>>({
|
|
142
|
+
...options,
|
|
143
|
+
type: 'DELETE',
|
|
144
|
+
url: appendDeleteParams(url, params),
|
|
145
|
+
data,
|
|
146
|
+
})
|
|
147
|
+
break
|
|
148
|
+
default:
|
|
149
|
+
throw new Error(`不支持的请求方法: ${method}`)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const result = normalizeNativeResponse<R>(response)
|
|
153
|
+
|
|
154
|
+
if (result.code !== 0) {
|
|
155
|
+
showToast(result.message || '请求失败')
|
|
156
|
+
|
|
157
|
+
if (result.code === 401) {
|
|
158
|
+
clearToken()
|
|
159
|
+
router.push('/login')
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const error = new Error(result.message || '请求失败') as Error & { handled?: boolean }
|
|
163
|
+
error.handled = true
|
|
164
|
+
throw error
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return result
|
|
168
|
+
} catch (error) {
|
|
169
|
+
const nativeError = error as Error & { status?: number; data?: unknown; handled?: boolean }
|
|
170
|
+
if (nativeError.handled) {
|
|
171
|
+
throw error
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const status = nativeError.status
|
|
175
|
+
const statusCodeMap: Record<number, string> = {
|
|
176
|
+
400: '请求参数错误',
|
|
177
|
+
401: '未授权,请重新登录',
|
|
178
|
+
403: '拒绝访问',
|
|
179
|
+
404: '请求资源不存在',
|
|
180
|
+
500: '服务器内部错误',
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
showToast(status ? statusCodeMap[status] || `连接错误 ${status}` : nativeError.message || '网络连接异常')
|
|
184
|
+
|
|
185
|
+
if (status === 401) {
|
|
186
|
+
clearToken()
|
|
187
|
+
router.push('/login')
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
throw error
|
|
191
|
+
} finally {
|
|
192
|
+
NProgress.done()
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function normalizeNativeResponse<R>(response: MXAjaxResponse<unknown>): ApiResponse<R> {
|
|
197
|
+
const data = response.data
|
|
198
|
+
|
|
199
|
+
if (isApiResponse<R>(data)) {
|
|
200
|
+
return data
|
|
121
201
|
}
|
|
122
202
|
|
|
123
|
-
// 包装成与 axios 拦截器一致的响应格式
|
|
124
203
|
return {
|
|
125
204
|
code: 0,
|
|
126
205
|
message: 'success',
|
|
127
|
-
data:
|
|
128
|
-
}
|
|
206
|
+
data: data as R,
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function isApiResponse<R>(value: unknown): value is ApiResponse<R> {
|
|
211
|
+
return typeof value === 'object'
|
|
212
|
+
&& value !== null
|
|
213
|
+
&& typeof (value as ApiResponse<R>).code === 'number'
|
|
214
|
+
&& 'data' in value
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function appendDeleteParams(url: string, params?: Record<string, unknown>): string {
|
|
218
|
+
if (!params) return url
|
|
219
|
+
|
|
220
|
+
const { id, ...rest } = params
|
|
221
|
+
const targetUrl = id === undefined || id === null
|
|
222
|
+
? url
|
|
223
|
+
: `${url.replace(/\/+$/, '')}/${encodeURIComponent(String(id))}`
|
|
224
|
+
|
|
225
|
+
const query = new URLSearchParams()
|
|
226
|
+
Object.entries(rest).forEach(([key, value]) => {
|
|
227
|
+
if (value === undefined || value === null) return
|
|
228
|
+
query.append(key, String(value))
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
const queryString = query.toString()
|
|
232
|
+
if (!queryString) return targetUrl
|
|
233
|
+
|
|
234
|
+
return `${targetUrl}${targetUrl.includes('?') ? '&' : '?'}${queryString}`
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function nativeAjax<T>(params: MXAjaxParams & { timeout?: number }): Promise<MXAjaxResponse<T>> {
|
|
238
|
+
const { timeout = 15000, ...ajaxParams } = params
|
|
239
|
+
|
|
240
|
+
return new Promise((resolve, reject) => {
|
|
241
|
+
let settled = false
|
|
242
|
+
const timer = window.setTimeout(() => {
|
|
243
|
+
if (settled) return
|
|
244
|
+
settled = true
|
|
245
|
+
reject(new Error(`[MX] ajax ${ajaxParams.type} ${ajaxParams.url} 超时(${timeout}ms)`))
|
|
246
|
+
}, timeout)
|
|
247
|
+
|
|
248
|
+
const settle = (callback: () => void) => {
|
|
249
|
+
if (settled) return
|
|
250
|
+
settled = true
|
|
251
|
+
window.clearTimeout(timer)
|
|
252
|
+
callback()
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
ajax({
|
|
256
|
+
...ajaxParams,
|
|
257
|
+
success(data, status, xhr) {
|
|
258
|
+
settle(() => {
|
|
259
|
+
ajaxParams.success?.(data, status, xhr)
|
|
260
|
+
resolve({
|
|
261
|
+
data: parseAjaxData<T>(data, ajaxParams.dataType),
|
|
262
|
+
status,
|
|
263
|
+
xhr,
|
|
264
|
+
})
|
|
265
|
+
})
|
|
266
|
+
},
|
|
267
|
+
error(data, status, xhr) {
|
|
268
|
+
settle(() => {
|
|
269
|
+
ajaxParams.error?.(data, status, xhr)
|
|
270
|
+
reject(createNativeAjaxError(data, status, xhr, ajaxParams))
|
|
271
|
+
})
|
|
272
|
+
},
|
|
273
|
+
complete() {
|
|
274
|
+
ajaxParams.complete?.()
|
|
275
|
+
},
|
|
276
|
+
})
|
|
277
|
+
})
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function appendQuery(url: string, query?: Record<string, unknown>): string {
|
|
281
|
+
if (!query) return url
|
|
282
|
+
|
|
283
|
+
const searchParams = new URLSearchParams()
|
|
284
|
+
Object.entries(query).forEach(([key, value]) => {
|
|
285
|
+
if (value === undefined || value === null) return
|
|
286
|
+
if (Array.isArray(value)) {
|
|
287
|
+
value.forEach((item) => {
|
|
288
|
+
if (item !== undefined && item !== null) {
|
|
289
|
+
searchParams.append(key, String(item))
|
|
290
|
+
}
|
|
291
|
+
})
|
|
292
|
+
return
|
|
293
|
+
}
|
|
294
|
+
searchParams.append(key, String(value))
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
const queryString = searchParams.toString()
|
|
298
|
+
if (!queryString) return url
|
|
299
|
+
|
|
300
|
+
return `${url}${url.includes('?') ? '&' : '?'}${queryString}`
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function parseAjaxData<T>(data: unknown, dataType?: string): T {
|
|
304
|
+
if (dataType === 'text') {
|
|
305
|
+
return parseJsonString(data) as T
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (typeof data !== 'string') return data as T
|
|
309
|
+
|
|
310
|
+
return parseJsonString(data) as T
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function parseJsonString(data: unknown): unknown {
|
|
314
|
+
if (typeof data !== 'string') return data
|
|
315
|
+
|
|
316
|
+
const trimmed = data.trim()
|
|
317
|
+
if (!trimmed) return undefined
|
|
318
|
+
|
|
319
|
+
try {
|
|
320
|
+
return JSON.parse(trimmed)
|
|
321
|
+
} catch {
|
|
322
|
+
return data
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function createNativeAjaxError(
|
|
327
|
+
data: unknown,
|
|
328
|
+
status: number | undefined,
|
|
329
|
+
xhr: unknown,
|
|
330
|
+
params: Omit<MXAjaxParams, 'success' | 'error'>,
|
|
331
|
+
): Error & { data: unknown; status?: number; xhr?: unknown } {
|
|
332
|
+
const parsedData = parseAjaxData(data, params.dataType)
|
|
333
|
+
const message = typeof parsedData === 'object' && parsedData && 'message' in parsedData
|
|
334
|
+
? String((parsedData as { message?: unknown }).message || '请求失败')
|
|
335
|
+
: typeof parsedData === 'string'
|
|
336
|
+
? parsedData
|
|
337
|
+
: '请求失败'
|
|
338
|
+
const error = new Error(message) as Error & { data: unknown; status?: number; xhr?: unknown }
|
|
339
|
+
error.data = parsedData
|
|
340
|
+
error.status = status
|
|
341
|
+
error.xhr = xhr
|
|
342
|
+
return error
|
|
129
343
|
}
|