api-render-ui 1.1.0 → 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 +614 -145
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +614 -145
- 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 -3
- package/src/api-render-ui.ts +880 -170
- package/src/inlined-styles.ts +3 -3
- package/src/main.ts +0 -10
package/src/api-render-ui.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
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;
|
|
8
8
|
container: any;
|
|
9
|
+
|
|
10
|
+
// 静态标志:记录是否已注入全局样式
|
|
11
|
+
private static globalStyleInjected = false;
|
|
12
|
+
|
|
9
13
|
constructor(options: any) {
|
|
10
14
|
this.options = Object.assign({
|
|
11
15
|
mountPoint: document?.body, // 默认挂载到body
|
|
@@ -19,10 +23,13 @@ export class ApiRenderer {
|
|
|
19
23
|
render(apiSpec: OpenAPIV3CustomDoc, renderUnit: boolean = false) {
|
|
20
24
|
|
|
21
25
|
const appendInlineStyle = (text: string) => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
if (!ApiRenderer.globalStyleInjected) {
|
|
27
|
+
// 动态创建 <style> 标签并插入全局样式
|
|
28
|
+
const styleEl = document.createElement('style');
|
|
29
|
+
styleEl.textContent = text;
|
|
30
|
+
document.head.appendChild(styleEl);
|
|
31
|
+
ApiRenderer.globalStyleInjected = true; // 标记已注入
|
|
32
|
+
}
|
|
26
33
|
};
|
|
27
34
|
// 使用
|
|
28
35
|
appendInlineStyle(GLOBAL_STYLES);
|
|
@@ -131,14 +138,53 @@ export class ApiRenderer {
|
|
|
131
138
|
}
|
|
132
139
|
|
|
133
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
|
+
|
|
134
185
|
|
|
135
186
|
function renderApiUnit(apiOperator: any, containerRef: any, elementMap: any) {
|
|
136
187
|
return function (evt: any) {
|
|
137
|
-
console.log('点击的API操作:');
|
|
138
|
-
console.log('方法:', apiOperator.method);
|
|
139
|
-
console.log('URL:', apiOperator.url);
|
|
140
|
-
console.log('------------------------');
|
|
141
|
-
|
|
142
188
|
const currentTarget = evt.currentTarget;
|
|
143
189
|
// 检查是否已存在对应的新元素
|
|
144
190
|
if (elementMap.has(currentTarget)) {
|
|
@@ -186,7 +232,7 @@ function createApiUnit(apiOperator: any) {
|
|
|
186
232
|
// 授权部分
|
|
187
233
|
const authSection = createSectionAuth(apiOperator);
|
|
188
234
|
// 请求体部分
|
|
189
|
-
const bodySection = createSectionRequestBody(apiOperator
|
|
235
|
+
const bodySection = createSectionRequestBody(apiOperator);
|
|
190
236
|
|
|
191
237
|
reqContent.append(paramSection, headerSection, authSection, bodySection);
|
|
192
238
|
apiContainer.appendChild(reqContent);
|
|
@@ -226,7 +272,6 @@ function createReqOperator(apiOperator: any) {
|
|
|
226
272
|
reqUrl.value = apiOperator.url; // 绑定初始值
|
|
227
273
|
// 可选:添加输入事件监听(根据需求)
|
|
228
274
|
reqUrl.addEventListener('input', (e: any) => {
|
|
229
|
-
console.log('当前值:', e.target.value);
|
|
230
275
|
// 这里可以添加保存逻辑(如更新状态/发送请求
|
|
231
276
|
apiOperator.url = e.target.value
|
|
232
277
|
});
|
|
@@ -242,7 +287,6 @@ function createReqOperator(apiOperator: any) {
|
|
|
242
287
|
sendButton.appendChild(sendText);
|
|
243
288
|
|
|
244
289
|
sendButton.addEventListener('click', (e: any) => {
|
|
245
|
-
console.log('当前值:', e.target.value);
|
|
246
290
|
// 这里可以添加保存逻辑(如更新状态/发送请求
|
|
247
291
|
// responseSectionRef 在渲染时会被挂载到 apiOperator._responseSectionRef 上
|
|
248
292
|
const respRef = apiOperator._responseSectionRef || null;
|
|
@@ -324,19 +368,191 @@ function createSectionAuth(apiOperator: any) {
|
|
|
324
368
|
authValues.setAttribute('data-layer', 'paraKeyValues');
|
|
325
369
|
authValues.className = 'Parakeyvalues codigma-apiunit-parakeyvalues';
|
|
326
370
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
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
|
+
});
|
|
334
397
|
|
|
398
|
+
authValues.append(authTypeRow);
|
|
335
399
|
authSection.append(authCnr, authValues);
|
|
336
400
|
return authSection;
|
|
337
401
|
}
|
|
338
402
|
|
|
339
|
-
|
|
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) {
|
|
340
556
|
const bodySection = document.createElement('div');
|
|
341
557
|
bodySection.setAttribute('data-layer', 'request-body-section');
|
|
342
558
|
bodySection.className = 'RequestBodySection codigma-apiunit-request-body-section';
|
|
@@ -351,14 +567,170 @@ function createSectionRequestBody(requestBody: any) {
|
|
|
351
567
|
bodyCnr.appendChild(bodyText);
|
|
352
568
|
bodySection.appendChild(bodyCnr);
|
|
353
569
|
// 请求体内容
|
|
354
|
-
|
|
355
|
-
bodyValue.setAttribute('data-layer', 'bodyTextValue');
|
|
356
|
-
bodyValue.className = 'Id0CategoryId0NameNamePhotourlsTagsId0NameStatusAvailable codigma-apiunit-parakeyvalues';
|
|
357
|
-
bodyValue.value = JSON.stringify(requestBody);
|
|
358
|
-
bodySection.appendChild(bodyValue);
|
|
570
|
+
renderConsumeSection(apiOperator, bodySection, bodyCnr);
|
|
359
571
|
return bodySection;
|
|
360
572
|
}
|
|
361
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
|
+
|
|
362
734
|
function createSectionResponse(apiOperator: any) {
|
|
363
735
|
const responseSection = document.createElement('div');
|
|
364
736
|
responseSection.setAttribute('data-layer', 'reqresponse');
|
|
@@ -398,6 +770,11 @@ function createTimeStatusElement(apiOperator: any) {
|
|
|
398
770
|
return timeStatus;
|
|
399
771
|
}
|
|
400
772
|
|
|
773
|
+
function updateTimeStatus(timeStatus: any, apiOperator: any) {
|
|
774
|
+
timeStatus.textContent
|
|
775
|
+
= `Status: ${apiOperator.response.status || ""} ${apiOperator.response.statusText || ""} Time: ${apiOperator.requestDuration || ""}`;
|
|
776
|
+
}
|
|
777
|
+
|
|
401
778
|
function createRow(parameter: any) {
|
|
402
779
|
const petIdRow = document.createElement('div');
|
|
403
780
|
petIdRow.setAttribute('data-layer', 'keyValue');
|
|
@@ -413,7 +790,6 @@ function createRow(parameter: any) {
|
|
|
413
790
|
|
|
414
791
|
// 可选:添加输入事件监听(根据需求)
|
|
415
792
|
petIdValue.addEventListener('input', (e: any) => {
|
|
416
|
-
console.log('当前值:', e.target.value);
|
|
417
793
|
// 这里可以添加保存逻辑(如更新状态/发送请求
|
|
418
794
|
parameter["value"] = e.target.value
|
|
419
795
|
});
|
|
@@ -430,7 +806,7 @@ function createInputElement() {
|
|
|
430
806
|
return inputText;
|
|
431
807
|
}
|
|
432
808
|
|
|
433
|
-
function createSelectRow(
|
|
809
|
+
function createSelectRow(name: string, args: any) {
|
|
434
810
|
// 创建外层容器div
|
|
435
811
|
const container = document.createElement('div');
|
|
436
812
|
container.setAttribute('data-layer', 'keyValue');
|
|
@@ -438,9 +814,9 @@ function createSelectRow(auths: any, authValues: any) {
|
|
|
438
814
|
|
|
439
815
|
// 创建type显示div
|
|
440
816
|
const typeLabel = document.createElement('div');
|
|
441
|
-
typeLabel.setAttribute('data-layer',
|
|
817
|
+
typeLabel.setAttribute('data-layer', name);
|
|
442
818
|
typeLabel.className = 'type codigma-apiunit-send';
|
|
443
|
-
typeLabel.textContent =
|
|
819
|
+
typeLabel.textContent = name + ":";
|
|
444
820
|
|
|
445
821
|
// 创建select元素
|
|
446
822
|
const selectElement: any = document.createElement('select');
|
|
@@ -449,22 +825,13 @@ function createSelectRow(auths: any, authValues: any) {
|
|
|
449
825
|
selectElement.setAttribute('data-layer', 'valueText');
|
|
450
826
|
|
|
451
827
|
// 示例选项(可根据实际需求添加
|
|
452
|
-
|
|
828
|
+
args.forEach((auth: any) => {
|
|
453
829
|
const option1 = document.createElement('option');
|
|
454
|
-
option1.value = auth["
|
|
455
|
-
option1.textContent = auth["
|
|
830
|
+
option1.value = auth["value"];
|
|
831
|
+
option1.textContent = (auth['displayName'] != null || auth['label'] != null) ? (auth["displayName"] || auth['label']): auth["value"];
|
|
456
832
|
selectElement.appendChild(option1);
|
|
457
833
|
})
|
|
458
834
|
|
|
459
|
-
// 添加选择事件监听
|
|
460
|
-
selectElement.addEventListener('change', function (event: any) {
|
|
461
|
-
//切换前先移除掉原来的元素
|
|
462
|
-
authValues && Array.from(authValues.children).slice(1).forEach((el: any) => el.remove());
|
|
463
|
-
const auth = auths[event.target.selectedIndex];
|
|
464
|
-
let parameters = auth.parameters || [];
|
|
465
|
-
const authRows = parameters.map((parameter: any) => createRow(parameter));
|
|
466
|
-
authValues.append(...authRows);
|
|
467
|
-
});
|
|
468
835
|
// 组装DOM结构
|
|
469
836
|
container.appendChild(typeLabel);
|
|
470
837
|
container.appendChild(selectElement);
|
|
@@ -479,6 +846,179 @@ function isHeaderParam(param: any) {
|
|
|
479
846
|
return param.in === 'header';
|
|
480
847
|
}
|
|
481
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
|
+
|
|
482
1022
|
/**
|
|
483
1023
|
*
|
|
484
1024
|
*
|
|
@@ -493,43 +1033,45 @@ function isHeaderParam(param: any) {
|
|
|
493
1033
|
* @param {*} apiOperator
|
|
494
1034
|
* @param {*} apiInfo
|
|
495
1035
|
*/
|
|
496
|
-
|
|
497
1036
|
function sendRequest(apiOperator: any, responseSectionRef: any) {
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
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');
|
|
505
1043
|
|
|
506
|
-
let header = result.hasRequestBody ? 'application/json' :
|
|
507
|
-
(result.hasRequestFormData ? 'application/x-www-form-urlencoded' : 'application/json');
|
|
508
1044
|
let headers: any = {
|
|
509
1045
|
'Content-Type': header
|
|
510
1046
|
}
|
|
511
|
-
|
|
512
|
-
//
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
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
|
+
}
|
|
518
1066
|
}
|
|
1067
|
+
} else {
|
|
1068
|
+
body = "";
|
|
519
1069
|
}
|
|
1070
|
+
} else {
|
|
1071
|
+
body = "";
|
|
520
1072
|
}
|
|
521
1073
|
|
|
522
|
-
|
|
523
|
-
(result.hasRequestFormData ? getRequestFormData(apiOperator.rawApiInfo) : null);
|
|
524
|
-
|
|
525
|
-
//TODO
|
|
526
|
-
if (apiOperator.custom) {
|
|
527
|
-
if (apiOperator.method.toUpperCase() == "POST" || apiOperator.method.toUpperCase() == "PUT") {
|
|
528
|
-
body = apiOperator.requestBody;
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
apiOperator.ifSendingRequest = true;
|
|
1074
|
+
ifSendingRequest = true;
|
|
533
1075
|
const startTime = Date.now(); // 记录开始时间
|
|
534
1076
|
|
|
535
1077
|
apiOperator.controller = new AbortController();
|
|
@@ -540,32 +1082,32 @@ function sendRequest(apiOperator: any, responseSectionRef: any) {
|
|
|
540
1082
|
|
|
541
1083
|
// 使用 fetch 发送请求,并传递 signal
|
|
542
1084
|
fetch(reuqestUrl, {
|
|
543
|
-
method:
|
|
1085
|
+
method: apiInfo.method.toUpperCase(),
|
|
544
1086
|
headers: headers,
|
|
545
|
-
body: body
|
|
1087
|
+
body: body,
|
|
546
1088
|
signal: signal
|
|
547
1089
|
})
|
|
548
1090
|
.then(response => {
|
|
549
1091
|
if (!response.ok) {
|
|
550
|
-
|
|
1092
|
+
responseObj = {
|
|
551
1093
|
status: response.status,
|
|
552
|
-
statusText: response.statusText
|
|
1094
|
+
statusText: response.statusText,
|
|
1095
|
+
body: ""
|
|
553
1096
|
}
|
|
554
1097
|
|
|
555
1098
|
const endTime = Date.now(); // 即使在错误的情况下也记录结束时间
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
// apiOperator.responseJsoneditor.value = "";
|
|
1099
|
+
requestDuration = formatDuration(endTime - startTime);
|
|
1100
|
+
ifSendingRequest = false;
|
|
559
1101
|
throw new Error('Network response was not ok.');
|
|
560
1102
|
}
|
|
561
1103
|
const endTime = Date.now(); // 记录结束时间
|
|
562
|
-
|
|
1104
|
+
requestDuration = formatDuration(endTime - startTime); // 计算耗时
|
|
563
1105
|
|
|
564
1106
|
const responsebodyElement = responseSectionRef.querySelector('[data-layer="responsebody"]');
|
|
565
1107
|
responsebodyElement.removeChild(overlayLayerContainer);
|
|
566
1108
|
|
|
567
|
-
|
|
568
|
-
|
|
1109
|
+
ifSendingRequest = false;
|
|
1110
|
+
responseObj = {
|
|
569
1111
|
status: response.status,
|
|
570
1112
|
statusText: response.statusText
|
|
571
1113
|
}
|
|
@@ -586,18 +1128,19 @@ function sendRequest(apiOperator: any, responseSectionRef: any) {
|
|
|
586
1128
|
});
|
|
587
1129
|
})
|
|
588
1130
|
.then(data => {
|
|
589
|
-
|
|
1131
|
+
gotResponse = true;
|
|
590
1132
|
const responsebodyElement = responseSectionRef.querySelector('[data-layer="responsebody"]');
|
|
591
1133
|
// 此时 data 可能是 JSON 对象,也可能是文本字符串
|
|
592
1134
|
if (typeof data === 'object') {
|
|
593
1135
|
// 假设 data 是 JSON 对象,你可以在这里处理它
|
|
594
1136
|
console.log('Received JSON:', data);
|
|
595
|
-
|
|
1137
|
+
responseObj.body = JSON.stringify(data, null, 4);
|
|
596
1138
|
} else {
|
|
597
1139
|
// 假设 data 是文本字符串,你可以在这里处理它
|
|
598
1140
|
console.log('Received text:', data);
|
|
599
|
-
|
|
1141
|
+
responseObj.body = data;
|
|
600
1142
|
}
|
|
1143
|
+
responsebodyElement.textContent = responseObj.body;
|
|
601
1144
|
})
|
|
602
1145
|
.catch(error => {
|
|
603
1146
|
// 错误处理
|
|
@@ -605,11 +1148,6 @@ function sendRequest(apiOperator: any, responseSectionRef: any) {
|
|
|
605
1148
|
});
|
|
606
1149
|
}
|
|
607
1150
|
|
|
608
|
-
function updateTimeStatus(timeStatus: any, apiOperator: any) {
|
|
609
|
-
timeStatus.textContent
|
|
610
|
-
= `Status: ${apiOperator.response.status || ""} ${apiOperator.response.statusText || ""} Time: ${apiOperator.requestDuration || ""}`;
|
|
611
|
-
}
|
|
612
|
-
|
|
613
1151
|
function createRequestOverlayLayer(apiOperator: any, responseSectionRef: any) {
|
|
614
1152
|
// 创建主容器
|
|
615
1153
|
const container = document.createElement('div');
|
|
@@ -666,40 +1204,15 @@ function createRequestOverlayLayer(apiOperator: any, responseSectionRef: any) {
|
|
|
666
1204
|
return container
|
|
667
1205
|
}
|
|
668
1206
|
|
|
669
|
-
function checkIfParameter(apiOperator: any) {
|
|
670
|
-
let hasRequestBody = false;
|
|
671
|
-
let hasRequestFormData = false;
|
|
672
|
-
const parameters = apiOperator.rawApiInfo.parameters;
|
|
673
|
-
if (parameters) {
|
|
674
|
-
for (let index = 0; index < parameters.length; index++) {
|
|
675
|
-
const parameter = parameters[index];
|
|
676
|
-
if (parameter.in == "query" || parameter.in == "path") {
|
|
677
|
-
} else if (parameter.in == "body") {
|
|
678
|
-
hasRequestBody = true;
|
|
679
|
-
parameter.name = parameter.name.charAt(0).toUpperCase() + parameter.name.slice(1);
|
|
680
|
-
} else if (parameter.in == "formData") {
|
|
681
|
-
hasRequestFormData = true;
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
//support openapi 3.0
|
|
687
|
-
const requestBody = apiOperator.rawApiInfo.requestBody;
|
|
688
|
-
if (requestBody) {
|
|
689
|
-
hasRequestBody = true;
|
|
690
|
-
}
|
|
691
|
-
// 返回包含两个状态的对象
|
|
692
|
-
return { hasRequestBody, hasRequestFormData };
|
|
693
|
-
}
|
|
694
1207
|
|
|
695
1208
|
function formatDuration(milliseconds: number) {
|
|
696
|
-
let totalSeconds
|
|
697
|
-
let seconds:
|
|
698
|
-
let minutes:
|
|
699
|
-
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));
|
|
700
1213
|
|
|
701
1214
|
// 毫秒部分
|
|
702
|
-
let millisecondsPart:
|
|
1215
|
+
let millisecondsPart: any = Math.floor(milliseconds % 1000);
|
|
703
1216
|
// 毫秒不足三位时前面补0
|
|
704
1217
|
millisecondsPart = millisecondsPart.toString().padStart(3, '0');
|
|
705
1218
|
|
|
@@ -712,10 +1225,18 @@ function formatDuration(milliseconds: number) {
|
|
|
712
1225
|
return `${hours}h${minutes}m${seconds}s${millisecondsPart}ms`;
|
|
713
1226
|
}
|
|
714
1227
|
|
|
715
|
-
function
|
|
716
|
-
|
|
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;
|
|
717
1238
|
|
|
718
|
-
const requestParameters =
|
|
1239
|
+
const requestParameters = apiInfo.rawApiInfo.parameters || [];
|
|
719
1240
|
if (requestParameters == null) {
|
|
720
1241
|
return reuqestUrl;
|
|
721
1242
|
}
|
|
@@ -726,13 +1247,51 @@ function getRequestUrl(apiOperator: any) {
|
|
|
726
1247
|
}
|
|
727
1248
|
}
|
|
728
1249
|
|
|
729
|
-
let queryParams = getQueryParams(
|
|
1250
|
+
let queryParams = getQueryParams(apiInfo, requestParameters);
|
|
730
1251
|
reuqestUrl = queryParams.length > 0 ? (reuqestUrl + "?" + queryParams.join("&")) : reuqestUrl;
|
|
731
1252
|
|
|
732
1253
|
return reuqestUrl;
|
|
733
1254
|
}
|
|
734
1255
|
|
|
735
|
-
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) {
|
|
736
1295
|
let queryParams = [];
|
|
737
1296
|
for (const element of requestParameters) {
|
|
738
1297
|
if (element.in == "query") {
|
|
@@ -748,9 +1307,9 @@ function getQueryParams(apiOperator: any, requestParameters: any) {
|
|
|
748
1307
|
}
|
|
749
1308
|
}
|
|
750
1309
|
|
|
751
|
-
if (
|
|
752
|
-
for (let index = 0; index <
|
|
753
|
-
const paras =
|
|
1310
|
+
if (apiInfo.customQueryparameters) {
|
|
1311
|
+
for (let index = 0; index < apiInfo.customQueryparameters.length; index++) {
|
|
1312
|
+
const paras = apiInfo.customQueryparameters[index];
|
|
754
1313
|
if (paras.name != '' && paras.value != '' && paras.name != null && paras.value != null) {
|
|
755
1314
|
queryParams.push(paras.name + "=" + paras.value)
|
|
756
1315
|
}
|
|
@@ -781,6 +1340,16 @@ function getRequestFormData(rawApiInfo: any) {
|
|
|
781
1340
|
return formData;
|
|
782
1341
|
}
|
|
783
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
|
+
|
|
784
1353
|
|
|
785
1354
|
function createSvg() {
|
|
786
1355
|
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
@@ -803,20 +1372,17 @@ function createSvg() {
|
|
|
803
1372
|
|
|
804
1373
|
function parseParaModel(parameterObj: any, dataDef: any) {
|
|
805
1374
|
let bodyModel;
|
|
806
|
-
if (parameterObj
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
bodyModel = parseElement(itemObj);
|
|
815
|
-
}
|
|
816
|
-
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);
|
|
817
1383
|
}
|
|
1384
|
+
bodyModel = [bodyModel];
|
|
818
1385
|
}
|
|
819
|
-
|
|
820
1386
|
return bodyModel;
|
|
821
1387
|
}
|
|
822
1388
|
|
|
@@ -849,10 +1415,69 @@ function parseModel(modelDef: any, apiDef: any) {
|
|
|
849
1415
|
return model;
|
|
850
1416
|
}
|
|
851
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
|
+
|
|
852
1473
|
function parseElement(element: any) {
|
|
853
1474
|
let elementValue;
|
|
854
1475
|
if (element['type'].includes('integer')) {
|
|
855
|
-
|
|
1476
|
+
if (element['enum']) {
|
|
1477
|
+
elementValue = element['enum'][0];
|
|
1478
|
+
} else {
|
|
1479
|
+
elementValue = 0;
|
|
1480
|
+
}
|
|
856
1481
|
} else if (element['type'].includes('boolean')) {
|
|
857
1482
|
elementValue = false;
|
|
858
1483
|
} else if (element['type'].includes('string')) {
|
|
@@ -863,6 +1488,12 @@ function parseElement(element: any) {
|
|
|
863
1488
|
}
|
|
864
1489
|
}
|
|
865
1490
|
|
|
1491
|
+
// 如果有default则用default的值
|
|
1492
|
+
if (element['default']) {
|
|
1493
|
+
elementValue = element['default'];
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
//如果有example则用example的值
|
|
866
1497
|
if (element['example']) {
|
|
867
1498
|
elementValue = element['example'];
|
|
868
1499
|
}
|
|
@@ -870,6 +1501,18 @@ function parseElement(element: any) {
|
|
|
870
1501
|
return elementValue;
|
|
871
1502
|
}
|
|
872
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
|
+
|
|
873
1516
|
const HTTP_METHODS = ['get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace'] as const;
|
|
874
1517
|
type HttpMethod = typeof HTTP_METHODS[number]; // 等价于你的 HttpMethods 的值类型
|
|
875
1518
|
|
|
@@ -909,56 +1552,123 @@ function parseOpenAPI(openapiSpec: OpenAPIV3CustomDoc) {
|
|
|
909
1552
|
const apiOperator: any = {
|
|
910
1553
|
method: method.toUpperCase(),
|
|
911
1554
|
url: path,
|
|
912
|
-
rawApiInfo:
|
|
1555
|
+
rawApiInfo: operation,
|
|
913
1556
|
requestBody: null,
|
|
914
1557
|
response: {},
|
|
915
|
-
|
|
916
|
-
{
|
|
917
|
-
type: "No Auth"
|
|
918
|
-
},
|
|
919
|
-
{
|
|
920
|
-
type: "Basic Auth",
|
|
921
|
-
parameters: [
|
|
922
|
-
{
|
|
923
|
-
name: "userName",
|
|
924
|
-
value: ""
|
|
925
|
-
},
|
|
926
|
-
{
|
|
927
|
-
name: "password",
|
|
928
|
-
value: ""
|
|
929
|
-
}
|
|
930
|
-
]
|
|
931
|
-
}
|
|
932
|
-
]
|
|
1558
|
+
auth: {}
|
|
933
1559
|
};
|
|
934
1560
|
|
|
935
1561
|
if (operation) {
|
|
936
1562
|
// requestBody
|
|
937
1563
|
// support openapi 2.0
|
|
938
|
-
if (operation.parameters) {
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
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
|
+
}
|
|
943
1632
|
}
|
|
944
1633
|
}
|
|
945
1634
|
|
|
946
1635
|
//support openapi 3.0
|
|
947
|
-
if (
|
|
948
|
-
const
|
|
949
|
-
|
|
1636
|
+
if (apiOperator.rawApiInfo.requestBody) {
|
|
1637
|
+
const content = apiOperator.rawApiInfo.requestBody.content;
|
|
1638
|
+
apiOperator["requestBody"] = {
|
|
1639
|
+
content: {}
|
|
1640
|
+
}
|
|
1641
|
+
|
|
950
1642
|
for (const key in content) {
|
|
951
1643
|
if (Object.prototype.hasOwnProperty.call(content, key)) {
|
|
952
|
-
const element
|
|
1644
|
+
const element = content[key];
|
|
1645
|
+
apiOperator['consumes']?.push(key);
|
|
953
1646
|
if (element) {
|
|
954
|
-
|
|
955
|
-
|
|
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
|
|
956
1662
|
}
|
|
957
1663
|
}
|
|
958
1664
|
}
|
|
1665
|
+
if (apiOperator.consumes) {
|
|
1666
|
+
if (apiOperator.consumes.length > 0) {
|
|
1667
|
+
apiOperator['currentConsume'] = apiOperator['consumes'][0]
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
959
1670
|
}
|
|
960
1671
|
|
|
961
|
-
apiOperator.rawApiInfo = operation;
|
|
962
1672
|
// 添加到结果列表
|
|
963
1673
|
apiOperatorList.push(apiOperator);
|
|
964
1674
|
}
|