whistle.mock-plugins 1.1.1-dev.8 → 1.1.1-dev.9
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 +5 -0
- package/app/public/js/index.js +1 -1
- package/lib/routes/interfaces.js +169 -0
- package/package.json +1 -1
- package/ui/src/pages/InterfaceManagement.js +200 -10
package/lib/routes/interfaces.js
CHANGED
|
@@ -516,6 +516,175 @@ const initRouter = () => {
|
|
|
516
516
|
}
|
|
517
517
|
});
|
|
518
518
|
|
|
519
|
+
// 批量更新接口状态
|
|
520
|
+
router.patch('/interfaces', (req, res) => {
|
|
521
|
+
try {
|
|
522
|
+
const { active } = req.query;
|
|
523
|
+
const { featureId, group } = req.body;
|
|
524
|
+
|
|
525
|
+
if (active === undefined) {
|
|
526
|
+
return res.status(400).json({
|
|
527
|
+
code: 1,
|
|
528
|
+
message: '状态参数为必填项'
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
if (!featureId) {
|
|
533
|
+
return res.status(400).json({
|
|
534
|
+
code: 1,
|
|
535
|
+
message: '功能ID为必填项'
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// 检查功能是否存在
|
|
540
|
+
const featuresFile = path.join(DATA_DIR, 'features.json');
|
|
541
|
+
if (!fs.existsSync(featuresFile)) {
|
|
542
|
+
return res.status(404).json({
|
|
543
|
+
code: 1,
|
|
544
|
+
message: '功能不存在'
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
const features = fs.readJsonSync(featuresFile);
|
|
549
|
+
const feature = features.find(f => f.id === featureId);
|
|
550
|
+
if (!feature) {
|
|
551
|
+
return res.status(404).json({
|
|
552
|
+
code: 1,
|
|
553
|
+
message: '功能不存在'
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// 读取接口列表
|
|
558
|
+
const interfacesFile = path.join(DATA_DIR, `interfaces-${featureId}.json`);
|
|
559
|
+
if (!fs.existsSync(interfacesFile)) {
|
|
560
|
+
return res.status(404).json({
|
|
561
|
+
code: 1,
|
|
562
|
+
message: '接口列表不存在'
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
const interfaces = fs.readJsonSync(interfacesFile);
|
|
567
|
+
|
|
568
|
+
// 根据分组筛选要更新的接口
|
|
569
|
+
let updatedCount = 0;
|
|
570
|
+
const updatedInterfaces = interfaces.map(item => {
|
|
571
|
+
// 如果指定了分组,只更新该分组下的接口
|
|
572
|
+
if (group && item.group !== group) {
|
|
573
|
+
return item;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// 更新接口状态
|
|
577
|
+
if (item.active !== (active === 'true')) {
|
|
578
|
+
updatedCount++;
|
|
579
|
+
return {
|
|
580
|
+
...item,
|
|
581
|
+
active: active === 'true',
|
|
582
|
+
updatedAt: new Date().toISOString()
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
return item;
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
// 保存更新后的接口列表
|
|
590
|
+
fs.writeJsonSync(interfacesFile, updatedInterfaces, { spaces: 2 });
|
|
591
|
+
|
|
592
|
+
res.json({
|
|
593
|
+
code: 0,
|
|
594
|
+
message: `成功${active === 'true' ? '启用' : '禁用'} ${updatedCount} 个接口`,
|
|
595
|
+
data: { updatedCount }
|
|
596
|
+
});
|
|
597
|
+
} catch (err) {
|
|
598
|
+
console.error('批量更新接口状态失败:', err);
|
|
599
|
+
res.status(500).json({
|
|
600
|
+
code: 1,
|
|
601
|
+
message: '批量更新接口状态失败: ' + err.message
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
// 部分更新接口
|
|
607
|
+
router.patch('/interfaces/:id', (req, res) => {
|
|
608
|
+
try {
|
|
609
|
+
const { id } = req.params;
|
|
610
|
+
const updateData = req.body;
|
|
611
|
+
|
|
612
|
+
if (!id) {
|
|
613
|
+
return res.status(400).json({
|
|
614
|
+
code: 1,
|
|
615
|
+
message: '接口ID为必填项'
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// 检查功能是否存在
|
|
620
|
+
const featuresFile = path.join(DATA_DIR, 'features.json');
|
|
621
|
+
if (!fs.existsSync(featuresFile)) {
|
|
622
|
+
return res.status(404).json({
|
|
623
|
+
code: 1,
|
|
624
|
+
message: '功能不存在'
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
const features = fs.readJsonSync(featuresFile);
|
|
629
|
+
|
|
630
|
+
// 在所有功能模块中查找接口
|
|
631
|
+
let foundInterface = null;
|
|
632
|
+
let foundFeature = null;
|
|
633
|
+
let foundInterfaceIndex = -1;
|
|
634
|
+
let interfacesFile = '';
|
|
635
|
+
|
|
636
|
+
for (const feature of features) {
|
|
637
|
+
const featureInterfacesFile = path.join(DATA_DIR, `interfaces-${feature.id}.json`);
|
|
638
|
+
if (fs.existsSync(featureInterfacesFile)) {
|
|
639
|
+
const interfaces = fs.readJsonSync(featureInterfacesFile);
|
|
640
|
+
const index = interfaces.findIndex(item => item.id === id);
|
|
641
|
+
|
|
642
|
+
if (index !== -1) {
|
|
643
|
+
foundInterface = interfaces[index];
|
|
644
|
+
foundFeature = feature;
|
|
645
|
+
foundInterfaceIndex = index;
|
|
646
|
+
interfacesFile = featureInterfacesFile;
|
|
647
|
+
break;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
if (!foundInterface) {
|
|
653
|
+
return res.status(404).json({
|
|
654
|
+
code: 1,
|
|
655
|
+
message: '接口不存在'
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// 读取接口所在文件的所有接口
|
|
660
|
+
const interfaces = fs.readJsonSync(interfacesFile);
|
|
661
|
+
|
|
662
|
+
// 更新接口
|
|
663
|
+
const updatedInterface = {
|
|
664
|
+
...foundInterface,
|
|
665
|
+
...updateData,
|
|
666
|
+
updatedAt: new Date().toISOString()
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
interfaces[foundInterfaceIndex] = updatedInterface;
|
|
670
|
+
|
|
671
|
+
// 保存更新后的接口列表
|
|
672
|
+
fs.writeJsonSync(interfacesFile, interfaces, { spaces: 2 });
|
|
673
|
+
|
|
674
|
+
res.json({
|
|
675
|
+
code: 0,
|
|
676
|
+
message: '接口更新成功',
|
|
677
|
+
data: updatedInterface
|
|
678
|
+
});
|
|
679
|
+
} catch (err) {
|
|
680
|
+
console.error('更新接口失败:', err);
|
|
681
|
+
res.status(500).json({
|
|
682
|
+
code: 1,
|
|
683
|
+
message: '更新接口失败: ' + err.message
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
});
|
|
687
|
+
|
|
519
688
|
return router;
|
|
520
689
|
};
|
|
521
690
|
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@ import AppLayout from '../components/AppLayout';
|
|
|
4
4
|
import {
|
|
5
5
|
Table, Button, Modal, Form, Input, Select, message, Switch,
|
|
6
6
|
Popconfirm, Alert, Space, Card, Badge, Tooltip, Row, Col,
|
|
7
|
-
Popover, Checkbox
|
|
7
|
+
Popover, Checkbox, Tag
|
|
8
8
|
} from 'antd';
|
|
9
9
|
import {
|
|
10
10
|
PlusOutlined, EditOutlined, DeleteOutlined,
|
|
@@ -32,6 +32,7 @@ const { Option } = Select;
|
|
|
32
32
|
const COLUMN_CONFIG = [
|
|
33
33
|
{ key: 'active', title: '状态', required: true },
|
|
34
34
|
{ key: 'name', title: '名称', required: true },
|
|
35
|
+
{ key: 'group', title: '分组', required: false },
|
|
35
36
|
{ key: 'urlPattern', title: 'URL匹配规则', required: false },
|
|
36
37
|
{ key: 'proxyType', title: '处理方式', required: false },
|
|
37
38
|
{ key: 'currentResponse', title: '当前响应', required: false },
|
|
@@ -57,6 +58,11 @@ const InterfaceManagement = () => {
|
|
|
57
58
|
const [interfacesLoading, setInterfacesLoading] = useState(false);
|
|
58
59
|
const [selectedFeatureId, setSelectedFeatureId] = useState(null);
|
|
59
60
|
|
|
61
|
+
// 分组状态
|
|
62
|
+
const [groups, setGroups] = useState([]);
|
|
63
|
+
const [selectedGroup, setSelectedGroup] = useState(null);
|
|
64
|
+
const [groupActionLoading, setGroupActionLoading] = useState(false);
|
|
65
|
+
|
|
60
66
|
// 模态框状态
|
|
61
67
|
const [modalVisible, setModalVisible] = useState(false);
|
|
62
68
|
const [previewVisible, setPreviewVisible] = useState(false);
|
|
@@ -166,6 +172,9 @@ const InterfaceManagement = () => {
|
|
|
166
172
|
|
|
167
173
|
setInterfaces(processedInterfaces);
|
|
168
174
|
console.log('处理后的接口列表:', processedInterfaces);
|
|
175
|
+
|
|
176
|
+
// 提取并更新分组列表
|
|
177
|
+
updateGroups(processedInterfaces);
|
|
169
178
|
} else {
|
|
170
179
|
console.warn('接口数据格式不正确:', response.data);
|
|
171
180
|
setInterfaces([]);
|
|
@@ -179,6 +188,41 @@ const InterfaceManagement = () => {
|
|
|
179
188
|
setInterfacesLoading(false);
|
|
180
189
|
}
|
|
181
190
|
};
|
|
191
|
+
|
|
192
|
+
// 提取并更新分组列表
|
|
193
|
+
const updateGroups = (interfaces) => {
|
|
194
|
+
// 从接口列表中提取所有分组
|
|
195
|
+
const groupSet = new Set();
|
|
196
|
+
interfaces.forEach(item => {
|
|
197
|
+
if (item.group) {
|
|
198
|
+
groupSet.add(item.group);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// 转换为数组并排序
|
|
203
|
+
const groupArray = Array.from(groupSet).sort();
|
|
204
|
+
setGroups(groupArray);
|
|
205
|
+
|
|
206
|
+
// 如果当前选中的分组不在列表中,重置选中的分组
|
|
207
|
+
if (selectedGroup && !groupArray.includes(selectedGroup)) {
|
|
208
|
+
setSelectedGroup(null);
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// 根据分组筛选接口
|
|
213
|
+
const getFilteredInterfaces = () => {
|
|
214
|
+
// 首先按功能模块筛选
|
|
215
|
+
const featureFiltered = interfaces.filter(item =>
|
|
216
|
+
!selectedFeatureId || item.featureId === selectedFeatureId
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
// 然后按分组筛选
|
|
220
|
+
if (selectedGroup) {
|
|
221
|
+
return featureFiltered.filter(item => item.group === selectedGroup);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return featureFiltered;
|
|
225
|
+
};
|
|
182
226
|
|
|
183
227
|
const handleAddInterface = () => {
|
|
184
228
|
if (!selectedFeatureId) {
|
|
@@ -256,6 +300,7 @@ const InterfaceManagement = () => {
|
|
|
256
300
|
// 设置表单值
|
|
257
301
|
form.setFieldsValue({
|
|
258
302
|
name: record.name,
|
|
303
|
+
group: record.group || '',
|
|
259
304
|
pattern: record.urlPattern,
|
|
260
305
|
proxyType: record.proxyType || 'response',
|
|
261
306
|
statusCode: (record.httpStatus || record.statusCode || 200).toString(),
|
|
@@ -294,12 +339,15 @@ const InterfaceManagement = () => {
|
|
|
294
339
|
|
|
295
340
|
const handleToggleActive = async (id, currentActive) => {
|
|
296
341
|
try {
|
|
297
|
-
const response = await axios.patch(`/cgi-bin/interfaces
|
|
342
|
+
const response = await axios.patch(`/cgi-bin/interfaces/${id}`, {
|
|
298
343
|
active: !currentActive
|
|
299
344
|
});
|
|
300
345
|
if (response.data && response.data.code === 0) {
|
|
301
346
|
message.success(`接口${!currentActive ? '启用' : '禁用'}成功`);
|
|
302
347
|
fetchInterfaces();
|
|
348
|
+
|
|
349
|
+
// 刷新规则缓存
|
|
350
|
+
refreshCacheAfterUpdate();
|
|
303
351
|
} else {
|
|
304
352
|
throw new Error(response.data?.message || `接口${!currentActive ? '启用' : '禁用'}失败`);
|
|
305
353
|
}
|
|
@@ -328,6 +376,7 @@ const InterfaceManagement = () => {
|
|
|
328
376
|
// 构建接口数据
|
|
329
377
|
const interfaceData = {
|
|
330
378
|
name: values.name,
|
|
379
|
+
group: values.group,
|
|
331
380
|
urlPattern: values.pattern,
|
|
332
381
|
proxyType: values.proxyType,
|
|
333
382
|
featureId: selectedFeatureId,
|
|
@@ -460,9 +509,7 @@ const InterfaceManagement = () => {
|
|
|
460
509
|
}
|
|
461
510
|
};
|
|
462
511
|
|
|
463
|
-
const filteredInterfaces =
|
|
464
|
-
!selectedFeatureId || item.featureId === selectedFeatureId
|
|
465
|
-
);
|
|
512
|
+
const filteredInterfaces = getFilteredInterfaces();
|
|
466
513
|
|
|
467
514
|
// 处理表格变化(排序、分页)
|
|
468
515
|
const handleTableChange = (pagination, filters, sorter) => {
|
|
@@ -527,6 +574,27 @@ const InterfaceManagement = () => {
|
|
|
527
574
|
sorter: (a, b) => a.name.localeCompare(b.name),
|
|
528
575
|
render: (text) => <span className="interface-name">{text}</span>,
|
|
529
576
|
},
|
|
577
|
+
{
|
|
578
|
+
title: '分组',
|
|
579
|
+
dataIndex: 'group',
|
|
580
|
+
key: 'group',
|
|
581
|
+
width: 120,
|
|
582
|
+
sorter: (a, b) => {
|
|
583
|
+
const groupA = a.group || '';
|
|
584
|
+
const groupB = b.group || '';
|
|
585
|
+
return groupA.localeCompare(groupB);
|
|
586
|
+
},
|
|
587
|
+
render: (group) => {
|
|
588
|
+
if (!group) {
|
|
589
|
+
return <span style={{ color: '#999', fontStyle: 'italic' }}>未分组</span>;
|
|
590
|
+
}
|
|
591
|
+
return (
|
|
592
|
+
<Tag color="blue" style={{ cursor: 'pointer' }} onClick={() => setSelectedGroup(group)}>
|
|
593
|
+
{group}
|
|
594
|
+
</Tag>
|
|
595
|
+
);
|
|
596
|
+
},
|
|
597
|
+
},
|
|
530
598
|
{
|
|
531
599
|
title: 'URL匹配规则',
|
|
532
600
|
dataIndex: 'urlPattern',
|
|
@@ -775,6 +843,28 @@ const InterfaceManagement = () => {
|
|
|
775
843
|
const visibleColumns = tableConfig.visibleColumns || COLUMN_CONFIG.map(col => col.key);
|
|
776
844
|
const columns = allColumns.filter(col => visibleColumns.includes(col.key));
|
|
777
845
|
|
|
846
|
+
// 分组筛选和操作区域
|
|
847
|
+
const handleBatchToggleActive = async (active) => {
|
|
848
|
+
try {
|
|
849
|
+
setGroupActionLoading(true);
|
|
850
|
+
const response = await axios.patch(`/cgi-bin/interfaces?active=${active}`, {
|
|
851
|
+
featureId: selectedFeatureId,
|
|
852
|
+
group: selectedGroup
|
|
853
|
+
});
|
|
854
|
+
if (response.data && response.data.code === 0) {
|
|
855
|
+
message.success(`分组 "${selectedGroup}" 中的接口已成功${active ? '启用' : '禁用'}`);
|
|
856
|
+
fetchInterfaces();
|
|
857
|
+
} else {
|
|
858
|
+
throw new Error(response.data?.message || '批量操作失败');
|
|
859
|
+
}
|
|
860
|
+
} catch (error) {
|
|
861
|
+
console.error('批量操作失败:', error);
|
|
862
|
+
message.error(error.response?.data?.message || error.message || '批量操作失败');
|
|
863
|
+
} finally {
|
|
864
|
+
setGroupActionLoading(false);
|
|
865
|
+
}
|
|
866
|
+
};
|
|
867
|
+
|
|
778
868
|
return (
|
|
779
869
|
<AppLayout>
|
|
780
870
|
<div className="interface-management-container">
|
|
@@ -828,6 +918,77 @@ const InterfaceManagement = () => {
|
|
|
828
918
|
/>
|
|
829
919
|
)}
|
|
830
920
|
|
|
921
|
+
{/* 分组筛选和操作区域 */}
|
|
922
|
+
<div style={{
|
|
923
|
+
display: 'flex',
|
|
924
|
+
justifyContent: 'space-between',
|
|
925
|
+
alignItems: 'center',
|
|
926
|
+
marginBottom: 16,
|
|
927
|
+
padding: '12px 16px',
|
|
928
|
+
backgroundColor: '#f5f5f5',
|
|
929
|
+
borderRadius: '4px'
|
|
930
|
+
}}>
|
|
931
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '16px' }}>
|
|
932
|
+
<span>分组筛选:</span>
|
|
933
|
+
<Select
|
|
934
|
+
value={selectedGroup}
|
|
935
|
+
onChange={value => setSelectedGroup(value)}
|
|
936
|
+
style={{ width: 200 }}
|
|
937
|
+
placeholder="选择分组"
|
|
938
|
+
allowClear
|
|
939
|
+
showSearch
|
|
940
|
+
loading={interfacesLoading}
|
|
941
|
+
>
|
|
942
|
+
{groups.map(group => (
|
|
943
|
+
<Option key={group} value={group}>{group}</Option>
|
|
944
|
+
))}
|
|
945
|
+
</Select>
|
|
946
|
+
{selectedGroup && (
|
|
947
|
+
<Button
|
|
948
|
+
type="link"
|
|
949
|
+
onClick={() => setSelectedGroup(null)}
|
|
950
|
+
size="small"
|
|
951
|
+
>
|
|
952
|
+
清除筛选
|
|
953
|
+
</Button>
|
|
954
|
+
)}
|
|
955
|
+
</div>
|
|
956
|
+
|
|
957
|
+
{selectedGroup && (
|
|
958
|
+
<div style={{ display: 'flex', gap: '8px' }}>
|
|
959
|
+
<Popconfirm
|
|
960
|
+
title={`确定要启用分组 "${selectedGroup}" 中的所有接口吗?`}
|
|
961
|
+
onConfirm={() => handleBatchToggleActive(true)}
|
|
962
|
+
okText="确定"
|
|
963
|
+
cancelText="取消"
|
|
964
|
+
>
|
|
965
|
+
<Button
|
|
966
|
+
type="primary"
|
|
967
|
+
size="small"
|
|
968
|
+
loading={groupActionLoading}
|
|
969
|
+
>
|
|
970
|
+
批量启用
|
|
971
|
+
</Button>
|
|
972
|
+
</Popconfirm>
|
|
973
|
+
|
|
974
|
+
<Popconfirm
|
|
975
|
+
title={`确定要禁用分组 "${selectedGroup}" 中的所有接口吗?`}
|
|
976
|
+
onConfirm={() => handleBatchToggleActive(false)}
|
|
977
|
+
okText="确定"
|
|
978
|
+
cancelText="取消"
|
|
979
|
+
>
|
|
980
|
+
<Button
|
|
981
|
+
danger
|
|
982
|
+
size="small"
|
|
983
|
+
loading={groupActionLoading}
|
|
984
|
+
>
|
|
985
|
+
批量禁用
|
|
986
|
+
</Button>
|
|
987
|
+
</Popconfirm>
|
|
988
|
+
</div>
|
|
989
|
+
)}
|
|
990
|
+
</div>
|
|
991
|
+
|
|
831
992
|
{/* 接口列表状态栏 */}
|
|
832
993
|
{filteredInterfaces.length > 0 && !interfacesLoading && (
|
|
833
994
|
<div style={{
|
|
@@ -843,6 +1004,11 @@ const InterfaceManagement = () => {
|
|
|
843
1004
|
}}>
|
|
844
1005
|
<span>
|
|
845
1006
|
当前功能模块:<strong>{selectedFeature?.name}</strong>
|
|
1007
|
+
{selectedGroup && (
|
|
1008
|
+
<span style={{ marginLeft: 8 }}>
|
|
1009
|
+
| 分组:<Tag color="blue">{selectedGroup}</Tag>
|
|
1010
|
+
</span>
|
|
1011
|
+
)}
|
|
846
1012
|
</span>
|
|
847
1013
|
<span>
|
|
848
1014
|
共 {filteredInterfaces.length} 个接口,每页显示 {tableConfig.pageSize} 个
|
|
@@ -957,6 +1123,7 @@ const InterfaceManagement = () => {
|
|
|
957
1123
|
layout="vertical"
|
|
958
1124
|
initialValues={{
|
|
959
1125
|
name: '',
|
|
1126
|
+
group: '',
|
|
960
1127
|
pattern: '',
|
|
961
1128
|
proxyType: 'response',
|
|
962
1129
|
statusCode: '200',
|
|
@@ -969,7 +1136,7 @@ const InterfaceManagement = () => {
|
|
|
969
1136
|
responseDelay: '0'
|
|
970
1137
|
}}
|
|
971
1138
|
>
|
|
972
|
-
{/*
|
|
1139
|
+
{/* 基础信息表单项 */}
|
|
973
1140
|
<div style={{ display: 'flex', flexDirection: 'row', gap: '16px' }}>
|
|
974
1141
|
<div style={{ flex: 1 }}>
|
|
975
1142
|
<Form.Item
|
|
@@ -980,6 +1147,26 @@ const InterfaceManagement = () => {
|
|
|
980
1147
|
<Input placeholder="请输入接口名称" />
|
|
981
1148
|
</Form.Item>
|
|
982
1149
|
</div>
|
|
1150
|
+
<div style={{ flex: 1 }}>
|
|
1151
|
+
<Form.Item
|
|
1152
|
+
name="group"
|
|
1153
|
+
label="分组"
|
|
1154
|
+
tooltip="为接口设置分组,便于管理和批量操作"
|
|
1155
|
+
>
|
|
1156
|
+
<Select
|
|
1157
|
+
placeholder="选择或创建分组"
|
|
1158
|
+
showSearch
|
|
1159
|
+
allowClear
|
|
1160
|
+
>
|
|
1161
|
+
{Array.from(new Set(interfaces.map(item => item.group).filter(Boolean))).map(group => (
|
|
1162
|
+
<Option key={group} value={group}>{group}</Option>
|
|
1163
|
+
))}
|
|
1164
|
+
</Select>
|
|
1165
|
+
</Form.Item>
|
|
1166
|
+
</div>
|
|
1167
|
+
</div>
|
|
1168
|
+
|
|
1169
|
+
<div style={{ display: 'flex', flexDirection: 'row', gap: '16px' }}>
|
|
983
1170
|
<div style={{ flex: 1 }}>
|
|
984
1171
|
<Form.Item
|
|
985
1172
|
name="pattern"
|
|
@@ -1059,9 +1246,6 @@ const InterfaceManagement = () => {
|
|
|
1059
1246
|
/>
|
|
1060
1247
|
</Form.Item>
|
|
1061
1248
|
</div>
|
|
1062
|
-
</div>
|
|
1063
|
-
|
|
1064
|
-
<div style={{ display: 'flex', flexDirection: 'row', gap: '16px' }}>
|
|
1065
1249
|
<div style={{ flex: 1 }}>
|
|
1066
1250
|
<Form.Item
|
|
1067
1251
|
name="proxyType"
|
|
@@ -1089,7 +1273,7 @@ const InterfaceManagement = () => {
|
|
|
1089
1273
|
const patternInput = document.querySelector('input[placeholder="根据选择的处理方式输入相应格式的URL"]');
|
|
1090
1274
|
if (patternInput) {
|
|
1091
1275
|
if (value === 'response') {
|
|
1092
|
-
patternInput.placeholder = "例如:/api/users,/api/users/*,/api
|
|
1276
|
+
patternInput.placeholder = "例如:/api/users,/api/users/*,/api\\/users\\/\\d+/";
|
|
1093
1277
|
} else if (value === 'redirect') {
|
|
1094
1278
|
patternInput.placeholder = "例如:https://example.com/api";
|
|
1095
1279
|
} else if (value === 'url_redirect') {
|
|
@@ -1103,6 +1287,9 @@ const InterfaceManagement = () => {
|
|
|
1103
1287
|
</Select>
|
|
1104
1288
|
</Form.Item>
|
|
1105
1289
|
</div>
|
|
1290
|
+
</div>
|
|
1291
|
+
|
|
1292
|
+
<div style={{ display: 'flex', flexDirection: 'row', gap: '16px' }}>
|
|
1106
1293
|
<div style={{ flex: 1 }}>
|
|
1107
1294
|
<Form.Item
|
|
1108
1295
|
name="httpMethod"
|
|
@@ -1116,6 +1303,9 @@ const InterfaceManagement = () => {
|
|
|
1116
1303
|
</Select>
|
|
1117
1304
|
</Form.Item>
|
|
1118
1305
|
</div>
|
|
1306
|
+
<div style={{ flex: 1 }}>
|
|
1307
|
+
{/* 这里可以留空或添加其他字段 */}
|
|
1308
|
+
</div>
|
|
1119
1309
|
</div>
|
|
1120
1310
|
|
|
1121
1311
|
{/* 根据proxyType显示不同的表单项 */}
|