whistle.mock-plugins 1.2.0-beta.13 → 1.2.0-beta.15
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/VERSION.md +13 -0
- package/app/public/js/index.js +1 -1
- package/package.json +1 -1
- package/ui/src/pages/InterfaceManagement.js +104 -10
- package/ui/src/pages/InterfaceManagementV2.js +104 -10
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
PlusOutlined, EditOutlined, DeleteOutlined,
|
|
11
11
|
FileTextOutlined, PlusCircleOutlined, SettingOutlined,
|
|
12
|
-
SearchOutlined, FilterOutlined, ReloadOutlined
|
|
12
|
+
SearchOutlined, FilterOutlined, ReloadOutlined, CopyOutlined
|
|
13
13
|
} from '@ant-design/icons';
|
|
14
14
|
import '../styles/interface-management.css';
|
|
15
15
|
import axios from 'axios';
|
|
@@ -68,6 +68,7 @@ const InterfaceManagement = () => {
|
|
|
68
68
|
// 模态框状态
|
|
69
69
|
const [modalVisible, setModalVisible] = useState(false);
|
|
70
70
|
const [previewVisible, setPreviewVisible] = useState(false);
|
|
71
|
+
const [isDuplicateMode, setIsDuplicateMode] = useState(false);
|
|
71
72
|
|
|
72
73
|
// 列配置状态
|
|
73
74
|
const [columnConfigVisible, setColumnConfigVisible] = useState(false);
|
|
@@ -247,6 +248,7 @@ const InterfaceManagement = () => {
|
|
|
247
248
|
return;
|
|
248
249
|
}
|
|
249
250
|
form.resetFields();
|
|
251
|
+
setIsDuplicateMode(false);
|
|
250
252
|
|
|
251
253
|
// 创建默认响应
|
|
252
254
|
const defaultResponseId = generateResponseId();
|
|
@@ -286,6 +288,7 @@ const InterfaceManagement = () => {
|
|
|
286
288
|
|
|
287
289
|
// 重置表单
|
|
288
290
|
form.resetFields();
|
|
291
|
+
setIsDuplicateMode(false);
|
|
289
292
|
|
|
290
293
|
// 处理响应数据
|
|
291
294
|
let responses = [];
|
|
@@ -345,6 +348,91 @@ const InterfaceManagement = () => {
|
|
|
345
348
|
setModalVisible(true);
|
|
346
349
|
};
|
|
347
350
|
|
|
351
|
+
// 复制新增接口
|
|
352
|
+
const handleDuplicate = (record) => {
|
|
353
|
+
if (!selectedFeatureId) {
|
|
354
|
+
message.warning('请先选择一个功能模块');
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
if (!record) {
|
|
358
|
+
message.warning('接口数据不完整,无法复制');
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
form.resetFields();
|
|
363
|
+
|
|
364
|
+
// 深拷贝源数据
|
|
365
|
+
const source = JSON.parse(JSON.stringify(record));
|
|
366
|
+
|
|
367
|
+
// 处理响应数据
|
|
368
|
+
let responses = [];
|
|
369
|
+
let activeResponseId = '';
|
|
370
|
+
|
|
371
|
+
if (Array.isArray(source.responses) && source.responses.length > 0) {
|
|
372
|
+
// 为每条响应生成新的ID,并重映射activeResponseId
|
|
373
|
+
const idMap = new Map();
|
|
374
|
+
responses = source.responses.map((resp) => {
|
|
375
|
+
const newId = generateResponseId();
|
|
376
|
+
idMap.set(resp.id, newId);
|
|
377
|
+
return {
|
|
378
|
+
id: newId,
|
|
379
|
+
name: resp.name || '未命名响应',
|
|
380
|
+
description: resp.description || '',
|
|
381
|
+
content: resp.content || '{}'
|
|
382
|
+
};
|
|
383
|
+
});
|
|
384
|
+
const mapped = idMap.get(source.activeResponseId) || responses[0]?.id;
|
|
385
|
+
activeResponseId = mapped || '';
|
|
386
|
+
} else if (source.responseContent) {
|
|
387
|
+
// 兼容旧数据格式
|
|
388
|
+
const defaultResponseId = generateResponseId();
|
|
389
|
+
responses = [{
|
|
390
|
+
id: defaultResponseId,
|
|
391
|
+
name: '默认响应',
|
|
392
|
+
description: '',
|
|
393
|
+
content: source.responseContent
|
|
394
|
+
}];
|
|
395
|
+
activeResponseId = defaultResponseId;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// 处理自定义请求头 -> 表单需要的数组结构
|
|
399
|
+
let headerItems = [];
|
|
400
|
+
if (source.headers && typeof source.headers === 'object') {
|
|
401
|
+
headerItems = Object.entries(source.headers).map(([headerName, headerValue]) => ({
|
|
402
|
+
headerName,
|
|
403
|
+
headerValue
|
|
404
|
+
}));
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// 分组值保证为字符串
|
|
408
|
+
let groupValue = source.group;
|
|
409
|
+
if (Array.isArray(groupValue)) {
|
|
410
|
+
groupValue = groupValue.length > 0 ? groupValue[0] : undefined;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// 设定表单初值
|
|
414
|
+
form.setFieldsValue({
|
|
415
|
+
name: `${source.name || '未命名接口'} - 副本`,
|
|
416
|
+
group: groupValue || undefined,
|
|
417
|
+
pattern: source.urlPattern,
|
|
418
|
+
proxyType: source.proxyType || 'response',
|
|
419
|
+
statusCode: (source.httpStatus || source.statusCode || 200).toString(),
|
|
420
|
+
contentType: source.contentType || 'application/json; charset=utf-8',
|
|
421
|
+
responses,
|
|
422
|
+
activeResponseId,
|
|
423
|
+
httpMethod: source.httpMethod || source.method || 'ALL',
|
|
424
|
+
targetUrl: source.targetUrl || '',
|
|
425
|
+
headerItems,
|
|
426
|
+
paramMatchers: Array.isArray(source.paramMatchers) ? source.paramMatchers : [],
|
|
427
|
+
responseDelay: source.responseDelay ? String(source.responseDelay) : '0'
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
setCurrentResponseId(activeResponseId || null);
|
|
431
|
+
setEditingInterface(null); // 新增模式
|
|
432
|
+
setIsDuplicateMode(true);
|
|
433
|
+
setModalVisible(true);
|
|
434
|
+
};
|
|
435
|
+
|
|
348
436
|
const handleDeleteInterface = async (id) => {
|
|
349
437
|
try {
|
|
350
438
|
const response = await axios.delete(`/cgi-bin/interfaces?id=${id}`);
|
|
@@ -430,13 +518,11 @@ const InterfaceManagement = () => {
|
|
|
430
518
|
interfaceData.headers = headers;
|
|
431
519
|
}
|
|
432
520
|
|
|
433
|
-
//
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
);
|
|
439
|
-
}
|
|
521
|
+
// 添加参数匹配规则(始终发送,空数组用于清空后端旧值)
|
|
522
|
+
const filteredParamMatchers = Array.isArray(values.paramMatchers)
|
|
523
|
+
? values.paramMatchers.filter(matcher => matcher && matcher.paramPath && matcher.paramValue)
|
|
524
|
+
: [];
|
|
525
|
+
interfaceData.paramMatchers = filteredParamMatchers;
|
|
440
526
|
|
|
441
527
|
console.log('提交接口数据:', interfaceData);
|
|
442
528
|
|
|
@@ -477,6 +563,7 @@ const InterfaceManagement = () => {
|
|
|
477
563
|
|
|
478
564
|
const handleCancel = () => {
|
|
479
565
|
setModalVisible(false);
|
|
566
|
+
setIsDuplicateMode(false);
|
|
480
567
|
};
|
|
481
568
|
|
|
482
569
|
const handleSelectFeature = (featureId) => {
|
|
@@ -906,7 +993,7 @@ const InterfaceManagement = () => {
|
|
|
906
993
|
{
|
|
907
994
|
title: '操作',
|
|
908
995
|
key: 'action',
|
|
909
|
-
width:
|
|
996
|
+
width: 220,
|
|
910
997
|
render: (_, record) => (
|
|
911
998
|
<div className="action-buttons">
|
|
912
999
|
<Button
|
|
@@ -914,6 +1001,13 @@ const InterfaceManagement = () => {
|
|
|
914
1001
|
icon={<EditOutlined />}
|
|
915
1002
|
onClick={() => handleEditInterface(record)}
|
|
916
1003
|
/>
|
|
1004
|
+
<Tooltip title="复制新增">
|
|
1005
|
+
<Button
|
|
1006
|
+
type="text"
|
|
1007
|
+
icon={<CopyOutlined />}
|
|
1008
|
+
onClick={() => handleDuplicate(record)}
|
|
1009
|
+
/>
|
|
1010
|
+
</Tooltip>
|
|
917
1011
|
<Popconfirm
|
|
918
1012
|
title="确定要删除此接口吗?"
|
|
919
1013
|
onConfirm={() => handleDeleteInterface(record.id)}
|
|
@@ -1253,7 +1347,7 @@ const InterfaceManagement = () => {
|
|
|
1253
1347
|
|
|
1254
1348
|
{/* 接口编辑/创建模态框 */}
|
|
1255
1349
|
<Modal
|
|
1256
|
-
title={editingInterface ? '编辑接口' : '添加接口'}
|
|
1350
|
+
title={editingInterface ? '编辑接口' : (isDuplicateMode ? '复制新增接口' : '添加接口')}
|
|
1257
1351
|
open={modalVisible}
|
|
1258
1352
|
onOk={handleSubmit}
|
|
1259
1353
|
onCancel={handleCancel}
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
import {
|
|
16
16
|
PlusOutlined, EditOutlined, DeleteOutlined,
|
|
17
17
|
FileTextOutlined, PlusCircleOutlined, SettingOutlined,
|
|
18
|
-
SearchOutlined, FilterOutlined, ReloadOutlined, DownOutlined, QuestionCircleOutlined
|
|
18
|
+
SearchOutlined, FilterOutlined, ReloadOutlined, DownOutlined, QuestionCircleOutlined, CopyOutlined
|
|
19
19
|
} from '@ant-design/icons';
|
|
20
20
|
import '../styles/interface-management.css';
|
|
21
21
|
import axios from 'axios';
|
|
@@ -74,6 +74,7 @@ const InterfaceManagement = () => {
|
|
|
74
74
|
// 模态框状态
|
|
75
75
|
const [modalVisible, setModalVisible] = useState(false);
|
|
76
76
|
const [previewVisible, setPreviewVisible] = useState(false);
|
|
77
|
+
const [isDuplicateMode, setIsDuplicateMode] = useState(false);
|
|
77
78
|
|
|
78
79
|
// 列配置状态
|
|
79
80
|
const [columnConfigVisible, setColumnConfigVisible] = useState(false);
|
|
@@ -253,6 +254,7 @@ const InterfaceManagement = () => {
|
|
|
253
254
|
return;
|
|
254
255
|
}
|
|
255
256
|
form.resetFields();
|
|
257
|
+
setIsDuplicateMode(false);
|
|
256
258
|
|
|
257
259
|
// 创建默认响应
|
|
258
260
|
const defaultResponseId = generateResponseId();
|
|
@@ -292,6 +294,7 @@ const InterfaceManagement = () => {
|
|
|
292
294
|
|
|
293
295
|
// 重置表单
|
|
294
296
|
form.resetFields();
|
|
297
|
+
setIsDuplicateMode(false);
|
|
295
298
|
|
|
296
299
|
// 处理响应数据
|
|
297
300
|
let responses = [];
|
|
@@ -351,6 +354,91 @@ const InterfaceManagement = () => {
|
|
|
351
354
|
setModalVisible(true);
|
|
352
355
|
};
|
|
353
356
|
|
|
357
|
+
// 复制新增接口
|
|
358
|
+
const handleDuplicate = (record) => {
|
|
359
|
+
if (!selectedFeatureId) {
|
|
360
|
+
message.warning('请先选择一个功能模块');
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
if (!record) {
|
|
364
|
+
message.warning('接口数据不完整,无法复制');
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
form.resetFields();
|
|
369
|
+
|
|
370
|
+
// 深拷贝源数据
|
|
371
|
+
const source = JSON.parse(JSON.stringify(record));
|
|
372
|
+
|
|
373
|
+
// 处理响应数据
|
|
374
|
+
let responses = [];
|
|
375
|
+
let activeResponseId = '';
|
|
376
|
+
|
|
377
|
+
if (Array.isArray(source.responses) && source.responses.length > 0) {
|
|
378
|
+
// 为每条响应生成新的ID,并重映射activeResponseId
|
|
379
|
+
const idMap = new Map();
|
|
380
|
+
responses = source.responses.map((resp) => {
|
|
381
|
+
const newId = generateResponseId();
|
|
382
|
+
idMap.set(resp.id, newId);
|
|
383
|
+
return {
|
|
384
|
+
id: newId,
|
|
385
|
+
name: resp.name || '未命名响应',
|
|
386
|
+
description: resp.description || '',
|
|
387
|
+
content: resp.content || '{}'
|
|
388
|
+
};
|
|
389
|
+
});
|
|
390
|
+
const mapped = idMap.get(source.activeResponseId) || responses[0]?.id;
|
|
391
|
+
activeResponseId = mapped || '';
|
|
392
|
+
} else if (source.responseContent) {
|
|
393
|
+
// 兼容旧数据格式
|
|
394
|
+
const defaultResponseId = generateResponseId();
|
|
395
|
+
responses = [{
|
|
396
|
+
id: defaultResponseId,
|
|
397
|
+
name: '默认响应',
|
|
398
|
+
description: '',
|
|
399
|
+
content: source.responseContent
|
|
400
|
+
}];
|
|
401
|
+
activeResponseId = defaultResponseId;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// 处理自定义请求头 -> 表单需要的数组结构
|
|
405
|
+
let headerItems = [];
|
|
406
|
+
if (source.headers && typeof source.headers === 'object') {
|
|
407
|
+
headerItems = Object.entries(source.headers).map(([headerName, headerValue]) => ({
|
|
408
|
+
headerName,
|
|
409
|
+
headerValue
|
|
410
|
+
}));
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// 分组值保证为字符串
|
|
414
|
+
let groupValue = source.group;
|
|
415
|
+
if (Array.isArray(groupValue)) {
|
|
416
|
+
groupValue = groupValue.length > 0 ? groupValue[0] : undefined;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// 设定表单初值
|
|
420
|
+
form.setFieldsValue({
|
|
421
|
+
name: `${source.name || '未命名接口'} - 副本`,
|
|
422
|
+
group: groupValue || undefined,
|
|
423
|
+
pattern: source.urlPattern,
|
|
424
|
+
proxyType: source.proxyType || 'response',
|
|
425
|
+
statusCode: (source.httpStatus || source.statusCode || 200).toString(),
|
|
426
|
+
contentType: source.contentType || 'application/json; charset=utf-8',
|
|
427
|
+
responses,
|
|
428
|
+
activeResponseId,
|
|
429
|
+
httpMethod: source.httpMethod || source.method || 'ALL',
|
|
430
|
+
targetUrl: source.targetUrl || '',
|
|
431
|
+
headerItems,
|
|
432
|
+
paramMatchers: Array.isArray(source.paramMatchers) ? source.paramMatchers : [],
|
|
433
|
+
responseDelay: source.responseDelay ? String(source.responseDelay) : '0'
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
setCurrentResponseId(activeResponseId || null);
|
|
437
|
+
setEditingInterface(null); // 新增模式
|
|
438
|
+
setIsDuplicateMode(true);
|
|
439
|
+
setModalVisible(true);
|
|
440
|
+
};
|
|
441
|
+
|
|
354
442
|
const handleDeleteInterface = async (id) => {
|
|
355
443
|
try {
|
|
356
444
|
const response = await axios.delete(`/cgi-bin/interfaces?id=${id}`);
|
|
@@ -436,13 +524,11 @@ const InterfaceManagement = () => {
|
|
|
436
524
|
interfaceData.headers = headers;
|
|
437
525
|
}
|
|
438
526
|
|
|
439
|
-
//
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
);
|
|
445
|
-
}
|
|
527
|
+
// 添加参数匹配规则(始终发送,空数组用于清空后端旧值)
|
|
528
|
+
const filteredParamMatchers = Array.isArray(values.paramMatchers)
|
|
529
|
+
? values.paramMatchers.filter(matcher => matcher && matcher.paramPath && matcher.paramValue)
|
|
530
|
+
: [];
|
|
531
|
+
interfaceData.paramMatchers = filteredParamMatchers;
|
|
446
532
|
|
|
447
533
|
console.log('提交接口数据:', interfaceData);
|
|
448
534
|
|
|
@@ -483,6 +569,7 @@ const InterfaceManagement = () => {
|
|
|
483
569
|
|
|
484
570
|
const handleCancel = () => {
|
|
485
571
|
setModalVisible(false);
|
|
572
|
+
setIsDuplicateMode(false);
|
|
486
573
|
};
|
|
487
574
|
|
|
488
575
|
const handleSelectFeature = (featureId) => {
|
|
@@ -912,7 +999,7 @@ const InterfaceManagement = () => {
|
|
|
912
999
|
{
|
|
913
1000
|
title: '操作',
|
|
914
1001
|
key: 'action',
|
|
915
|
-
width:
|
|
1002
|
+
width: 220,
|
|
916
1003
|
render: (_, record) => (
|
|
917
1004
|
<div className="action-buttons">
|
|
918
1005
|
<Button
|
|
@@ -920,6 +1007,13 @@ const InterfaceManagement = () => {
|
|
|
920
1007
|
icon={<EditOutlined />}
|
|
921
1008
|
onClick={() => handleEditInterface(record)}
|
|
922
1009
|
/>
|
|
1010
|
+
<Tooltip title="复制新增">
|
|
1011
|
+
<Button
|
|
1012
|
+
type="text"
|
|
1013
|
+
icon={<CopyOutlined />}
|
|
1014
|
+
onClick={() => handleDuplicate(record)}
|
|
1015
|
+
/>
|
|
1016
|
+
</Tooltip>
|
|
923
1017
|
<Popconfirm
|
|
924
1018
|
title="确定要删除此接口吗?"
|
|
925
1019
|
onConfirm={() => handleDeleteInterface(record.id)}
|
|
@@ -1272,7 +1366,7 @@ const InterfaceManagement = () => {
|
|
|
1272
1366
|
alignItems: 'center',
|
|
1273
1367
|
gap: '8px'
|
|
1274
1368
|
}}>
|
|
1275
|
-
<span>{editingInterface ? '编辑接口' : '添加接口'}</span>
|
|
1369
|
+
<span>{editingInterface ? '编辑接口' : (isDuplicateMode ? '复制新增接口' : '添加接口')}</span>
|
|
1276
1370
|
<Badge
|
|
1277
1371
|
count="配置向导"
|
|
1278
1372
|
style={{
|