zentao-api 0.1.0 → 0.2.0-beta.1
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/LICENSE +2 -2
- package/README.md +103 -147
- package/dist/browser/zentao-api.global.js +1 -0
- package/dist/browser.d.ts +1 -0
- package/dist/browser.js +1 -0
- package/dist/client/index.d.ts +37 -0
- package/dist/client/index.js +149 -0
- package/dist/index.d.ts +7 -4
- package/dist/index.js +6 -8
- package/dist/misc/browser-global.d.ts +1 -0
- package/dist/misc/browser-global.js +8 -0
- package/dist/misc/environment.d.ts +6 -0
- package/dist/misc/environment.js +30 -0
- package/dist/misc/errors.d.ts +25 -0
- package/dist/misc/errors.js +35 -0
- package/dist/misc/global-options.d.ts +5 -0
- package/dist/misc/global-options.js +9 -0
- package/dist/modules/generated.d.ts +8 -0
- package/dist/modules/generated.js +4226 -0
- package/dist/modules/registry.d.ts +22 -0
- package/dist/modules/registry.js +129 -0
- package/dist/modules/resolve.d.ts +7 -0
- package/dist/modules/resolve.js +196 -0
- package/dist/request/index.d.ts +7 -0
- package/dist/request/index.js +65 -0
- package/dist/types/index.d.ts +235 -0
- package/dist/types/index.js +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +14 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +4 -0
- package/package.json +43 -77
- package/dist/types.d.ts +0 -70
- package/dist/utils.d.ts +0 -93
- package/dist/zentao-api.cjs.development.js +0 -3619
- package/dist/zentao-api.cjs.development.js.map +0 -1
- package/dist/zentao-api.cjs.production.min.js +0 -2
- package/dist/zentao-api.cjs.production.min.js.map +0 -1
- package/dist/zentao-api.esm.js +0 -3611
- package/dist/zentao-api.esm.js.map +0 -1
- package/dist/zentao-config.d.ts +0 -93
- package/dist/zentao-request-builder.d.ts +0 -120
- package/dist/zentao.d.ts +0 -175
- package/dist/zentao12.d.ts +0 -676
- package/src/index.ts +0 -5
- package/src/types.ts +0 -88
- package/src/utils.ts +0 -216
- package/src/zentao-config.ts +0 -150
- package/src/zentao-request-builder.ts +0 -227
- package/src/zentao.ts +0 -596
- package/src/zentao12.ts +0 -1272
package/src/zentao.ts
DELETED
|
@@ -1,596 +0,0 @@
|
|
|
1
|
-
import axios, {AxiosResponse} from 'axios';
|
|
2
|
-
import Configstore from 'configstore';
|
|
3
|
-
import kleur from 'kleur';
|
|
4
|
-
import querystring from 'querystring';
|
|
5
|
-
import {
|
|
6
|
-
ZentaoApiResult,
|
|
7
|
-
ZentaoOptions,
|
|
8
|
-
ZentaoRequestMethod,
|
|
9
|
-
ZentaoRequestParamPair,
|
|
10
|
-
ZentaoRequestParams,
|
|
11
|
-
ZentaoRequestType,
|
|
12
|
-
} from './types';
|
|
13
|
-
import {formatZentaoUrl, normalizeRequestParams, slimmingObject} from './utils';
|
|
14
|
-
import ZentaoConfig from './zentao-config';
|
|
15
|
-
import ZentaoRequestBuilder from './zentao-request-builder';
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* 禅道请求类
|
|
19
|
-
*
|
|
20
|
-
* @example
|
|
21
|
-
* import { Zentao } from 'zentao-api';
|
|
22
|
-
* const zentao = new Zentao({
|
|
23
|
-
* url: 'https://pro.demo.zentao.net/', account: 'demo', password: '123456'
|
|
24
|
-
* });
|
|
25
|
-
* // TODO: 使用 zentao 调用其他 API
|
|
26
|
-
*/
|
|
27
|
-
export default class Zentao {
|
|
28
|
-
/**
|
|
29
|
-
* 当前服务器和登录账号标识字符串
|
|
30
|
-
*/
|
|
31
|
-
private readonly _identifier: string;
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* 是否将 token 存储到本地,如果设置为 `false`,则每次创建新的 `Zentao` 实例都会在首次调用 API 之前重新获取 Token
|
|
35
|
-
*/
|
|
36
|
-
private readonly _preserveToken: boolean;
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* 当前实例名称
|
|
40
|
-
*/
|
|
41
|
-
private readonly _sessionName: string;
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* 禅道服务器地址
|
|
45
|
-
*/
|
|
46
|
-
private readonly _url: string;
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* 登录账号
|
|
50
|
-
*/
|
|
51
|
-
private readonly _account: string;
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* 登录密码
|
|
55
|
-
*/
|
|
56
|
-
private readonly _password: string;
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* 如果设置为 `true`,则会在控制台输出详细日志
|
|
60
|
-
*/
|
|
61
|
-
private _debug: boolean;
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* 禅道配置
|
|
65
|
-
*/
|
|
66
|
-
private _config?: ZentaoConfig;
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* 本地存储管理对象
|
|
70
|
-
*/
|
|
71
|
-
private _store?: Configstore;
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* 用户指定的请求方式
|
|
75
|
-
*/
|
|
76
|
-
private _userRequestType?: ZentaoRequestType;
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* 构造一个禅道 API 请求对象
|
|
80
|
-
* @param {ZentaoOptions} [options] 选项,用于指定服务器地址、账号和密码以及 API 调用相关设置
|
|
81
|
-
* @example
|
|
82
|
-
* import { Zentao } from 'zentao-api';
|
|
83
|
-
* const zentao = new Zentao({
|
|
84
|
-
* url: 'https://pro.demo.zentao.net/', // 禅道服务器地址
|
|
85
|
-
* account: 'demo', // 用户账号
|
|
86
|
-
* password: '123456', // 用户密码
|
|
87
|
-
* accessMode: 'GET', // 请求方式
|
|
88
|
-
* preserveToken: true, // 是否将 token 存储到本地,如果设置为 `false`,则每次创建新的 `Zentao` 实例都会在首次调用 API 之前重新获取 Token
|
|
89
|
-
* debug: true, // 如果设置为 `true`,则会在控制台输出详细日志
|
|
90
|
-
* });
|
|
91
|
-
* // TODO: 使用 zentao 调用其他 API
|
|
92
|
-
*/
|
|
93
|
-
constructor(options: ZentaoOptions) {
|
|
94
|
-
this._debug = options.debug ?? false;
|
|
95
|
-
|
|
96
|
-
this._url = formatZentaoUrl(options.url);
|
|
97
|
-
this._account = options.account;
|
|
98
|
-
this._password = options.password;
|
|
99
|
-
|
|
100
|
-
// 创建账号标识
|
|
101
|
-
this._identifier = `${this.account}@${this._url}`;
|
|
102
|
-
|
|
103
|
-
// Zentao 实例名称
|
|
104
|
-
this._sessionName = `ZENTAO-API::${options.sessionName ??
|
|
105
|
-
this._identifier}`;
|
|
106
|
-
|
|
107
|
-
this._userRequestType = options.accessMode;
|
|
108
|
-
this._preserveToken = options.preserveToken ?? true;
|
|
109
|
-
|
|
110
|
-
if (this._debug) {
|
|
111
|
-
console.log(
|
|
112
|
-
[
|
|
113
|
-
`${kleur.yellow('▶︎')} ${kleur
|
|
114
|
-
.bold()
|
|
115
|
-
.blue(this._sessionName)} ${kleur.yellow('◀︎')}`,
|
|
116
|
-
` url: ${kleur.magenta(this.url)}`,
|
|
117
|
-
` account: ${kleur.magenta(this.account)}`,
|
|
118
|
-
` password: ${kleur.magenta(this.password)}`,
|
|
119
|
-
` preserveToken: ${kleur.magenta(
|
|
120
|
-
`${this._preserveToken}`
|
|
121
|
-
)}`,
|
|
122
|
-
` sessionName: ${kleur.magenta(this._sessionName)}`,
|
|
123
|
-
` identifier: ${kleur.magenta(this._identifier)}`,
|
|
124
|
-
` requestType: ${kleur.magenta(this.requestType)}`,
|
|
125
|
-
].join('\n')
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// 从本地存储加载禅道配置
|
|
130
|
-
if (this._preserveToken) {
|
|
131
|
-
this._store = new Configstore(this._sessionName, {});
|
|
132
|
-
const configFromStore = this._store.get('config');
|
|
133
|
-
if (configFromStore) {
|
|
134
|
-
this._config = new ZentaoConfig(configFromStore);
|
|
135
|
-
|
|
136
|
-
if (this._debug) {
|
|
137
|
-
console.log(
|
|
138
|
-
[
|
|
139
|
-
kleur.bold(
|
|
140
|
-
`\n${kleur.gray('➡︎')} ${kleur
|
|
141
|
-
.bold()
|
|
142
|
-
.blue(
|
|
143
|
-
'Load zentao config from local storage'
|
|
144
|
-
)}`
|
|
145
|
-
),
|
|
146
|
-
` ${JSON.stringify(configFromStore)}`,
|
|
147
|
-
].join('\n')
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* 禅道服务器地址
|
|
156
|
-
*/
|
|
157
|
-
get url(): string {
|
|
158
|
-
return this._url;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* 当前实例名称
|
|
163
|
-
*/
|
|
164
|
-
get sessionName(): string {
|
|
165
|
-
return this._sessionName;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* 当前服务器和账号标识
|
|
170
|
-
*/
|
|
171
|
-
get identifier(): string {
|
|
172
|
-
return this._identifier;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* 当前用户账号
|
|
177
|
-
*/
|
|
178
|
-
get account(): string {
|
|
179
|
-
return this._account;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* 登录密码
|
|
184
|
-
*/
|
|
185
|
-
get password(): string {
|
|
186
|
-
return this._password;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* 请求方式
|
|
191
|
-
*/
|
|
192
|
-
get requestType(): ZentaoRequestType {
|
|
193
|
-
return this._userRequestType ?? this._config?.requestType ?? 'GET';
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* 当前用于验证的 Token 字符串
|
|
198
|
-
*/
|
|
199
|
-
get token(): string {
|
|
200
|
-
return this._config?.token ?? '';
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* 登录到禅道并更新用于请求 API 的 token,通常不需要手动调用此方法,在调用 API 时会自动判断 token 是否可用,如果不可用会自动调用此方法
|
|
205
|
-
*
|
|
206
|
-
* @returns 返回请求结果,当登录成功时,其中 `result` 字段为所登录的用户信息对象
|
|
207
|
-
* @example
|
|
208
|
-
* import { Zentao } from 'zentao-api';
|
|
209
|
-
* const zentao = new Zentao({
|
|
210
|
-
* url: 'https://pro.demo.zentao.net/', account: 'demo', password: '123456'
|
|
211
|
-
* });
|
|
212
|
-
* const result = await zentao.login();
|
|
213
|
-
* const user = result.result; // 获取当前登录的用户对象
|
|
214
|
-
* console.log('当前登录的用户名称为:', user.realname);
|
|
215
|
-
*/
|
|
216
|
-
async login(): Promise<ZentaoApiResult> {
|
|
217
|
-
await this.fetchConfig();
|
|
218
|
-
|
|
219
|
-
const res = await this.m('user')
|
|
220
|
-
.f('login')
|
|
221
|
-
.useConverter((remoteData, result) => {
|
|
222
|
-
if (remoteData.user) {
|
|
223
|
-
result.result = remoteData.user;
|
|
224
|
-
}
|
|
225
|
-
return result;
|
|
226
|
-
})
|
|
227
|
-
.post({account: this.account, password: this.password});
|
|
228
|
-
|
|
229
|
-
return res;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* 获取禅道服务器配置
|
|
234
|
-
* @returns 禅道服务器配置
|
|
235
|
-
*/
|
|
236
|
-
async fetchConfig(): Promise<ZentaoConfig> {
|
|
237
|
-
const url = `${this._url}/?mode=getconfig`;
|
|
238
|
-
try {
|
|
239
|
-
const resp = await axios.get(url);
|
|
240
|
-
|
|
241
|
-
const config = new ZentaoConfig(resp.data);
|
|
242
|
-
this._config = config;
|
|
243
|
-
|
|
244
|
-
this._log('fetchConfig', {resp});
|
|
245
|
-
} catch (error) {
|
|
246
|
-
this._log('fetchConfig', {url, error});
|
|
247
|
-
throw error;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
return this._config;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* 根据模块名创建一个禅道请求构建实例
|
|
255
|
-
* @param moduleName 模块名
|
|
256
|
-
* @param methodName 方法名
|
|
257
|
-
* @param params 请求参数
|
|
258
|
-
* @returns 禅道请求构建实例
|
|
259
|
-
*/
|
|
260
|
-
module(
|
|
261
|
-
moduleName: string,
|
|
262
|
-
methodName?: string,
|
|
263
|
-
params?: ZentaoRequestParams
|
|
264
|
-
): ZentaoRequestBuilder {
|
|
265
|
-
return new ZentaoRequestBuilder(this, moduleName, methodName, params);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
/**
|
|
269
|
-
* 根据模块名创建一个禅道请求构建实例
|
|
270
|
-
* @param moduleName 模块名
|
|
271
|
-
* @param methodName 方法名
|
|
272
|
-
* @param params 请求参数
|
|
273
|
-
* @returns 禅道请求构建实例
|
|
274
|
-
* @alias module
|
|
275
|
-
*/
|
|
276
|
-
m(
|
|
277
|
-
moduleName: string,
|
|
278
|
-
methodName?: string,
|
|
279
|
-
params?: ZentaoRequestParams
|
|
280
|
-
): ZentaoRequestBuilder {
|
|
281
|
-
return this.module(moduleName, methodName, params);
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* 向禅道服务器发起请求
|
|
286
|
-
* @param moduleName 模块名
|
|
287
|
-
* @param methodName 方法名
|
|
288
|
-
* @param options 其他请求选项
|
|
289
|
-
* @returns 请求结果
|
|
290
|
-
*/
|
|
291
|
-
async request(
|
|
292
|
-
moduleName: string,
|
|
293
|
-
methodName: string = 'index',
|
|
294
|
-
options: {
|
|
295
|
-
params?: ZentaoRequestParams;
|
|
296
|
-
data?: string | Record<string, any>;
|
|
297
|
-
name?: string;
|
|
298
|
-
method?: ZentaoRequestMethod;
|
|
299
|
-
url?: string;
|
|
300
|
-
resultConvertor?: (
|
|
301
|
-
remoteData: any,
|
|
302
|
-
result: ZentaoApiResult
|
|
303
|
-
) => ZentaoApiResult;
|
|
304
|
-
fields?: string[];
|
|
305
|
-
} = {}
|
|
306
|
-
): Promise<ZentaoApiResult> {
|
|
307
|
-
if (
|
|
308
|
-
(!this._config || this._config?.isTokenExpired) &&
|
|
309
|
-
`${moduleName}/${methodName}`.toLowerCase() !== 'user/login'
|
|
310
|
-
) {
|
|
311
|
-
await this.login();
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
if (!this._config) {
|
|
315
|
-
throw new Error(
|
|
316
|
-
`Zentao config is empty, makesure to fetch config before request from ${moduleName}-${methodName}.`
|
|
317
|
-
);
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
const params = normalizeRequestParams(options.params);
|
|
321
|
-
const url =
|
|
322
|
-
options.url ?? this.createUrl(moduleName, methodName, params);
|
|
323
|
-
const name =
|
|
324
|
-
options.name ??
|
|
325
|
-
`${moduleName}${methodName[0].toUpperCase()}${methodName.substr(
|
|
326
|
-
1
|
|
327
|
-
)}`;
|
|
328
|
-
const method = options.method ?? 'GET';
|
|
329
|
-
const headers = {
|
|
330
|
-
Cookie: this._config.tokenAuth,
|
|
331
|
-
};
|
|
332
|
-
|
|
333
|
-
let {data} = options;
|
|
334
|
-
if (data && typeof data === 'object') {
|
|
335
|
-
const formData: Record<string, any> = {};
|
|
336
|
-
for (const key of Object.keys(data)) {
|
|
337
|
-
const value = data[key];
|
|
338
|
-
if (Array.isArray(value)) {
|
|
339
|
-
value.forEach((item, index) => {
|
|
340
|
-
formData[`${key}[${index}]`] = item;
|
|
341
|
-
});
|
|
342
|
-
delete data[key];
|
|
343
|
-
} else {
|
|
344
|
-
formData[key] = value;
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
data = querystring.stringify(formData);
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
try {
|
|
351
|
-
const resp = await axios.request({
|
|
352
|
-
method,
|
|
353
|
-
url,
|
|
354
|
-
data,
|
|
355
|
-
headers,
|
|
356
|
-
});
|
|
357
|
-
|
|
358
|
-
let result: ZentaoApiResult;
|
|
359
|
-
const remoteData = resp.data;
|
|
360
|
-
if (typeof remoteData === 'object' && remoteData !== null) {
|
|
361
|
-
if (
|
|
362
|
-
typeof remoteData.data === 'string' &&
|
|
363
|
-
(remoteData.data[0] === '[' || remoteData.data[0] === '{')
|
|
364
|
-
) {
|
|
365
|
-
remoteData.data = JSON.parse(remoteData.data);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
const success =
|
|
369
|
-
remoteData.status === 'success' ||
|
|
370
|
-
remoteData.result === 'success';
|
|
371
|
-
result = {
|
|
372
|
-
status: success ? 1 : 0,
|
|
373
|
-
msg: remoteData.message ?? (success ? 'success' : 'error'),
|
|
374
|
-
result: remoteData.data ?? remoteData.result,
|
|
375
|
-
};
|
|
376
|
-
} else {
|
|
377
|
-
result = {status: 0, msg: 'error', result: resp.data};
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
if (options.resultConvertor) {
|
|
381
|
-
result = options.resultConvertor(remoteData, result);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
if (
|
|
385
|
-
options.fields &&
|
|
386
|
-
typeof result.result === 'object' &&
|
|
387
|
-
result.result
|
|
388
|
-
) {
|
|
389
|
-
if (Array.isArray(result.result)) {
|
|
390
|
-
result.result = result.result.map(x =>
|
|
391
|
-
slimmingObject(x, options.fields!)
|
|
392
|
-
);
|
|
393
|
-
} else {
|
|
394
|
-
result.result = slimmingObject(
|
|
395
|
-
result.result,
|
|
396
|
-
options.fields!
|
|
397
|
-
);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
if (
|
|
402
|
-
`${moduleName}/${methodName}` === 'user/login' &&
|
|
403
|
-
result.status === 1
|
|
404
|
-
) {
|
|
405
|
-
this._config?.renewToken();
|
|
406
|
-
if (this._preserveToken) {
|
|
407
|
-
this._store?.set('config', this._config);
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
this._log(name, {url, result, params, data, resp});
|
|
412
|
-
return result;
|
|
413
|
-
} catch (error) {
|
|
414
|
-
this._log(name, {url, error, params, data});
|
|
415
|
-
throw error;
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
/**
|
|
420
|
-
* 生成请求地址
|
|
421
|
-
* @param moduleName 模块名
|
|
422
|
-
* @param methodName 方法名
|
|
423
|
-
* @param params 其他参数
|
|
424
|
-
* @returns 请求地址
|
|
425
|
-
*/
|
|
426
|
-
createUrl(
|
|
427
|
-
moduleName: string,
|
|
428
|
-
methodName: string = 'index',
|
|
429
|
-
params?: ZentaoRequestParamPair[]
|
|
430
|
-
): string {
|
|
431
|
-
const config = this._config;
|
|
432
|
-
if (!config) {
|
|
433
|
-
throw new Error(
|
|
434
|
-
'Zentao config is empty, makesure fetch config before call others api.'
|
|
435
|
-
);
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
const urlParts: string[] = [this.url];
|
|
439
|
-
if (this.requestType === 'PATH_INFO') {
|
|
440
|
-
urlParts.push(moduleName, config.requestFix, methodName);
|
|
441
|
-
if (params) {
|
|
442
|
-
for (const paramPair of params) {
|
|
443
|
-
urlParts.push(config.requestFix, paramPair[1]);
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
urlParts.push('.json');
|
|
447
|
-
} else {
|
|
448
|
-
urlParts.push(
|
|
449
|
-
`?${config.moduleVar}=${moduleName}&${config.methodVar}=${methodName}`
|
|
450
|
-
);
|
|
451
|
-
if (params) {
|
|
452
|
-
for (const paramPair of params) {
|
|
453
|
-
urlParts.push(
|
|
454
|
-
`&${paramPair[0]}=${encodeURIComponent(paramPair[1])}`
|
|
455
|
-
);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
urlParts.push(`&${config.viewVar}=json`);
|
|
459
|
-
}
|
|
460
|
-
return urlParts.join('');
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
/**
|
|
464
|
-
* 输出 API 请求日志
|
|
465
|
-
* @param name 名称
|
|
466
|
-
* @param atrributes 日志属性对象
|
|
467
|
-
* @param others 其他日志内容
|
|
468
|
-
*/
|
|
469
|
-
protected _log(
|
|
470
|
-
name: string,
|
|
471
|
-
atrributes: {
|
|
472
|
-
url?: string;
|
|
473
|
-
params?: ZentaoRequestParamPair[];
|
|
474
|
-
data?: string | Record<string, any>;
|
|
475
|
-
method?: string;
|
|
476
|
-
resp?: AxiosResponse;
|
|
477
|
-
result?: ZentaoApiResult;
|
|
478
|
-
error?: any;
|
|
479
|
-
},
|
|
480
|
-
...others: any[]
|
|
481
|
-
) {
|
|
482
|
-
if (!this._debug) {
|
|
483
|
-
return;
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
const logLines = ['\n\n'];
|
|
487
|
-
const {resp, result} = atrributes;
|
|
488
|
-
const status = resp?.status ?? '';
|
|
489
|
-
const success = result ? result.status === 1 : status === 200;
|
|
490
|
-
const url = (resp ? resp.config.url : atrributes.url) ?? '';
|
|
491
|
-
const method = (resp ? resp.config.method : atrributes.method) ?? 'GET';
|
|
492
|
-
|
|
493
|
-
logLines.push(
|
|
494
|
-
kleur.bold(
|
|
495
|
-
`${kleur.gray('➡︎')} ${kleur[
|
|
496
|
-
success ? 'green' : 'red'
|
|
497
|
-
]().inverse(` ${name} ${success ? '✓' : '𐄂'} `)}`
|
|
498
|
-
)
|
|
499
|
-
);
|
|
500
|
-
|
|
501
|
-
logLines.push(
|
|
502
|
-
`\n ${kleur
|
|
503
|
-
.bold()
|
|
504
|
-
.blue(method.toUpperCase())} ${kleur.blue().underline(url)}`
|
|
505
|
-
);
|
|
506
|
-
logLines.push(
|
|
507
|
-
` status: ${kleur[status === 200 ? 'green' : 'red'](
|
|
508
|
-
`● ${status}`
|
|
509
|
-
)} ${kleur.gray(resp?.statusText ?? '')}`
|
|
510
|
-
);
|
|
511
|
-
|
|
512
|
-
if (atrributes.params) {
|
|
513
|
-
logLines.push(`\n ${kleur.bold().blue('Request Parameters')}`);
|
|
514
|
-
for (const pair of atrributes.params) {
|
|
515
|
-
const pairValue =
|
|
516
|
-
typeof pair[1] === 'string'
|
|
517
|
-
? pair[1]
|
|
518
|
-
: JSON.stringify(pair[1]);
|
|
519
|
-
logLines.push(` ${pair[0]}: ${kleur.magenta(pairValue)}`);
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
if (resp?.config?.headers) {
|
|
524
|
-
logLines.push(`\n ${kleur.bold().blue('Request Headers')}`);
|
|
525
|
-
const headers = resp.config.headers;
|
|
526
|
-
for (const key of Object.keys(headers)) {
|
|
527
|
-
const value =
|
|
528
|
-
typeof headers[key] === 'string'
|
|
529
|
-
? headers[key]
|
|
530
|
-
: JSON.stringify(headers[key]);
|
|
531
|
-
logLines.push(` ${key}: ${kleur.magenta(value)}`);
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
if (atrributes.data) {
|
|
536
|
-
let {data} = atrributes;
|
|
537
|
-
logLines.push(`\n ${kleur.bold().blue('Request Data')}`);
|
|
538
|
-
if (typeof data === 'string') {
|
|
539
|
-
data = querystring.parse(data);
|
|
540
|
-
}
|
|
541
|
-
for (const key of Object.keys(data)) {
|
|
542
|
-
const value =
|
|
543
|
-
typeof data[key] === 'string'
|
|
544
|
-
? data[key]
|
|
545
|
-
: JSON.stringify(data[key]);
|
|
546
|
-
logLines.push(` ${key}: ${kleur.magenta(value)}`);
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
if (result) {
|
|
551
|
-
logLines.push(`\n ${kleur.bold().cyan('Response Data')}`);
|
|
552
|
-
logLines.push(
|
|
553
|
-
` status: ${kleur[result.status === 1 ? 'green' : 'red'](
|
|
554
|
-
result.status
|
|
555
|
-
)},`
|
|
556
|
-
);
|
|
557
|
-
if (result.msg !== undefined) {
|
|
558
|
-
logLines.push(
|
|
559
|
-
` msg: ${kleur[result.status === 1 ? 'green' : 'red'](
|
|
560
|
-
typeof result.msg === 'string'
|
|
561
|
-
? result.msg
|
|
562
|
-
: JSON.stringify(result.msg)
|
|
563
|
-
)},`
|
|
564
|
-
);
|
|
565
|
-
}
|
|
566
|
-
if (result.result !== undefined) {
|
|
567
|
-
logLines.push(
|
|
568
|
-
` result: ${kleur.magenta(
|
|
569
|
-
JSON.stringify(result.result)
|
|
570
|
-
)}`
|
|
571
|
-
);
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
if (resp && (!result || !success || !result.result)) {
|
|
575
|
-
logLines.push(`\n ${kleur.bold().cyan('Response Text')}`);
|
|
576
|
-
logLines.push(
|
|
577
|
-
` ${
|
|
578
|
-
typeof resp.data === 'string'
|
|
579
|
-
? resp.data
|
|
580
|
-
: JSON.stringify(resp.data)
|
|
581
|
-
}`
|
|
582
|
-
);
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
if (atrributes.error) {
|
|
586
|
-
logLines.push(`\n ${kleur.bold().red('Error')}`);
|
|
587
|
-
logLines.push(` ${kleur.red(atrributes.error)}`);
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
if (others && others.length) {
|
|
591
|
-
logLines.push(...others);
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
console.log(logLines.join('\n'));
|
|
595
|
-
}
|
|
596
|
-
}
|