whistle.mock-plugins 1.2.0-beta.8 → 1.2.0
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 +9 -6
- package/app/public/js/index.js +1 -1
- package/app/public/js/index.js.LICENSE.txt +0 -2
- package/package.json +1 -1
- package/ui/src/pages/InterfaceManagement.js +130 -28
- package/ui/src/pages/InterfaceManagementV2.js +132 -30
- package/ui/src/pages/MockDataV2.js +6 -134
- package/ui/src/styles/mock-data.css +0 -139
|
@@ -156,5 +156,3 @@
|
|
|
156
156
|
/** */
|
|
157
157
|
|
|
158
158
|
/** */
|
|
159
|
-
|
|
160
|
-
/** */
|
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}`);
|
|
@@ -385,8 +473,9 @@ const InterfaceManagement = () => {
|
|
|
385
473
|
|
|
386
474
|
const handleSubmit = async () => {
|
|
387
475
|
try {
|
|
388
|
-
// 表单验证
|
|
389
|
-
|
|
476
|
+
// 表单验证 - 先验证所有字段,再获取所有字段值(包括折叠的)
|
|
477
|
+
await form.validateFields();
|
|
478
|
+
const values = form.getFieldsValue(true); // true表示获取所有字段,包括未渲染的
|
|
390
479
|
console.log('表单提交数据:', values);
|
|
391
480
|
|
|
392
481
|
// 处理自定义请求头
|
|
@@ -405,19 +494,19 @@ const InterfaceManagement = () => {
|
|
|
405
494
|
groupValue = groupValue.length > 0 ? groupValue[0] : '';
|
|
406
495
|
}
|
|
407
496
|
|
|
408
|
-
// 构建接口数据
|
|
497
|
+
// 构建接口数据 - 在编辑模式下,确保关键字段不丢失
|
|
409
498
|
const interfaceData = {
|
|
410
|
-
name: values.name,
|
|
411
|
-
group: groupValue || '', // 确保group不为undefined
|
|
412
|
-
urlPattern: values.pattern,
|
|
413
|
-
proxyType: values.proxyType,
|
|
499
|
+
name: values.name || (editingInterface ? editingInterface.name : ''),
|
|
500
|
+
group: groupValue || (editingInterface ? editingInterface.group : '') || '', // 确保group不为undefined
|
|
501
|
+
urlPattern: values.pattern || (editingInterface ? editingInterface.urlPattern : ''),
|
|
502
|
+
proxyType: values.proxyType || (editingInterface ? editingInterface.proxyType : 'response'),
|
|
414
503
|
featureId: selectedFeatureId,
|
|
415
|
-
responses: values.responses,
|
|
416
|
-
activeResponseId: values.activeResponseId,
|
|
417
|
-
httpStatus: parseInt(values.statusCode, 10), // 转换为数字
|
|
418
|
-
contentType: values.contentType,
|
|
419
|
-
responseDelay: parseInt(values.responseDelay, 10) || 0,
|
|
420
|
-
httpMethod: values.httpMethod,
|
|
504
|
+
responses: values.responses || (editingInterface ? editingInterface.responses : []),
|
|
505
|
+
activeResponseId: values.activeResponseId || (editingInterface ? editingInterface.activeResponseId : null),
|
|
506
|
+
httpStatus: parseInt(values.statusCode, 10) || (editingInterface ? editingInterface.httpStatus : 200), // 转换为数字
|
|
507
|
+
contentType: values.contentType || (editingInterface ? editingInterface.contentType : 'application/json; charset=utf-8'),
|
|
508
|
+
responseDelay: parseInt(values.responseDelay, 10) || (editingInterface ? editingInterface.responseDelay : 0) || 0,
|
|
509
|
+
httpMethod: values.httpMethod || (editingInterface ? editingInterface.httpMethod : 'ALL'),
|
|
421
510
|
active: true
|
|
422
511
|
};
|
|
423
512
|
|
|
@@ -429,13 +518,11 @@ const InterfaceManagement = () => {
|
|
|
429
518
|
interfaceData.headers = headers;
|
|
430
519
|
}
|
|
431
520
|
|
|
432
|
-
//
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
);
|
|
438
|
-
}
|
|
521
|
+
// 添加参数匹配规则(始终发送,空数组用于清空后端旧值)
|
|
522
|
+
const filteredParamMatchers = Array.isArray(values.paramMatchers)
|
|
523
|
+
? values.paramMatchers.filter(matcher => matcher && matcher.paramPath && matcher.paramValue)
|
|
524
|
+
: [];
|
|
525
|
+
interfaceData.paramMatchers = filteredParamMatchers;
|
|
439
526
|
|
|
440
527
|
console.log('提交接口数据:', interfaceData);
|
|
441
528
|
|
|
@@ -476,6 +563,7 @@ const InterfaceManagement = () => {
|
|
|
476
563
|
|
|
477
564
|
const handleCancel = () => {
|
|
478
565
|
setModalVisible(false);
|
|
566
|
+
setIsDuplicateMode(false);
|
|
479
567
|
};
|
|
480
568
|
|
|
481
569
|
const handleSelectFeature = (featureId) => {
|
|
@@ -905,7 +993,7 @@ const InterfaceManagement = () => {
|
|
|
905
993
|
{
|
|
906
994
|
title: '操作',
|
|
907
995
|
key: 'action',
|
|
908
|
-
width:
|
|
996
|
+
width: 220,
|
|
909
997
|
render: (_, record) => (
|
|
910
998
|
<div className="action-buttons">
|
|
911
999
|
<Button
|
|
@@ -913,6 +1001,13 @@ const InterfaceManagement = () => {
|
|
|
913
1001
|
icon={<EditOutlined />}
|
|
914
1002
|
onClick={() => handleEditInterface(record)}
|
|
915
1003
|
/>
|
|
1004
|
+
<Tooltip title="复制新增">
|
|
1005
|
+
<Button
|
|
1006
|
+
type="text"
|
|
1007
|
+
icon={<CopyOutlined />}
|
|
1008
|
+
onClick={() => handleDuplicate(record)}
|
|
1009
|
+
/>
|
|
1010
|
+
</Tooltip>
|
|
916
1011
|
<Popconfirm
|
|
917
1012
|
title="确定要删除此接口吗?"
|
|
918
1013
|
onConfirm={() => handleDeleteInterface(record.id)}
|
|
@@ -1252,7 +1347,7 @@ const InterfaceManagement = () => {
|
|
|
1252
1347
|
|
|
1253
1348
|
{/* 接口编辑/创建模态框 */}
|
|
1254
1349
|
<Modal
|
|
1255
|
-
title={editingInterface ? '编辑接口' : '添加接口'}
|
|
1350
|
+
title={editingInterface ? '编辑接口' : (isDuplicateMode ? '复制新增接口' : '添加接口')}
|
|
1256
1351
|
open={modalVisible}
|
|
1257
1352
|
onOk={handleSubmit}
|
|
1258
1353
|
onCancel={handleCancel}
|
|
@@ -1298,14 +1393,21 @@ const InterfaceManagement = () => {
|
|
|
1298
1393
|
tooltip="为接口设置分组,便于管理和批量操作"
|
|
1299
1394
|
>
|
|
1300
1395
|
<Select
|
|
1301
|
-
placeholder="
|
|
1396
|
+
placeholder="选择或创建分组"
|
|
1302
1397
|
showSearch
|
|
1303
1398
|
allowClear
|
|
1304
1399
|
style={{ width: '100%' }}
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1400
|
+
mode="tags"
|
|
1401
|
+
maxTagCount="responsive"
|
|
1402
|
+
maxTagTextLength={10}
|
|
1403
|
+
onChange={(value) => {
|
|
1404
|
+
// 如果值是数组(tags模式),只取第一个元素
|
|
1405
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
1406
|
+
// 如果第一个元素是空字符串,则设置为undefined
|
|
1407
|
+
const groupValue = value[0] === '' ? undefined : value[0];
|
|
1408
|
+
form.setFieldsValue({ group: groupValue });
|
|
1409
|
+
}
|
|
1410
|
+
}}
|
|
1309
1411
|
onInputKeyDown={(e) => {
|
|
1310
1412
|
// 防止回车键提交表单
|
|
1311
1413
|
if (e.key === 'Enter') {
|
|
@@ -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}`);
|
|
@@ -391,8 +479,9 @@ const InterfaceManagement = () => {
|
|
|
391
479
|
|
|
392
480
|
const handleSubmit = async () => {
|
|
393
481
|
try {
|
|
394
|
-
// 表单验证
|
|
395
|
-
|
|
482
|
+
// 表单验证 - 先验证所有字段,再获取所有字段值(包括折叠的)
|
|
483
|
+
await form.validateFields();
|
|
484
|
+
const values = form.getFieldsValue(true); // true表示获取所有字段,包括未渲染的
|
|
396
485
|
console.log('表单提交数据:', values);
|
|
397
486
|
|
|
398
487
|
// 处理自定义请求头
|
|
@@ -411,19 +500,19 @@ const InterfaceManagement = () => {
|
|
|
411
500
|
groupValue = groupValue.length > 0 ? groupValue[0] : '';
|
|
412
501
|
}
|
|
413
502
|
|
|
414
|
-
// 构建接口数据
|
|
503
|
+
// 构建接口数据 - 在编辑模式下,确保关键字段不丢失
|
|
415
504
|
const interfaceData = {
|
|
416
|
-
name: values.name,
|
|
417
|
-
group: groupValue || '', // 确保group不为undefined
|
|
418
|
-
urlPattern: values.pattern,
|
|
419
|
-
proxyType: values.proxyType,
|
|
505
|
+
name: values.name || (editingInterface ? editingInterface.name : ''),
|
|
506
|
+
group: groupValue || (editingInterface ? editingInterface.group : '') || '', // 确保group不为undefined
|
|
507
|
+
urlPattern: values.pattern || (editingInterface ? editingInterface.urlPattern : ''),
|
|
508
|
+
proxyType: values.proxyType || (editingInterface ? editingInterface.proxyType : 'response'),
|
|
420
509
|
featureId: selectedFeatureId,
|
|
421
|
-
responses: values.responses,
|
|
422
|
-
activeResponseId: values.activeResponseId,
|
|
423
|
-
httpStatus: parseInt(values.statusCode, 10), // 转换为数字
|
|
424
|
-
contentType: values.contentType,
|
|
425
|
-
responseDelay: parseInt(values.responseDelay, 10) || 0,
|
|
426
|
-
httpMethod: values.httpMethod,
|
|
510
|
+
responses: values.responses || (editingInterface ? editingInterface.responses : []),
|
|
511
|
+
activeResponseId: values.activeResponseId || (editingInterface ? editingInterface.activeResponseId : null),
|
|
512
|
+
httpStatus: parseInt(values.statusCode, 10) || (editingInterface ? editingInterface.httpStatus : 200), // 转换为数字
|
|
513
|
+
contentType: values.contentType || (editingInterface ? editingInterface.contentType : 'application/json; charset=utf-8'),
|
|
514
|
+
responseDelay: parseInt(values.responseDelay, 10) || (editingInterface ? editingInterface.responseDelay : 0) || 0,
|
|
515
|
+
httpMethod: values.httpMethod || (editingInterface ? editingInterface.httpMethod : 'ALL'),
|
|
427
516
|
active: true
|
|
428
517
|
};
|
|
429
518
|
|
|
@@ -435,13 +524,11 @@ const InterfaceManagement = () => {
|
|
|
435
524
|
interfaceData.headers = headers;
|
|
436
525
|
}
|
|
437
526
|
|
|
438
|
-
//
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
);
|
|
444
|
-
}
|
|
527
|
+
// 添加参数匹配规则(始终发送,空数组用于清空后端旧值)
|
|
528
|
+
const filteredParamMatchers = Array.isArray(values.paramMatchers)
|
|
529
|
+
? values.paramMatchers.filter(matcher => matcher && matcher.paramPath && matcher.paramValue)
|
|
530
|
+
: [];
|
|
531
|
+
interfaceData.paramMatchers = filteredParamMatchers;
|
|
445
532
|
|
|
446
533
|
console.log('提交接口数据:', interfaceData);
|
|
447
534
|
|
|
@@ -482,6 +569,7 @@ const InterfaceManagement = () => {
|
|
|
482
569
|
|
|
483
570
|
const handleCancel = () => {
|
|
484
571
|
setModalVisible(false);
|
|
572
|
+
setIsDuplicateMode(false);
|
|
485
573
|
};
|
|
486
574
|
|
|
487
575
|
const handleSelectFeature = (featureId) => {
|
|
@@ -911,7 +999,7 @@ const InterfaceManagement = () => {
|
|
|
911
999
|
{
|
|
912
1000
|
title: '操作',
|
|
913
1001
|
key: 'action',
|
|
914
|
-
width:
|
|
1002
|
+
width: 220,
|
|
915
1003
|
render: (_, record) => (
|
|
916
1004
|
<div className="action-buttons">
|
|
917
1005
|
<Button
|
|
@@ -919,6 +1007,13 @@ const InterfaceManagement = () => {
|
|
|
919
1007
|
icon={<EditOutlined />}
|
|
920
1008
|
onClick={() => handleEditInterface(record)}
|
|
921
1009
|
/>
|
|
1010
|
+
<Tooltip title="复制新增">
|
|
1011
|
+
<Button
|
|
1012
|
+
type="text"
|
|
1013
|
+
icon={<CopyOutlined />}
|
|
1014
|
+
onClick={() => handleDuplicate(record)}
|
|
1015
|
+
/>
|
|
1016
|
+
</Tooltip>
|
|
922
1017
|
<Popconfirm
|
|
923
1018
|
title="确定要删除此接口吗?"
|
|
924
1019
|
onConfirm={() => handleDeleteInterface(record.id)}
|
|
@@ -1271,7 +1366,7 @@ const InterfaceManagement = () => {
|
|
|
1271
1366
|
alignItems: 'center',
|
|
1272
1367
|
gap: '8px'
|
|
1273
1368
|
}}>
|
|
1274
|
-
<span>{editingInterface ? '编辑接口' : '添加接口'}</span>
|
|
1369
|
+
<span>{editingInterface ? '编辑接口' : (isDuplicateMode ? '复制新增接口' : '添加接口')}</span>
|
|
1275
1370
|
<Badge
|
|
1276
1371
|
count="配置向导"
|
|
1277
1372
|
style={{
|
|
@@ -1320,8 +1415,8 @@ const InterfaceManagement = () => {
|
|
|
1320
1415
|
<Collapse
|
|
1321
1416
|
defaultActiveKey={
|
|
1322
1417
|
editingInterface && editingInterface.proxyType === 'response'
|
|
1323
|
-
? ['3']
|
|
1324
|
-
: ['1', '2', '3']
|
|
1418
|
+
? ['3'] // mock代理场景:只展开第3步(高级配置)
|
|
1419
|
+
: ['1', '2', '3'] // 其他场景:展开所有步骤
|
|
1325
1420
|
}
|
|
1326
1421
|
style={{ marginBottom: '16px' }}
|
|
1327
1422
|
ghost
|
|
@@ -1353,14 +1448,21 @@ const InterfaceManagement = () => {
|
|
|
1353
1448
|
tooltip="为接口设置分组,便于管理和批量操作"
|
|
1354
1449
|
>
|
|
1355
1450
|
<Select
|
|
1356
|
-
placeholder="
|
|
1451
|
+
placeholder="选择或创建分组"
|
|
1357
1452
|
showSearch
|
|
1358
1453
|
allowClear
|
|
1359
1454
|
style={{ width: '100%' }}
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1455
|
+
mode="tags"
|
|
1456
|
+
maxTagCount="responsive"
|
|
1457
|
+
maxTagTextLength={10}
|
|
1458
|
+
onChange={(value) => {
|
|
1459
|
+
// 如果值是数组(tags模式),只取第一个元素
|
|
1460
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
1461
|
+
// 如果第一个元素是空字符串,则设置为undefined
|
|
1462
|
+
const groupValue = value[0] === '' ? undefined : value[0];
|
|
1463
|
+
form.setFieldsValue({ group: groupValue });
|
|
1464
|
+
}
|
|
1465
|
+
}}
|
|
1364
1466
|
onInputKeyDown={(e) => {
|
|
1365
1467
|
// 防止回车键提交表单
|
|
1366
1468
|
if (e.key === 'Enter') {
|