api-render-ui 1.1.1 → 1.1.2
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/dist/index.cjs +605 -139
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +605 -139
- package/dist/index.js.map +1 -1
- package/example/animal.html +1137 -254
- package/package.json +1 -1
- package/src/api-render-ui.css +3 -1
- package/src/api-render-ui.ts +869 -166
- package/src/inlined-styles.ts +3 -1
package/src/api-render-ui.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { GLOBAL_STYLES } from './inlined-styles';
|
|
2
2
|
import { OpenAPIV3 } from 'openapi-types';
|
|
3
3
|
|
|
4
|
-
type OpenAPIV3CustomDoc = OpenAPIV3.Document & { swagger: string }
|
|
4
|
+
type OpenAPIV3CustomDoc = OpenAPIV3.Document & { swagger: string; definitions: any } //Compatible with version 2.0
|
|
5
5
|
|
|
6
6
|
export class ApiRenderer {
|
|
7
7
|
options: any;
|
|
@@ -138,14 +138,53 @@ export class ApiRenderer {
|
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
|
|
141
|
+
const auths = [
|
|
142
|
+
{
|
|
143
|
+
value: "No Auth"
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
value: "Basic Auth",
|
|
147
|
+
parameters: [
|
|
148
|
+
{
|
|
149
|
+
name: "userName",
|
|
150
|
+
value: ""
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
name: "password",
|
|
154
|
+
value: ""
|
|
155
|
+
}
|
|
156
|
+
]
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
value: "OAuth 2.0",
|
|
160
|
+
}
|
|
161
|
+
]
|
|
162
|
+
|
|
163
|
+
const grantTypes = [
|
|
164
|
+
{ value: "authorization_code" },
|
|
165
|
+
{ value: "Implicit" },
|
|
166
|
+
{ value: "Resource Owner Password Credentials" },
|
|
167
|
+
{ value: "client_credentials" }
|
|
168
|
+
]
|
|
169
|
+
|
|
170
|
+
const clientAuthenticationOpts = [
|
|
171
|
+
{ value: "Headers", displayName: "Send credentials in headers" },
|
|
172
|
+
{ value: "Body", displayName: "Send credentials in body" }
|
|
173
|
+
]
|
|
174
|
+
|
|
175
|
+
// ========== 数据定义 ==========
|
|
176
|
+
const consumeOpts = [
|
|
177
|
+
{ value: "None" },
|
|
178
|
+
{ value: "application/json" },
|
|
179
|
+
{ value: "application/xml" },
|
|
180
|
+
{ value: "application/x-www-form-urlencoded" },
|
|
181
|
+
{ value: "multipart/form-data" },
|
|
182
|
+
{ value: "text/plain" }
|
|
183
|
+
];
|
|
184
|
+
|
|
141
185
|
|
|
142
186
|
function renderApiUnit(apiOperator: any, containerRef: any, elementMap: any) {
|
|
143
187
|
return function (evt: any) {
|
|
144
|
-
console.log('点击的API操作:');
|
|
145
|
-
console.log('方法:', apiOperator.method);
|
|
146
|
-
console.log('URL:', apiOperator.url);
|
|
147
|
-
console.log('------------------------');
|
|
148
|
-
|
|
149
188
|
const currentTarget = evt.currentTarget;
|
|
150
189
|
// 检查是否已存在对应的新元素
|
|
151
190
|
if (elementMap.has(currentTarget)) {
|
|
@@ -193,7 +232,7 @@ function createApiUnit(apiOperator: any) {
|
|
|
193
232
|
// 授权部分
|
|
194
233
|
const authSection = createSectionAuth(apiOperator);
|
|
195
234
|
// 请求体部分
|
|
196
|
-
const bodySection = createSectionRequestBody(apiOperator
|
|
235
|
+
const bodySection = createSectionRequestBody(apiOperator);
|
|
197
236
|
|
|
198
237
|
reqContent.append(paramSection, headerSection, authSection, bodySection);
|
|
199
238
|
apiContainer.appendChild(reqContent);
|
|
@@ -233,7 +272,6 @@ function createReqOperator(apiOperator: any) {
|
|
|
233
272
|
reqUrl.value = apiOperator.url; // 绑定初始值
|
|
234
273
|
// 可选:添加输入事件监听(根据需求)
|
|
235
274
|
reqUrl.addEventListener('input', (e: any) => {
|
|
236
|
-
console.log('当前值:', e.target.value);
|
|
237
275
|
// 这里可以添加保存逻辑(如更新状态/发送请求
|
|
238
276
|
apiOperator.url = e.target.value
|
|
239
277
|
});
|
|
@@ -249,7 +287,6 @@ function createReqOperator(apiOperator: any) {
|
|
|
249
287
|
sendButton.appendChild(sendText);
|
|
250
288
|
|
|
251
289
|
sendButton.addEventListener('click', (e: any) => {
|
|
252
|
-
console.log('当前值:', e.target.value);
|
|
253
290
|
// 这里可以添加保存逻辑(如更新状态/发送请求
|
|
254
291
|
// responseSectionRef 在渲染时会被挂载到 apiOperator._responseSectionRef 上
|
|
255
292
|
const respRef = apiOperator._responseSectionRef || null;
|
|
@@ -331,19 +368,191 @@ function createSectionAuth(apiOperator: any) {
|
|
|
331
368
|
authValues.setAttribute('data-layer', 'paraKeyValues');
|
|
332
369
|
authValues.className = 'Parakeyvalues codigma-apiunit-parakeyvalues';
|
|
333
370
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
371
|
+
const authTypeRow = createSelectRow('Authorization Type', auths)
|
|
372
|
+
// 添加选择事件监听
|
|
373
|
+
authTypeRow.children[1].addEventListener('change', function (event: any) {
|
|
374
|
+
//切换前先移除掉原来的元素
|
|
375
|
+
authValues && Array.from(authValues.children).slice(1).forEach((el: any) => el.remove());
|
|
376
|
+
const auth = auths[event.target.selectedIndex];
|
|
377
|
+
if (auth.value == 'No Auth') {
|
|
378
|
+
|
|
379
|
+
} else if (auth.value == 'Basic Auth') {
|
|
380
|
+
apiOperator.auth = [
|
|
381
|
+
{
|
|
382
|
+
name: "userName",
|
|
383
|
+
value: ""
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
name: "password",
|
|
387
|
+
value: ""
|
|
388
|
+
}
|
|
389
|
+
]
|
|
390
|
+
const authRows = apiOperator.auth.map((parameter: any) => createRow(parameter));
|
|
391
|
+
authValues.append(...authRows);
|
|
392
|
+
} else if (auth.value == 'OAuth 2.0') {
|
|
393
|
+
apiOperator.auth = {}
|
|
394
|
+
renderAuthForm(apiOperator, authValues, authTypeRow)
|
|
395
|
+
}
|
|
396
|
+
});
|
|
341
397
|
|
|
398
|
+
authValues.append(authTypeRow);
|
|
342
399
|
authSection.append(authCnr, authValues);
|
|
343
400
|
return authSection;
|
|
344
401
|
}
|
|
345
402
|
|
|
346
|
-
|
|
403
|
+
// 工具函数:创建带 class 和属性的元素
|
|
404
|
+
function createElement(tag: string, props: Record<string, string> = {}, classes: string[] = []): HTMLElement {
|
|
405
|
+
const el = document.createElement(tag);
|
|
406
|
+
Object.entries(props).forEach(([key, value]) => el.setAttribute(key, value));
|
|
407
|
+
if (classes.length) el.classList.add(...classes);
|
|
408
|
+
return el;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// 工具函数:创建 label + input 结构
|
|
412
|
+
function createLabeledInput(apiOperator: any,
|
|
413
|
+
labelText: string,
|
|
414
|
+
inputId: string,
|
|
415
|
+
inputName: string,
|
|
416
|
+
modelKey: string,
|
|
417
|
+
required: boolean = false
|
|
418
|
+
): HTMLElement {
|
|
419
|
+
const wrapper = createElement('div', {}, ['Keyvalue', 'codigma-apiunit-keyvalue']);
|
|
420
|
+
const label = createElement('label', { for: inputId }, ['type', 'codigma-apiunit-send']);
|
|
421
|
+
label.textContent = labelText + ':';
|
|
422
|
+
const input = createElement('input', {
|
|
423
|
+
type: 'text',
|
|
424
|
+
id: inputId,
|
|
425
|
+
name: inputName,
|
|
426
|
+
autocomplete: 'off',
|
|
427
|
+
...(required ? { required: 'true' } : {})
|
|
428
|
+
}, ['Valuetext', 'codigma-apiunit-valuetext']) as HTMLInputElement;
|
|
429
|
+
|
|
430
|
+
// 双向绑定模拟:初始化值 + 监听输入
|
|
431
|
+
input.value = apiOperator.auth[modelKey] || '';
|
|
432
|
+
input.addEventListener('input', (e) => {
|
|
433
|
+
apiOperator.auth[modelKey] = (e.target as HTMLInputElement).value;
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
wrapper.appendChild(label);
|
|
437
|
+
wrapper.appendChild(input);
|
|
438
|
+
return wrapper;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// 创建下拉选择框(替代 ast-select)
|
|
442
|
+
function createSelect(apiOperator: any,
|
|
443
|
+
labelText: string,
|
|
444
|
+
selectId: string,
|
|
445
|
+
options: { value: string; displayName?: string }[],
|
|
446
|
+
modelKey: string,
|
|
447
|
+
changeHandler: (value: string) => void
|
|
448
|
+
): HTMLElement {
|
|
449
|
+
const wrapper = createElement('div', {}, ['Keyvalue', 'codigma-apiunit-keyvalue']);
|
|
450
|
+
const label = createElement('label', { for: selectId }, ['type', 'codigma-apiunit-send']);
|
|
451
|
+
label.textContent = labelText + ':';
|
|
452
|
+
|
|
453
|
+
const select = createElement('select', {
|
|
454
|
+
id: selectId,
|
|
455
|
+
name: selectId
|
|
456
|
+
}, []) as HTMLSelectElement;
|
|
457
|
+
|
|
458
|
+
options.forEach(opt => {
|
|
459
|
+
const option = createElement('option', { value: opt.value }) as HTMLOptionElement;
|
|
460
|
+
option.textContent = opt.displayName || opt.value;
|
|
461
|
+
select.appendChild(option);
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
// 初始化选中值
|
|
465
|
+
select.value = apiOperator.auth[modelKey] || options[0]?.value || '';
|
|
466
|
+
// changeHandler(select.value); // 触发初始设置
|
|
467
|
+
|
|
468
|
+
select.addEventListener('change', (e) => {
|
|
469
|
+
const val = (e.target as HTMLSelectElement).value;
|
|
470
|
+
changeHandler(val);
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
wrapper.appendChild(label);
|
|
474
|
+
wrapper.appendChild(select);
|
|
475
|
+
return wrapper;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// 重新渲染整个表单(基于当前 apiOperator.auth.grantType)
|
|
479
|
+
function renderAuthForm(apiOperator: any, authValues: any, authTypeRow: any) {
|
|
480
|
+
authValues.innerHTML = ''; // 清空
|
|
481
|
+
|
|
482
|
+
authValues.append(authTypeRow);
|
|
483
|
+
// Token
|
|
484
|
+
authValues.appendChild(createLabeledInput(apiOperator, 'Token', 'token', 'token', 'token', true));
|
|
485
|
+
|
|
486
|
+
// Grant Type
|
|
487
|
+
authValues.appendChild(
|
|
488
|
+
createSelect(apiOperator,
|
|
489
|
+
'Grant Type',
|
|
490
|
+
'grantType',
|
|
491
|
+
grantTypes,
|
|
492
|
+
'grantType',
|
|
493
|
+
(value: string) => {
|
|
494
|
+
apiOperator.auth.grantType = value;
|
|
495
|
+
renderAuthForm(apiOperator, authValues, authTypeRow); // 重新渲染以反映条件字段
|
|
496
|
+
}
|
|
497
|
+
)
|
|
498
|
+
);
|
|
499
|
+
|
|
500
|
+
const gt = apiOperator.auth.grantType || 'authorization_code';
|
|
501
|
+
|
|
502
|
+
// Conditional: Authorization Code or Implicit
|
|
503
|
+
if (gt === 'authorization_code' || gt === 'Implicit') {
|
|
504
|
+
authValues.appendChild(createLabeledInput(apiOperator, 'Authorization Endpoint', 'authorizationEndpoint', 'authorizationEndpoint', 'authorizationEndpoint', true));
|
|
505
|
+
authValues.appendChild(createLabeledInput(apiOperator, 'Redirect URL', 'RedirectURI', 'RedirectURI', 'redirectURI', true));
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Conditional: Token Endpoint needed
|
|
509
|
+
if (gt === 'authorization_code' || gt === 'client_credentials' || gt === 'Resource Owner Password Credentials') {
|
|
510
|
+
authValues.appendChild(createLabeledInput(apiOperator, 'Token Endpoint', 'TokenEndpoint', 'TokenEndpoint', 'tokenEndpoint', true));
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// Client ID (always shown)
|
|
514
|
+
authValues.appendChild(createLabeledInput(apiOperator, 'Client ID', 'ClientID', 'ClientID', 'clientId', true));
|
|
515
|
+
|
|
516
|
+
// Conditional: Client Secret
|
|
517
|
+
if (gt === 'authorization_code' || gt === 'client_credentials' || gt === 'Resource Owner Password Credentials') {
|
|
518
|
+
authValues.appendChild(createLabeledInput(apiOperator, 'Client Secret', 'ClientSecret', 'ClientSecret', 'clientSecret', true));
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Conditional: Username & Password
|
|
522
|
+
if (gt === 'Resource Owner Password Credentials') {
|
|
523
|
+
authValues.appendChild(createLabeledInput(apiOperator, 'Username', 'Username', 'Username', 'username', true));
|
|
524
|
+
authValues.appendChild(createLabeledInput(apiOperator, 'Password', 'Password', 'Password', 'password', true));
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// Scopes (always shown)
|
|
528
|
+
authValues.appendChild(createLabeledInput(apiOperator, 'Scopes', 'Scopes', 'Scopes', 'scopes', true));
|
|
529
|
+
|
|
530
|
+
// Client Authentication
|
|
531
|
+
authValues.appendChild(
|
|
532
|
+
createSelect(apiOperator,
|
|
533
|
+
'Client Authentication',
|
|
534
|
+
'clientAuthentication',
|
|
535
|
+
clientAuthenticationOpts,
|
|
536
|
+
'clientAuthentication',
|
|
537
|
+
(value: string) => {
|
|
538
|
+
apiOperator.auth.clientAuthentication = value;
|
|
539
|
+
// 不需要重新渲染整个表单,除非 UI 依赖此值
|
|
540
|
+
}
|
|
541
|
+
)
|
|
542
|
+
);
|
|
543
|
+
|
|
544
|
+
// --- 新增:Generate Token 按钮 ---
|
|
545
|
+
const buttonWrapper = createElement('div', {}, ['parameter-item']);
|
|
546
|
+
const generateBtn = createElement('button', {}, ['parameter-button']) as HTMLButtonElement;
|
|
547
|
+
generateBtn.type = 'button';
|
|
548
|
+
generateBtn.textContent = 'Generate Token';
|
|
549
|
+
generateBtn.addEventListener('click', () => generateOAuth2Token(apiOperator)); // 绑定点击事件
|
|
550
|
+
|
|
551
|
+
buttonWrapper.appendChild(generateBtn);
|
|
552
|
+
authValues.appendChild(buttonWrapper);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
function createSectionRequestBody(apiOperator: any) {
|
|
347
556
|
const bodySection = document.createElement('div');
|
|
348
557
|
bodySection.setAttribute('data-layer', 'request-body-section');
|
|
349
558
|
bodySection.className = 'RequestBodySection codigma-apiunit-request-body-section';
|
|
@@ -358,14 +567,170 @@ function createSectionRequestBody(requestBody: any) {
|
|
|
358
567
|
bodyCnr.appendChild(bodyText);
|
|
359
568
|
bodySection.appendChild(bodyCnr);
|
|
360
569
|
// 请求体内容
|
|
361
|
-
|
|
362
|
-
bodyValue.setAttribute('data-layer', 'bodyTextValue');
|
|
363
|
-
bodyValue.className = 'Id0CategoryId0NameNamePhotourlsTagsId0NameStatusAvailable codigma-apiunit-parakeyvalues';
|
|
364
|
-
bodyValue.value = JSON.stringify(requestBody);
|
|
365
|
-
bodySection.appendChild(bodyValue);
|
|
570
|
+
renderConsumeSection(apiOperator, bodySection, bodyCnr);
|
|
366
571
|
return bodySection;
|
|
367
572
|
}
|
|
368
573
|
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
// ========== 创建下拉选择框 ==========
|
|
578
|
+
function createConsumeSelect(apiOperator: any, container: HTMLElement, bodyCnr: any) {
|
|
579
|
+
const wrapper = createElement('div');
|
|
580
|
+
const label = createElement('label');
|
|
581
|
+
label.style.margin = '0 1rem';
|
|
582
|
+
label.textContent = 'Content-Type';
|
|
583
|
+
|
|
584
|
+
const select = createElement('select') as HTMLSelectElement;
|
|
585
|
+
select.style.width = '18rem'; // 模拟 [width]="'18rem'"
|
|
586
|
+
|
|
587
|
+
consumeOpts.forEach(opt => {
|
|
588
|
+
const option = document.createElement('option');
|
|
589
|
+
option.value = opt.value;
|
|
590
|
+
option.textContent = opt.value;
|
|
591
|
+
select.appendChild(option);
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
// 设置当前值
|
|
595
|
+
select.value = apiOperator.currentConsume || getCurrentConsume(apiOperator);
|
|
596
|
+
|
|
597
|
+
// 监听 change
|
|
598
|
+
select.addEventListener('change', (e) => {
|
|
599
|
+
const newValue = (e.target as HTMLSelectElement).value;
|
|
600
|
+
if (apiOperator.currentConsume !== newValue) {
|
|
601
|
+
apiOperator.currentConsume = newValue;
|
|
602
|
+
renderConsumeSection(apiOperator, container, bodyCnr); // 重新渲染整个区域
|
|
603
|
+
}
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
wrapper.appendChild(label);
|
|
607
|
+
wrapper.appendChild(select);
|
|
608
|
+
return wrapper;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// ========== 渲染请求体到指定容器(无 ID 依赖) ==========
|
|
612
|
+
function renderRequestBodyInto(apiOperator: any, targetDiv: HTMLElement) {
|
|
613
|
+
targetDiv.innerHTML = ''; // 清空目标区域
|
|
614
|
+
|
|
615
|
+
// 确保 requestBody 和 content 存在
|
|
616
|
+
const ct = apiOperator.currentConsume || getCurrentConsume(apiOperator);
|
|
617
|
+
// ✅ 情况 1: 使用 textarea(JSON/XML/None/text/plain)
|
|
618
|
+
if (
|
|
619
|
+
ct === null ||
|
|
620
|
+
ct === 'None' ||
|
|
621
|
+
ct === 'application/json' ||
|
|
622
|
+
ct === 'application/xml' ||
|
|
623
|
+
ct === 'text/plain'
|
|
624
|
+
) {
|
|
625
|
+
// 决定使用哪个 key:'None' 也视为一种 content 类型(或可映射为 '',但这里直接用 'None')
|
|
626
|
+
const mimeType = ct || 'None';
|
|
627
|
+
|
|
628
|
+
// 从 content[mimeType] 读取,若无则默认空字符串
|
|
629
|
+
let rawValue = apiOperator.requestBody.content[mimeType];
|
|
630
|
+
if (rawValue == null) {
|
|
631
|
+
rawValue = '';
|
|
632
|
+
apiOperator.requestBody.content[mimeType] = rawValue; // 初始化
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
const textarea = createElement('textarea', {}, []) as HTMLTextAreaElement;
|
|
636
|
+
textarea.style.width = '100%';
|
|
637
|
+
textarea.style.height = '200px';
|
|
638
|
+
textarea.style.fontFamily = 'monospace';
|
|
639
|
+
textarea.style.fontSize = '14px';
|
|
640
|
+
textarea.placeholder = `Enter ${mimeType} body...`;
|
|
641
|
+
|
|
642
|
+
textarea.value = rawValue;
|
|
643
|
+
|
|
644
|
+
// 监听输入 → 写回 content[mimeType]
|
|
645
|
+
textarea.addEventListener('input', () => {
|
|
646
|
+
apiOperator.requestBody.content[mimeType] = textarea.value;
|
|
647
|
+
console.log(`Content updated for ${mimeType}:`, textarea.value);
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
targetDiv.appendChild(textarea);
|
|
651
|
+
|
|
652
|
+
}
|
|
653
|
+
// ✅ 情况 2: 表单参数
|
|
654
|
+
else if (
|
|
655
|
+
(ct === 'application/x-www-form-urlencoded' || ct === 'multipart/form-data') &&
|
|
656
|
+
apiOperator.requestBody.content &&
|
|
657
|
+
Array.isArray(apiOperator.requestBody.content[ct])
|
|
658
|
+
) {
|
|
659
|
+
const params = apiOperator.requestBody.content[ct];
|
|
660
|
+
params.forEach((param: any, index: number) => {
|
|
661
|
+
const item = createElement('div', {}, ['Keyvalue', 'codigma-apiunit-keyvalue']);
|
|
662
|
+
|
|
663
|
+
const label = createElement('label', { for: `param-${Date.now()}-${index}` }, ['petId', 'codigma-apiunit-send']);
|
|
664
|
+
label.textContent = `${param.name}:`;
|
|
665
|
+
|
|
666
|
+
const input = createElement('input', {
|
|
667
|
+
type: param.uiType || 'text',
|
|
668
|
+
// 使用时间戳+索引避免 id 冲突(仅用于 label for)
|
|
669
|
+
id: `param-${Date.now()}-${index}`,
|
|
670
|
+
name: 'name'
|
|
671
|
+
}, ['Valuetext', 'codigma-apiunit-valuetext']) as HTMLInputElement;
|
|
672
|
+
|
|
673
|
+
input.value = param.value || '';
|
|
674
|
+
input.autocomplete = 'off';
|
|
675
|
+
input.required = true;
|
|
676
|
+
|
|
677
|
+
input.addEventListener('keydown', (e) => {
|
|
678
|
+
setEditStatus(e, true);
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
input.addEventListener('input', () => {
|
|
682
|
+
param.value = input.value;
|
|
683
|
+
});
|
|
684
|
+
|
|
685
|
+
item.appendChild(label);
|
|
686
|
+
item.appendChild(input);
|
|
687
|
+
targetDiv.appendChild(item);
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
function getCurrentConsume(apiOperator: any) {
|
|
693
|
+
if (!apiOperator.requestBody) {
|
|
694
|
+
apiOperator.requestBody = { content: {} };
|
|
695
|
+
}
|
|
696
|
+
if (!apiOperator.requestBody.content) {
|
|
697
|
+
apiOperator.requestBody.content = {};
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
const keys = Object.keys(apiOperator.requestBody.content);
|
|
701
|
+
const ct = apiOperator.currentConsume = keys.length > 0 ? keys[0] : 'None';
|
|
702
|
+
return ct;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// ========== 模拟 setEditStatus(你原有逻辑) ==========
|
|
706
|
+
function setEditStatus(event: KeyboardEvent, status: boolean) {
|
|
707
|
+
// TODO: 根据你的业务逻辑实现
|
|
708
|
+
console.log('setEditStatus called:', event.key, status);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// ========== 主渲染函数 ==========
|
|
712
|
+
function renderConsumeSection(apiOperator: any, container: HTMLElement, bodyCnr: any) {
|
|
713
|
+
container.innerHTML = '';
|
|
714
|
+
|
|
715
|
+
container.appendChild(bodyCnr);
|
|
716
|
+
|
|
717
|
+
// 创建外层包裹 div
|
|
718
|
+
const wrapperDiv = createElement('div', {}, ['codigma-apiunit-parakeyvalues']);
|
|
719
|
+
|
|
720
|
+
// 1. Content-Type 选择器
|
|
721
|
+
const selectWrapper = createConsumeSelect(apiOperator, container, bodyCnr);
|
|
722
|
+
wrapperDiv.appendChild(selectWrapper);
|
|
723
|
+
|
|
724
|
+
// 2. 请求体区域(不再使用固定 ID)
|
|
725
|
+
const reqBodyContainer = createElement('div', {}, ['codigma-apiunit-request-body-info']); // 无 id,避免冲突
|
|
726
|
+
renderRequestBodyInto(apiOperator, reqBodyContainer); // 改为传入目标容器
|
|
727
|
+
wrapperDiv.appendChild(reqBodyContainer);
|
|
728
|
+
|
|
729
|
+
// 将整个包裹 div 添加到外部容器
|
|
730
|
+
container.appendChild(wrapperDiv);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
|
|
369
734
|
function createSectionResponse(apiOperator: any) {
|
|
370
735
|
const responseSection = document.createElement('div');
|
|
371
736
|
responseSection.setAttribute('data-layer', 'reqresponse');
|
|
@@ -405,6 +770,11 @@ function createTimeStatusElement(apiOperator: any) {
|
|
|
405
770
|
return timeStatus;
|
|
406
771
|
}
|
|
407
772
|
|
|
773
|
+
function updateTimeStatus(timeStatus: any, apiOperator: any) {
|
|
774
|
+
timeStatus.textContent
|
|
775
|
+
= `Status: ${apiOperator.response.status || ""} ${apiOperator.response.statusText || ""} Time: ${apiOperator.requestDuration || ""}`;
|
|
776
|
+
}
|
|
777
|
+
|
|
408
778
|
function createRow(parameter: any) {
|
|
409
779
|
const petIdRow = document.createElement('div');
|
|
410
780
|
petIdRow.setAttribute('data-layer', 'keyValue');
|
|
@@ -420,7 +790,6 @@ function createRow(parameter: any) {
|
|
|
420
790
|
|
|
421
791
|
// 可选:添加输入事件监听(根据需求)
|
|
422
792
|
petIdValue.addEventListener('input', (e: any) => {
|
|
423
|
-
console.log('当前值:', e.target.value);
|
|
424
793
|
// 这里可以添加保存逻辑(如更新状态/发送请求
|
|
425
794
|
parameter["value"] = e.target.value
|
|
426
795
|
});
|
|
@@ -437,7 +806,7 @@ function createInputElement() {
|
|
|
437
806
|
return inputText;
|
|
438
807
|
}
|
|
439
808
|
|
|
440
|
-
function createSelectRow(
|
|
809
|
+
function createSelectRow(name: string, args: any) {
|
|
441
810
|
// 创建外层容器div
|
|
442
811
|
const container = document.createElement('div');
|
|
443
812
|
container.setAttribute('data-layer', 'keyValue');
|
|
@@ -445,9 +814,9 @@ function createSelectRow(auths: any, authValues: any) {
|
|
|
445
814
|
|
|
446
815
|
// 创建type显示div
|
|
447
816
|
const typeLabel = document.createElement('div');
|
|
448
|
-
typeLabel.setAttribute('data-layer',
|
|
817
|
+
typeLabel.setAttribute('data-layer', name);
|
|
449
818
|
typeLabel.className = 'type codigma-apiunit-send';
|
|
450
|
-
typeLabel.textContent =
|
|
819
|
+
typeLabel.textContent = name + ":";
|
|
451
820
|
|
|
452
821
|
// 创建select元素
|
|
453
822
|
const selectElement: any = document.createElement('select');
|
|
@@ -456,22 +825,13 @@ function createSelectRow(auths: any, authValues: any) {
|
|
|
456
825
|
selectElement.setAttribute('data-layer', 'valueText');
|
|
457
826
|
|
|
458
827
|
// 示例选项(可根据实际需求添加
|
|
459
|
-
|
|
828
|
+
args.forEach((auth: any) => {
|
|
460
829
|
const option1 = document.createElement('option');
|
|
461
|
-
option1.value = auth["
|
|
462
|
-
option1.textContent = auth["
|
|
830
|
+
option1.value = auth["value"];
|
|
831
|
+
option1.textContent = (auth['displayName'] != null || auth['label'] != null) ? (auth["displayName"] || auth['label']): auth["value"];
|
|
463
832
|
selectElement.appendChild(option1);
|
|
464
833
|
})
|
|
465
834
|
|
|
466
|
-
// 添加选择事件监听
|
|
467
|
-
selectElement.addEventListener('change', function (event: any) {
|
|
468
|
-
//切换前先移除掉原来的元素
|
|
469
|
-
authValues && Array.from(authValues.children).slice(1).forEach((el: any) => el.remove());
|
|
470
|
-
const auth = auths[event.target.selectedIndex];
|
|
471
|
-
let parameters = auth.parameters || [];
|
|
472
|
-
const authRows = parameters.map((parameter: any) => createRow(parameter));
|
|
473
|
-
authValues.append(...authRows);
|
|
474
|
-
});
|
|
475
835
|
// 组装DOM结构
|
|
476
836
|
container.appendChild(typeLabel);
|
|
477
837
|
container.appendChild(selectElement);
|
|
@@ -486,6 +846,179 @@ function isHeaderParam(param: any) {
|
|
|
486
846
|
return param.in === 'header';
|
|
487
847
|
}
|
|
488
848
|
|
|
849
|
+
|
|
850
|
+
async function generateOAuth2Token(apiInfo: any) {
|
|
851
|
+
// TODO 生成OAuth2.0 Token
|
|
852
|
+
// 1. 获取访问令牌
|
|
853
|
+
const accessToken = await getAccessToken(apiInfo);
|
|
854
|
+
apiInfo.auth.token = accessToken
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
|
|
858
|
+
/**
|
|
859
|
+
* 获取 OAuth 2.0 访问令牌
|
|
860
|
+
* @returns {Promise<string>} 访问令牌
|
|
861
|
+
*/
|
|
862
|
+
async function getAccessToken(apiInfo: any) {
|
|
863
|
+
const auth = apiInfo.auth;
|
|
864
|
+
if (auth == null) {
|
|
865
|
+
throw new Error('OAuth2.0认证信息未配置');
|
|
866
|
+
}
|
|
867
|
+
const CLIENT_ID = auth.clientId;
|
|
868
|
+
const CLIENT_SECRET = auth.clientSecret;
|
|
869
|
+
const SCOPE = auth.scopes;
|
|
870
|
+
|
|
871
|
+
if (apiInfo.auth.grantType == 'client_credentials') {
|
|
872
|
+
try {
|
|
873
|
+
console.log('正在获取访问令牌...');
|
|
874
|
+
|
|
875
|
+
// 构造请求头
|
|
876
|
+
const headerParams: any = {
|
|
877
|
+
'Content-Type': 'application/x-www-form-urlencoded'
|
|
878
|
+
};
|
|
879
|
+
// 构造请求体 (使用 client_credentials 流)
|
|
880
|
+
const bodyParams = new URLSearchParams();
|
|
881
|
+
bodyParams.append('grant_type', 'client_credentials');
|
|
882
|
+
if (SCOPE) {
|
|
883
|
+
bodyParams.append('scope', SCOPE);
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
if (apiInfo.auth.clientAuthentication == 'Body') {
|
|
887
|
+
bodyParams.append('client_id', CLIENT_ID);
|
|
888
|
+
bodyParams.append('client_secret', CLIENT_SECRET);
|
|
889
|
+
} else {
|
|
890
|
+
// 如果是 Headers 方式,则在后续的 fetch 请求中添加 Authorization 头
|
|
891
|
+
headerParams['Authorization'] = 'Basic ' + btoa(CLIENT_ID + ':' + CLIENT_SECRET);
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
const response = await fetch(auth.tokenEndpoint, {
|
|
895
|
+
method: 'POST',
|
|
896
|
+
headers: headerParams,
|
|
897
|
+
body: bodyParams.toString()
|
|
898
|
+
})
|
|
899
|
+
|
|
900
|
+
if (!response.ok) {
|
|
901
|
+
const errorData = await response.json().catch(() => ({}));
|
|
902
|
+
throw new Error(`获取令牌失败: ${response.status} ${response.statusText}. ${JSON.stringify(errorData)}`);
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
const tokenData = await response.json();
|
|
906
|
+
console.log('令牌获取成功:', tokenData);
|
|
907
|
+
return tokenData.access_token;
|
|
908
|
+
} catch (error) {
|
|
909
|
+
console.error('获取访问令牌时出错:', error);
|
|
910
|
+
throw error;
|
|
911
|
+
}
|
|
912
|
+
} else if (apiInfo.auth.grantType == 'Resource Owner Password Credentials') {
|
|
913
|
+
|
|
914
|
+
} else if (apiInfo.auth.grantType == 'authorization_code') {
|
|
915
|
+
// ========== 配置:替换为你在本地 OAuth 服务注册的客户端信息 ==========
|
|
916
|
+
const config = {
|
|
917
|
+
clientId: apiInfo.auth.clientId, // 替换为你的 client_id
|
|
918
|
+
clientSecret: apiInfo.auth.clientSecret, // 替换为你的 client_secret
|
|
919
|
+
redirectUri: apiInfo.auth.redirectURI, // 必须与注册的 redirect_uri 一致
|
|
920
|
+
authUrl: apiInfo.auth.authorizationEndpoint,
|
|
921
|
+
tokenUrl: apiInfo.auth.tokenEndpoint,
|
|
922
|
+
scope: apiInfo.auth.scopes // 可选: 'openid profile email' 如果服务支持
|
|
923
|
+
};
|
|
924
|
+
|
|
925
|
+
// 从 URL 获取参数
|
|
926
|
+
function getUrlParams() {
|
|
927
|
+
const params = new URLSearchParams(window.location.search);
|
|
928
|
+
return Object.fromEntries(params.entries());
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
// 构建授权 URL 并跳转
|
|
932
|
+
function redirectToAuth() {
|
|
933
|
+
const state = Math.random().toString(36).substring(2);
|
|
934
|
+
const nonce = Math.random().toString(36).substring(2); // OpenID Connect 推荐使用 nonce
|
|
935
|
+
const authUrl = new URL(config.authUrl);
|
|
936
|
+
authUrl.searchParams.append('client_id', config.clientId);
|
|
937
|
+
authUrl.searchParams.append('redirect_uri', config.redirectUri);
|
|
938
|
+
authUrl.searchParams.append('response_type', 'code');
|
|
939
|
+
authUrl.searchParams.append('scope', config.scope);
|
|
940
|
+
authUrl.searchParams.append('state', state);
|
|
941
|
+
authUrl.searchParams.append('nonce', nonce); // 用于 ID Token 验证
|
|
942
|
+
authUrl.searchParams.append('access_type', 'offline'); // 请求 refresh_token(如果支持)
|
|
943
|
+
|
|
944
|
+
const newTab = window.open(authUrl.toString(), '_blank');
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
// // 使用授权码换取 Token
|
|
948
|
+
// async function exchangeCodeForToken(code: any) {
|
|
949
|
+
// try {
|
|
950
|
+
// const response = await fetch(config.tokenUrl, {
|
|
951
|
+
// method: 'POST',
|
|
952
|
+
// headers: {
|
|
953
|
+
// 'Content-Type': 'application/x-www-form-urlencoded',
|
|
954
|
+
// 'Authorization': 'Basic ' + btoa(config.clientId + ':' + config.clientSecret)
|
|
955
|
+
// },
|
|
956
|
+
// body: new URLSearchParams({
|
|
957
|
+
// // 'client_id': config.clientId,
|
|
958
|
+
// // 'client_secret': config.clientSecret,
|
|
959
|
+
// 'code': code,
|
|
960
|
+
// 'redirect_uri': config.redirectUri,
|
|
961
|
+
// 'grant_type': 'authorization_code'
|
|
962
|
+
// })
|
|
963
|
+
// });
|
|
964
|
+
|
|
965
|
+
// if (!response.ok) {
|
|
966
|
+
// const errorText = await response.text();
|
|
967
|
+
// throw new Error(`HTTP ${response.status}: ${errorText}`);
|
|
968
|
+
// }
|
|
969
|
+
|
|
970
|
+
// const tokenData = await response.json();
|
|
971
|
+
// console.log('Token Response:', tokenData);
|
|
972
|
+
|
|
973
|
+
// // 可选:清除 URL 参数
|
|
974
|
+
// // history.replaceState({}, document.title, window.location.pathname);
|
|
975
|
+
// } catch (error) {
|
|
976
|
+
// console.error('Token Exchange Error:', error);
|
|
977
|
+
// }
|
|
978
|
+
// }
|
|
979
|
+
|
|
980
|
+
// // 页面初始化
|
|
981
|
+
// document.addEventListener('DOMContentLoaded', () => {
|
|
982
|
+
// const loginBtn = document.getElementById('loginBtn');
|
|
983
|
+
// const urlParams = getUrlParams();
|
|
984
|
+
|
|
985
|
+
// if (urlParams.code) {
|
|
986
|
+
// // 已收到授权码
|
|
987
|
+
// loginBtn.style.display = 'none';
|
|
988
|
+
// exchangeCodeForToken(urlParams.code);
|
|
989
|
+
// } else {
|
|
990
|
+
|
|
991
|
+
// }
|
|
992
|
+
// });
|
|
993
|
+
|
|
994
|
+
redirectToAuth();
|
|
995
|
+
} else if (apiInfo.auth.grantType == 'Implicit') {
|
|
996
|
+
|
|
997
|
+
} else {
|
|
998
|
+
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
|
|
1003
|
+
function getBodyEditorContent(apiOperator: any): string {
|
|
1004
|
+
const ct = apiOperator.currentConsume || 'None';
|
|
1005
|
+
return apiOperator.requestBody.content[ct];
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
|
|
1009
|
+
|
|
1010
|
+
let gotResponse = false;
|
|
1011
|
+
|
|
1012
|
+
let ifSendingRequest = false;
|
|
1013
|
+
let requestDuration: string = "0";
|
|
1014
|
+
let responseObj: {
|
|
1015
|
+
status ?: number | string;
|
|
1016
|
+
statusText ?: string;
|
|
1017
|
+
body ?: string;//响应体统一转换成字符串
|
|
1018
|
+
} = { };
|
|
1019
|
+
// 创建一个新的 AbortController 实例
|
|
1020
|
+
let controller: AbortController | undefined;
|
|
1021
|
+
|
|
489
1022
|
/**
|
|
490
1023
|
*
|
|
491
1024
|
*
|
|
@@ -500,43 +1033,45 @@ function isHeaderParam(param: any) {
|
|
|
500
1033
|
* @param {*} apiOperator
|
|
501
1034
|
* @param {*} apiInfo
|
|
502
1035
|
*/
|
|
503
|
-
|
|
504
1036
|
function sendRequest(apiOperator: any, responseSectionRef: any) {
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
const result = checkIfParameter(apiOperator);
|
|
1037
|
+
const apiInfo = apiOperator
|
|
1038
|
+
let reuqestUrl = getRequestUrl(apiInfo);
|
|
1039
|
+
|
|
1040
|
+
//TODO 根据参数类型构造请求头和请求体,apiInfo['parameterHasFormDataVer2']表示有formData参数,暂时未区分具体的content-type,待改造
|
|
1041
|
+
let header = apiInfo['parameterHasFormDataVer2'] ? 'application/x-www-form-urlencoded' :
|
|
1042
|
+
((apiInfo['parameterHasBody']) ? apiInfo['currentConsume'] : 'application/json');
|
|
512
1043
|
|
|
513
|
-
let header = result.hasRequestBody ? 'application/json' :
|
|
514
|
-
(result.hasRequestFormData ? 'application/x-www-form-urlencoded' : 'application/json');
|
|
515
1044
|
let headers: any = {
|
|
516
1045
|
'Content-Type': header
|
|
517
1046
|
}
|
|
518
|
-
|
|
519
|
-
//
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
1047
|
+
const headerParas = getHeadersParams(apiInfo, apiInfo.rawApiInfo.parameters || []);
|
|
1048
|
+
// 合并自定义头参数
|
|
1049
|
+
Object.assign(headers, headerParas);
|
|
1050
|
+
// 构造 Basic Auth 头
|
|
1051
|
+
addAuthHeader(apiInfo, headers);
|
|
1052
|
+
|
|
1053
|
+
let body;
|
|
1054
|
+
if (apiInfo.method.toUpperCase() == "POST" || apiInfo.method.toUpperCase() == "PUT") {
|
|
1055
|
+
if (apiInfo['currentConsume'] == 'application/json' && apiInfo.requestBody != null) {
|
|
1056
|
+
body = getBodyEditorContent(apiOperator);
|
|
1057
|
+
} else if (apiInfo['parameterHasFormDataVer2']) {
|
|
1058
|
+
body = getRequestFormData(apiInfo.rawApiInfo);
|
|
1059
|
+
} else if (apiInfo['currentConsume'] == 'application/x-www-form-urlencoded') {
|
|
1060
|
+
for (const key of apiInfo["requestBody"]["content"][apiInfo['currentConsume']]) {
|
|
1061
|
+
if (body == null || body == '') {
|
|
1062
|
+
body = key.name + "=" + key.value;
|
|
1063
|
+
} else {
|
|
1064
|
+
body = body + "&" + key.name + "=" + key.value;
|
|
1065
|
+
}
|
|
525
1066
|
}
|
|
1067
|
+
} else {
|
|
1068
|
+
body = "";
|
|
526
1069
|
}
|
|
1070
|
+
} else {
|
|
1071
|
+
body = "";
|
|
527
1072
|
}
|
|
528
1073
|
|
|
529
|
-
|
|
530
|
-
(result.hasRequestFormData ? getRequestFormData(apiOperator.rawApiInfo) : null);
|
|
531
|
-
|
|
532
|
-
//TODO
|
|
533
|
-
if (apiOperator.custom) {
|
|
534
|
-
if (apiOperator.method.toUpperCase() == "POST" || apiOperator.method.toUpperCase() == "PUT") {
|
|
535
|
-
body = apiOperator.requestBody;
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
apiOperator.ifSendingRequest = true;
|
|
1074
|
+
ifSendingRequest = true;
|
|
540
1075
|
const startTime = Date.now(); // 记录开始时间
|
|
541
1076
|
|
|
542
1077
|
apiOperator.controller = new AbortController();
|
|
@@ -547,32 +1082,32 @@ function sendRequest(apiOperator: any, responseSectionRef: any) {
|
|
|
547
1082
|
|
|
548
1083
|
// 使用 fetch 发送请求,并传递 signal
|
|
549
1084
|
fetch(reuqestUrl, {
|
|
550
|
-
method:
|
|
1085
|
+
method: apiInfo.method.toUpperCase(),
|
|
551
1086
|
headers: headers,
|
|
552
|
-
body: body
|
|
1087
|
+
body: body,
|
|
553
1088
|
signal: signal
|
|
554
1089
|
})
|
|
555
1090
|
.then(response => {
|
|
556
1091
|
if (!response.ok) {
|
|
557
|
-
|
|
1092
|
+
responseObj = {
|
|
558
1093
|
status: response.status,
|
|
559
|
-
statusText: response.statusText
|
|
1094
|
+
statusText: response.statusText,
|
|
1095
|
+
body: ""
|
|
560
1096
|
}
|
|
561
1097
|
|
|
562
1098
|
const endTime = Date.now(); // 即使在错误的情况下也记录结束时间
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
// apiOperator.responseJsoneditor.value = "";
|
|
1099
|
+
requestDuration = formatDuration(endTime - startTime);
|
|
1100
|
+
ifSendingRequest = false;
|
|
566
1101
|
throw new Error('Network response was not ok.');
|
|
567
1102
|
}
|
|
568
1103
|
const endTime = Date.now(); // 记录结束时间
|
|
569
|
-
|
|
1104
|
+
requestDuration = formatDuration(endTime - startTime); // 计算耗时
|
|
570
1105
|
|
|
571
1106
|
const responsebodyElement = responseSectionRef.querySelector('[data-layer="responsebody"]');
|
|
572
1107
|
responsebodyElement.removeChild(overlayLayerContainer);
|
|
573
1108
|
|
|
574
|
-
|
|
575
|
-
|
|
1109
|
+
ifSendingRequest = false;
|
|
1110
|
+
responseObj = {
|
|
576
1111
|
status: response.status,
|
|
577
1112
|
statusText: response.statusText
|
|
578
1113
|
}
|
|
@@ -593,18 +1128,19 @@ function sendRequest(apiOperator: any, responseSectionRef: any) {
|
|
|
593
1128
|
});
|
|
594
1129
|
})
|
|
595
1130
|
.then(data => {
|
|
596
|
-
|
|
1131
|
+
gotResponse = true;
|
|
597
1132
|
const responsebodyElement = responseSectionRef.querySelector('[data-layer="responsebody"]');
|
|
598
1133
|
// 此时 data 可能是 JSON 对象,也可能是文本字符串
|
|
599
1134
|
if (typeof data === 'object') {
|
|
600
1135
|
// 假设 data 是 JSON 对象,你可以在这里处理它
|
|
601
1136
|
console.log('Received JSON:', data);
|
|
602
|
-
|
|
1137
|
+
responseObj.body = JSON.stringify(data, null, 4);
|
|
603
1138
|
} else {
|
|
604
1139
|
// 假设 data 是文本字符串,你可以在这里处理它
|
|
605
1140
|
console.log('Received text:', data);
|
|
606
|
-
|
|
1141
|
+
responseObj.body = data;
|
|
607
1142
|
}
|
|
1143
|
+
responsebodyElement.textContent = responseObj.body;
|
|
608
1144
|
})
|
|
609
1145
|
.catch(error => {
|
|
610
1146
|
// 错误处理
|
|
@@ -612,11 +1148,6 @@ function sendRequest(apiOperator: any, responseSectionRef: any) {
|
|
|
612
1148
|
});
|
|
613
1149
|
}
|
|
614
1150
|
|
|
615
|
-
function updateTimeStatus(timeStatus: any, apiOperator: any) {
|
|
616
|
-
timeStatus.textContent
|
|
617
|
-
= `Status: ${apiOperator.response.status || ""} ${apiOperator.response.statusText || ""} Time: ${apiOperator.requestDuration || ""}`;
|
|
618
|
-
}
|
|
619
|
-
|
|
620
1151
|
function createRequestOverlayLayer(apiOperator: any, responseSectionRef: any) {
|
|
621
1152
|
// 创建主容器
|
|
622
1153
|
const container = document.createElement('div');
|
|
@@ -673,40 +1204,15 @@ function createRequestOverlayLayer(apiOperator: any, responseSectionRef: any) {
|
|
|
673
1204
|
return container
|
|
674
1205
|
}
|
|
675
1206
|
|
|
676
|
-
function checkIfParameter(apiOperator: any) {
|
|
677
|
-
let hasRequestBody = false;
|
|
678
|
-
let hasRequestFormData = false;
|
|
679
|
-
const parameters = apiOperator.rawApiInfo.parameters;
|
|
680
|
-
if (parameters) {
|
|
681
|
-
for (let index = 0; index < parameters.length; index++) {
|
|
682
|
-
const parameter = parameters[index];
|
|
683
|
-
if (parameter.in == "query" || parameter.in == "path") {
|
|
684
|
-
} else if (parameter.in == "body") {
|
|
685
|
-
hasRequestBody = true;
|
|
686
|
-
parameter.name = parameter.name.charAt(0).toUpperCase() + parameter.name.slice(1);
|
|
687
|
-
} else if (parameter.in == "formData") {
|
|
688
|
-
hasRequestFormData = true;
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
//support openapi 3.0
|
|
694
|
-
const requestBody = apiOperator.rawApiInfo.requestBody;
|
|
695
|
-
if (requestBody) {
|
|
696
|
-
hasRequestBody = true;
|
|
697
|
-
}
|
|
698
|
-
// 返回包含两个状态的对象
|
|
699
|
-
return { hasRequestBody, hasRequestFormData };
|
|
700
|
-
}
|
|
701
1207
|
|
|
702
1208
|
function formatDuration(milliseconds: number) {
|
|
703
|
-
let totalSeconds
|
|
704
|
-
let seconds:
|
|
705
|
-
let minutes:
|
|
706
|
-
let hours:
|
|
1209
|
+
let totalSeconds = Math.floor(milliseconds / 1000);
|
|
1210
|
+
let seconds: any = totalSeconds % 60;
|
|
1211
|
+
let minutes: any = Math.floor(totalSeconds / 60) % 60;
|
|
1212
|
+
let hours: any = Math.floor(totalSeconds / (60 * 60));
|
|
707
1213
|
|
|
708
1214
|
// 毫秒部分
|
|
709
|
-
let millisecondsPart:
|
|
1215
|
+
let millisecondsPart: any = Math.floor(milliseconds % 1000);
|
|
710
1216
|
// 毫秒不足三位时前面补0
|
|
711
1217
|
millisecondsPart = millisecondsPart.toString().padStart(3, '0');
|
|
712
1218
|
|
|
@@ -719,10 +1225,18 @@ function formatDuration(milliseconds: number) {
|
|
|
719
1225
|
return `${hours}h${minutes}m${seconds}s${millisecondsPart}ms`;
|
|
720
1226
|
}
|
|
721
1227
|
|
|
722
|
-
function
|
|
723
|
-
|
|
1228
|
+
function clickAbortRequest() {
|
|
1229
|
+
// 如果你想取消请求,调用 controller 的 abort 方法
|
|
1230
|
+
if (controller) {
|
|
1231
|
+
controller.abort();
|
|
1232
|
+
ifSendingRequest = false;
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
function getRequestUrl(apiInfo: any) {
|
|
1237
|
+
let reuqestUrl = apiInfo.url;
|
|
724
1238
|
|
|
725
|
-
const requestParameters =
|
|
1239
|
+
const requestParameters = apiInfo.rawApiInfo.parameters || [];
|
|
726
1240
|
if (requestParameters == null) {
|
|
727
1241
|
return reuqestUrl;
|
|
728
1242
|
}
|
|
@@ -733,13 +1247,51 @@ function getRequestUrl(apiOperator: any) {
|
|
|
733
1247
|
}
|
|
734
1248
|
}
|
|
735
1249
|
|
|
736
|
-
let queryParams = getQueryParams(
|
|
1250
|
+
let queryParams = getQueryParams(apiInfo, requestParameters);
|
|
737
1251
|
reuqestUrl = queryParams.length > 0 ? (reuqestUrl + "?" + queryParams.join("&")) : reuqestUrl;
|
|
738
1252
|
|
|
739
1253
|
return reuqestUrl;
|
|
740
1254
|
}
|
|
741
1255
|
|
|
742
|
-
function
|
|
1256
|
+
function addAuthHeader(apiInfo: any, headers: any) {
|
|
1257
|
+
const env = isBrowserEnvironment();
|
|
1258
|
+
if (apiInfo.auth.authType == "Basic Auth" && apiInfo.auth != null) {
|
|
1259
|
+
if (env) {
|
|
1260
|
+
const credentials = btoa(`${apiInfo.auth.username}:${apiInfo.auth.passWord}`); // btoa 是浏览器内置的 Base64 编码函数
|
|
1261
|
+
headers['Authorization'] = `Basic ${credentials}`;
|
|
1262
|
+
} else {
|
|
1263
|
+
const buffer = Buffer.from(`${apiInfo.auth.username}:${apiInfo.auth.passWord}`);
|
|
1264
|
+
const credentials = buffer.toString('base64');
|
|
1265
|
+
headers['Authorization'] = `Basic ${credentials}`;
|
|
1266
|
+
}
|
|
1267
|
+
} else if (apiInfo.auth.authType == "OAuth 2.0" && apiInfo.auth != null) {
|
|
1268
|
+
if (apiInfo.auth.token != null || apiInfo.auth.token != '') {
|
|
1269
|
+
headers['Authorization'] = `Bearer ${apiInfo.auth.token}`;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
function getHeadersParams(apiInfo: any, requestParameters: any) {
|
|
1275
|
+
let headersParams = [];
|
|
1276
|
+
for (const element of requestParameters) {
|
|
1277
|
+
if (element.in == "header") {
|
|
1278
|
+
headersParams[element.name] = element.value
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
if (apiInfo.customHeaderparameters) {
|
|
1283
|
+
for (let index = 0; index < apiInfo.customHeaderparameters.length; index++) {
|
|
1284
|
+
const paras = apiInfo.customHeaderparameters[index];
|
|
1285
|
+
if (paras.name != '' && paras.value != '' && paras.name != null && paras.value != null) {
|
|
1286
|
+
headersParams[paras.name] = paras.value
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
return headersParams;
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
function getQueryParams(apiInfo: any, requestParameters: any) {
|
|
743
1295
|
let queryParams = [];
|
|
744
1296
|
for (const element of requestParameters) {
|
|
745
1297
|
if (element.in == "query") {
|
|
@@ -755,9 +1307,9 @@ function getQueryParams(apiOperator: any, requestParameters: any) {
|
|
|
755
1307
|
}
|
|
756
1308
|
}
|
|
757
1309
|
|
|
758
|
-
if (
|
|
759
|
-
for (let index = 0; index <
|
|
760
|
-
const paras =
|
|
1310
|
+
if (apiInfo.customQueryparameters) {
|
|
1311
|
+
for (let index = 0; index < apiInfo.customQueryparameters.length; index++) {
|
|
1312
|
+
const paras = apiInfo.customQueryparameters[index];
|
|
761
1313
|
if (paras.name != '' && paras.value != '' && paras.name != null && paras.value != null) {
|
|
762
1314
|
queryParams.push(paras.name + "=" + paras.value)
|
|
763
1315
|
}
|
|
@@ -788,6 +1340,16 @@ function getRequestFormData(rawApiInfo: any) {
|
|
|
788
1340
|
return formData;
|
|
789
1341
|
}
|
|
790
1342
|
|
|
1343
|
+
function isBrowserEnvironment() {
|
|
1344
|
+
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
|
|
1345
|
+
return true; // 浏览器环境
|
|
1346
|
+
} else if (typeof process !== 'undefined' && process.versions && process.versions.node) {
|
|
1347
|
+
return false; // Node.js 环境
|
|
1348
|
+
} else {
|
|
1349
|
+
return false;
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
|
|
791
1353
|
|
|
792
1354
|
function createSvg() {
|
|
793
1355
|
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
@@ -810,20 +1372,17 @@ function createSvg() {
|
|
|
810
1372
|
|
|
811
1373
|
function parseParaModel(parameterObj: any, dataDef: any) {
|
|
812
1374
|
let bodyModel;
|
|
813
|
-
if (parameterObj
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
bodyModel = parseElement(itemObj);
|
|
822
|
-
}
|
|
823
|
-
bodyModel = [bodyModel];
|
|
1375
|
+
if (parameterObj.schema['$ref']) { // 对象类型
|
|
1376
|
+
bodyModel = parseModel(parameterObj.schema['$ref'], dataDef);
|
|
1377
|
+
} else if (parameterObj.schema['type'] == 'array') { // 数组类型
|
|
1378
|
+
const itemObj = parameterObj.schema['items'];
|
|
1379
|
+
if (itemObj['$ref']) {
|
|
1380
|
+
bodyModel = parseModel(itemObj['$ref'], dataDef);
|
|
1381
|
+
} else if (itemObj['type']) {
|
|
1382
|
+
bodyModel = parseElement(itemObj);
|
|
824
1383
|
}
|
|
1384
|
+
bodyModel = [bodyModel];
|
|
825
1385
|
}
|
|
826
|
-
|
|
827
1386
|
return bodyModel;
|
|
828
1387
|
}
|
|
829
1388
|
|
|
@@ -856,10 +1415,69 @@ function parseModel(modelDef: any, apiDef: any) {
|
|
|
856
1415
|
return model;
|
|
857
1416
|
}
|
|
858
1417
|
|
|
1418
|
+
function parseFormDataModel(modelDef: any, apiDef: any) {
|
|
1419
|
+
const model: any = [];
|
|
1420
|
+
const bodyName = modelDef.substring(modelDef.lastIndexOf('/') + 1);
|
|
1421
|
+
const def = apiDef[bodyName];
|
|
1422
|
+
const props = def['properties'];
|
|
1423
|
+
if (props) {
|
|
1424
|
+
for (const key in props) {
|
|
1425
|
+
if (Object.prototype.hasOwnProperty.call(props, key)) {
|
|
1426
|
+
const element = props[key];
|
|
1427
|
+
let modelEle: any;
|
|
1428
|
+
if (element.hasOwnProperty('items') && element['type'] == 'array') {
|
|
1429
|
+
if (element["items"]['$ref']) {
|
|
1430
|
+
modelEle = [parseModel(element["items"]['$ref'], apiDef)]
|
|
1431
|
+
} else if (element["items"]['type']) {
|
|
1432
|
+
modelEle = [parseElement(element["items"])];
|
|
1433
|
+
}
|
|
1434
|
+
if (modelEle) {
|
|
1435
|
+
model.push({
|
|
1436
|
+
type: 'string',
|
|
1437
|
+
uiType: 'text',
|
|
1438
|
+
name: key,
|
|
1439
|
+
value: JSON.stringify(modelEle)
|
|
1440
|
+
});
|
|
1441
|
+
}
|
|
1442
|
+
} else if (element['type']) {
|
|
1443
|
+
model.push({
|
|
1444
|
+
type: element['type'],
|
|
1445
|
+
uiType: ((element['type'] == 'integer' || element['type'] == 'number') ? 'number' : 'text'),
|
|
1446
|
+
name: key,
|
|
1447
|
+
value: parseElement(element)
|
|
1448
|
+
});
|
|
1449
|
+
} else if (element['$ref']) {
|
|
1450
|
+
const bodyModel = parseModel(element['$ref'], apiDef);
|
|
1451
|
+
model.push({
|
|
1452
|
+
type: 'string',
|
|
1453
|
+
uiType: 'text',
|
|
1454
|
+
name: key,
|
|
1455
|
+
value: JSON.stringify(bodyModel)
|
|
1456
|
+
});
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
return model;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
function parseFormDataParaModel(parameterObj: any, dataDef: any) {
|
|
1466
|
+
let bodyModel: any = [];
|
|
1467
|
+
if (parameterObj.schema['$ref']) { // 对象类型
|
|
1468
|
+
bodyModel = parseFormDataModel(parameterObj.schema['$ref'], dataDef);
|
|
1469
|
+
}
|
|
1470
|
+
return bodyModel;
|
|
1471
|
+
}
|
|
1472
|
+
|
|
859
1473
|
function parseElement(element: any) {
|
|
860
1474
|
let elementValue;
|
|
861
1475
|
if (element['type'].includes('integer')) {
|
|
862
|
-
|
|
1476
|
+
if (element['enum']) {
|
|
1477
|
+
elementValue = element['enum'][0];
|
|
1478
|
+
} else {
|
|
1479
|
+
elementValue = 0;
|
|
1480
|
+
}
|
|
863
1481
|
} else if (element['type'].includes('boolean')) {
|
|
864
1482
|
elementValue = false;
|
|
865
1483
|
} else if (element['type'].includes('string')) {
|
|
@@ -870,6 +1488,12 @@ function parseElement(element: any) {
|
|
|
870
1488
|
}
|
|
871
1489
|
}
|
|
872
1490
|
|
|
1491
|
+
// 如果有default则用default的值
|
|
1492
|
+
if (element['default']) {
|
|
1493
|
+
elementValue = element['default'];
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
//如果有example则用example的值
|
|
873
1497
|
if (element['example']) {
|
|
874
1498
|
elementValue = element['example'];
|
|
875
1499
|
}
|
|
@@ -877,6 +1501,18 @@ function parseElement(element: any) {
|
|
|
877
1501
|
return elementValue;
|
|
878
1502
|
}
|
|
879
1503
|
|
|
1504
|
+
function parseElementType(element: any) {
|
|
1505
|
+
if (element['type'].includes('integer')) {
|
|
1506
|
+
return 'integer';
|
|
1507
|
+
} else if (element['type'].includes('boolean')) {
|
|
1508
|
+
return 'boolean';
|
|
1509
|
+
} else if (element['type'].includes('string')) {
|
|
1510
|
+
return 'string';
|
|
1511
|
+
}
|
|
1512
|
+
return 'string';
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
|
|
880
1516
|
const HTTP_METHODS = ['get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace'] as const;
|
|
881
1517
|
type HttpMethod = typeof HTTP_METHODS[number]; // 等价于你的 HttpMethods 的值类型
|
|
882
1518
|
|
|
@@ -916,56 +1552,123 @@ function parseOpenAPI(openapiSpec: OpenAPIV3CustomDoc) {
|
|
|
916
1552
|
const apiOperator: any = {
|
|
917
1553
|
method: method.toUpperCase(),
|
|
918
1554
|
url: path,
|
|
919
|
-
rawApiInfo:
|
|
1555
|
+
rawApiInfo: operation,
|
|
920
1556
|
requestBody: null,
|
|
921
1557
|
response: {},
|
|
922
|
-
|
|
923
|
-
{
|
|
924
|
-
type: "No Auth"
|
|
925
|
-
},
|
|
926
|
-
{
|
|
927
|
-
type: "Basic Auth",
|
|
928
|
-
parameters: [
|
|
929
|
-
{
|
|
930
|
-
name: "userName",
|
|
931
|
-
value: ""
|
|
932
|
-
},
|
|
933
|
-
{
|
|
934
|
-
name: "password",
|
|
935
|
-
value: ""
|
|
936
|
-
}
|
|
937
|
-
]
|
|
938
|
-
}
|
|
939
|
-
]
|
|
1558
|
+
auth: {}
|
|
940
1559
|
};
|
|
941
1560
|
|
|
942
1561
|
if (operation) {
|
|
943
1562
|
// requestBody
|
|
944
1563
|
// support openapi 2.0
|
|
945
|
-
if (operation.parameters) {
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
1564
|
+
// if (operation.parameters) {
|
|
1565
|
+
// const parameter = operation.parameters.filter((val: any) => val.in == 'body');
|
|
1566
|
+
// if (parameter && parameter.length > 0) {
|
|
1567
|
+
// // let requestBody = parseParaModel(parameter[0], data['definitions']);
|
|
1568
|
+
// // apiOperator.requestBody = requestBody;
|
|
1569
|
+
// }
|
|
1570
|
+
// }
|
|
1571
|
+
|
|
1572
|
+
// //support openapi 3.0
|
|
1573
|
+
// if (operation.requestBody) {
|
|
1574
|
+
// const requestBodyObject = operation.requestBody as OpenAPIV3.RequestBodyObject //目前只支持对象类型 TODO 引用类型待支持
|
|
1575
|
+
// const content = requestBodyObject.content;
|
|
1576
|
+
// for (const key in content) {
|
|
1577
|
+
// if (Object.prototype.hasOwnProperty.call(content, key)) {
|
|
1578
|
+
// const element: OpenAPIV3.MediaTypeObject = content[key];
|
|
1579
|
+
// if (element) {
|
|
1580
|
+
// let requestBody = parseParaModel(element, openapiSpec["components"]!["schemas"]);
|
|
1581
|
+
// apiOperator.requestBody = requestBody;
|
|
1582
|
+
// }
|
|
1583
|
+
// }
|
|
1584
|
+
// }
|
|
1585
|
+
// }
|
|
1586
|
+
|
|
1587
|
+
|
|
1588
|
+
if (apiOperator.rawApiInfo.parameters) {
|
|
1589
|
+
const parameterBody = apiOperator.rawApiInfo.parameters.filter((val: any) => val.in == 'body');
|
|
1590
|
+
if (parameterBody && parameterBody.length > 0) {
|
|
1591
|
+
apiOperator["requestBody"] = {
|
|
1592
|
+
content: {},
|
|
1593
|
+
}
|
|
1594
|
+
apiOperator['consumes'] = apiOperator.rawApiInfo['consumes']
|
|
1595
|
+
const currentConsume = apiOperator.rawApiInfo['consumes'].length > 0 ? apiOperator.rawApiInfo['consumes'][0] : "application/json" //TODO 简化处理暂时取第一个
|
|
1596
|
+
apiOperator['currentConsume'] = currentConsume
|
|
1597
|
+
let requestBody: any = parseParaModel(parameterBody[0], openapiSpec['definitions']); // support openapi 2.0
|
|
1598
|
+
apiOperator["requestBody"]["content"][currentConsume] = JSON.stringify(requestBody, null, 4);
|
|
1599
|
+
apiOperator["parameterHasBody"] = true;//标记该接口有body参数,仅适用于openapi 2.0
|
|
1600
|
+
} else {
|
|
1601
|
+
for (const parameter of apiOperator.rawApiInfo.parameters) {
|
|
1602
|
+
if (parameter.in == 'query' || parameter.in == 'header' || parameter.in == 'path' || parameter.in == 'formData') {
|
|
1603
|
+
if (parameter.type == 'integer' || (parameter.schema != null && parameter.schema.type == 'integer')
|
|
1604
|
+
|| parameter.type == 'number' || (parameter.schema != null && parameter.schema.type == 'number')) {
|
|
1605
|
+
parameter.uiType = 'number';
|
|
1606
|
+
}
|
|
1607
|
+
if (parameter.type == 'string' || (parameter.schema != null && parameter.schema.type == 'string')) {
|
|
1608
|
+
parameter.uiType = 'text';
|
|
1609
|
+
}
|
|
1610
|
+
if (parameter.type == 'boolean' || (parameter.schema != null && parameter.schema.type == 'boolean')) {
|
|
1611
|
+
parameter.uiType = 'text';// TODO 未来可以改成checkbox
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
const parameterFormData = apiOperator.rawApiInfo.parameters.filter((val: any) => val.in == 'formData');
|
|
1616
|
+
if (parameterFormData && parameterFormData.length > 0) {
|
|
1617
|
+
apiOperator["parameterHasFormDataVer2"] = true;//标记该接口有formData参数,仅适用于openapi 2.0 body参数和formData参数互斥
|
|
1618
|
+
}
|
|
1619
|
+
// support openapi 3.0 enum parameter parsing
|
|
1620
|
+
for (const param of apiOperator.rawApiInfo.parameters) {
|
|
1621
|
+
const paramSchema = param.schema;
|
|
1622
|
+
if (paramSchema && paramSchema['$ref']) {
|
|
1623
|
+
const bodyName = paramSchema['$ref'].substring(paramSchema['$ref'].lastIndexOf('/') + 1);
|
|
1624
|
+
if (openapiSpec && openapiSpec["components"] != null && openapiSpec["components"]["schemas"]!=null) {
|
|
1625
|
+
const def = openapiSpec["components"] != null ? openapiSpec["components"]["schemas"][bodyName] : {type: ''};
|
|
1626
|
+
param.type = parseElementType(def);
|
|
1627
|
+
param.uiType = (param.type == 'integer' || param.type == 'number') ? 'number' : 'text';
|
|
1628
|
+
param.value = parseElement(def);
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
950
1632
|
}
|
|
951
1633
|
}
|
|
952
1634
|
|
|
953
1635
|
//support openapi 3.0
|
|
954
|
-
if (
|
|
955
|
-
const
|
|
956
|
-
|
|
1636
|
+
if (apiOperator.rawApiInfo.requestBody) {
|
|
1637
|
+
const content = apiOperator.rawApiInfo.requestBody.content;
|
|
1638
|
+
apiOperator["requestBody"] = {
|
|
1639
|
+
content: {}
|
|
1640
|
+
}
|
|
1641
|
+
|
|
957
1642
|
for (const key in content) {
|
|
958
1643
|
if (Object.prototype.hasOwnProperty.call(content, key)) {
|
|
959
|
-
const element
|
|
1644
|
+
const element = content[key];
|
|
1645
|
+
apiOperator['consumes']?.push(key);
|
|
960
1646
|
if (element) {
|
|
961
|
-
|
|
962
|
-
|
|
1647
|
+
if (element.schema == undefined) {
|
|
1648
|
+
console.log("pathKey is:", path);
|
|
1649
|
+
console.log("key is:", key);
|
|
1650
|
+
console.log("content is:", content);
|
|
1651
|
+
console.log("Unsupported requestBody schema format:", element);
|
|
1652
|
+
continue;
|
|
1653
|
+
}
|
|
1654
|
+
if (key != 'application/x-www-form-urlencoded' && key != 'multipart/form-data') {//TODO 支持更多的content-type
|
|
1655
|
+
let requestBody: any = parseParaModel(element, openapiSpec["components"]!["schemas"]);
|
|
1656
|
+
apiOperator["requestBody"]["content"][key] = JSON.stringify(requestBody, null, 4)
|
|
1657
|
+
} else {
|
|
1658
|
+
let requestFormDataBody: any = parseFormDataParaModel(element, openapiSpec["components"]!["schemas"]);
|
|
1659
|
+
apiOperator["requestBody"]["content"][key] = requestFormDataBody;
|
|
1660
|
+
}
|
|
1661
|
+
apiOperator["parameterHasBody"] = true;//标记该接口有body参数,仅适用于openapi 3.0
|
|
963
1662
|
}
|
|
964
1663
|
}
|
|
965
1664
|
}
|
|
1665
|
+
if (apiOperator.consumes) {
|
|
1666
|
+
if (apiOperator.consumes.length > 0) {
|
|
1667
|
+
apiOperator['currentConsume'] = apiOperator['consumes'][0]
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
966
1670
|
}
|
|
967
1671
|
|
|
968
|
-
apiOperator.rawApiInfo = operation;
|
|
969
1672
|
// 添加到结果列表
|
|
970
1673
|
apiOperatorList.push(apiOperator);
|
|
971
1674
|
}
|