whistle.mock-plugins 1.1.3-dev.9 → 1.2.0-beta.1
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 -0
- package/app/public/js/index.js +1 -1
- package/package.json +1 -1
- package/ui/src/pages/InterfaceManagementV2.js +179 -174
- package/ui/src/pages/MockDataV2.js +124 -96
- package/ui/src/styles/interface-management.css +156 -220
- package/ui/src/styles/mock-data.css +260 -22
package/package.json
CHANGED
|
@@ -10,12 +10,12 @@ import AppLayout from '../components/AppLayout';
|
|
|
10
10
|
import {
|
|
11
11
|
Table, Button, Modal, Form, Input, Select, message, Switch,
|
|
12
12
|
Popconfirm, Alert, Space, Card, Badge, Tooltip, Row, Col,
|
|
13
|
-
Popover, Checkbox, Tag, Input as AntInput, Radio, Drawer, Dropdown, Menu
|
|
13
|
+
Popover, Checkbox, Tag, Input as AntInput, Radio, Drawer, Dropdown, Menu, Collapse
|
|
14
14
|
} from 'antd';
|
|
15
15
|
import {
|
|
16
16
|
PlusOutlined, EditOutlined, DeleteOutlined,
|
|
17
17
|
FileTextOutlined, PlusCircleOutlined, SettingOutlined,
|
|
18
|
-
SearchOutlined, FilterOutlined, ReloadOutlined, DownOutlined
|
|
18
|
+
SearchOutlined, FilterOutlined, ReloadOutlined, DownOutlined, QuestionCircleOutlined
|
|
19
19
|
} from '@ant-design/icons';
|
|
20
20
|
import '../styles/interface-management.css';
|
|
21
21
|
import axios from 'axios';
|
|
@@ -679,40 +679,10 @@ const InterfaceManagement = () => {
|
|
|
679
679
|
},
|
|
680
680
|
render: (group) => {
|
|
681
681
|
if (!group) {
|
|
682
|
-
return
|
|
683
|
-
<span style={{
|
|
684
|
-
color: '#a0aec0',
|
|
685
|
-
fontStyle: 'italic',
|
|
686
|
-
fontSize: '12px'
|
|
687
|
-
}}>
|
|
688
|
-
未分组
|
|
689
|
-
</span>
|
|
690
|
-
);
|
|
682
|
+
return <span style={{ color: '#999', fontStyle: 'italic' }}>未分组</span>;
|
|
691
683
|
}
|
|
692
684
|
return (
|
|
693
|
-
<Tag
|
|
694
|
-
style={{
|
|
695
|
-
cursor: 'pointer',
|
|
696
|
-
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
697
|
-
border: 'none',
|
|
698
|
-
borderRadius: '12px',
|
|
699
|
-
color: '#ffffff',
|
|
700
|
-
fontWeight: '600',
|
|
701
|
-
fontSize: '11px',
|
|
702
|
-
padding: '2px 8px',
|
|
703
|
-
boxShadow: '0 2px 4px rgba(102, 126, 234, 0.3)',
|
|
704
|
-
transition: 'all 0.2s ease'
|
|
705
|
-
}}
|
|
706
|
-
onClick={() => setSelectedGroup(group)}
|
|
707
|
-
onMouseEnter={(e) => {
|
|
708
|
-
e.target.style.transform = 'translateY(-1px)';
|
|
709
|
-
e.target.style.boxShadow = '0 4px 8px rgba(102, 126, 234, 0.4)';
|
|
710
|
-
}}
|
|
711
|
-
onMouseLeave={(e) => {
|
|
712
|
-
e.target.style.transform = 'translateY(0)';
|
|
713
|
-
e.target.style.boxShadow = '0 2px 4px rgba(102, 126, 234, 0.3)';
|
|
714
|
-
}}
|
|
715
|
-
>
|
|
685
|
+
<Tag color="blue" style={{ cursor: 'pointer' }} onClick={() => setSelectedGroup(group)}>
|
|
716
686
|
{group}
|
|
717
687
|
</Tag>
|
|
718
688
|
);
|
|
@@ -732,31 +702,11 @@ const InterfaceManagement = () => {
|
|
|
732
702
|
width: 120,
|
|
733
703
|
render: (text) => {
|
|
734
704
|
const proxyType = proxyTypes.find(item => item.value === text);
|
|
735
|
-
const color = proxyType?.color || '#999';
|
|
736
|
-
const label = proxyType?.label || text;
|
|
737
|
-
|
|
738
705
|
return (
|
|
739
|
-
<
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
padding: '4px 10px',
|
|
744
|
-
borderRadius: '12px',
|
|
745
|
-
fontSize: '12px',
|
|
746
|
-
fontWeight: '600',
|
|
747
|
-
backgroundColor: color === '#1890ff' ? '#ebf8ff' :
|
|
748
|
-
color === '#52c41a' ? '#f0fff4' :
|
|
749
|
-
color === '#faad14' ? '#fffbf0' : '#f5f5f5',
|
|
750
|
-
color: color === '#1890ff' ? '#3182ce' :
|
|
751
|
-
color === '#52c41a' ? '#38a169' :
|
|
752
|
-
color === '#faad14' ? '#d69e2e' : '#718096',
|
|
753
|
-
border: `1px solid ${color === '#1890ff' ? '#bee3f8' :
|
|
754
|
-
color === '#52c41a' ? '#c6f6d5' :
|
|
755
|
-
color === '#faad14' ? '#feebc8' : '#e2e8f0'}`
|
|
756
|
-
}}
|
|
757
|
-
>
|
|
758
|
-
{label}
|
|
759
|
-
</span>
|
|
706
|
+
<Badge
|
|
707
|
+
color={proxyType?.color || '#999'}
|
|
708
|
+
text={proxyType?.label || text}
|
|
709
|
+
/>
|
|
760
710
|
);
|
|
761
711
|
},
|
|
762
712
|
},
|
|
@@ -780,22 +730,13 @@ const InterfaceManagement = () => {
|
|
|
780
730
|
return (
|
|
781
731
|
<Select
|
|
782
732
|
value={activeResponseId || record.responses[0]?.id}
|
|
783
|
-
style={{
|
|
784
|
-
width: '100%',
|
|
785
|
-
borderRadius: '6px'
|
|
786
|
-
}}
|
|
733
|
+
style={{ width: '100%' }}
|
|
787
734
|
onChange={(value) => handleResponseSwitch(record.id, value)}
|
|
788
735
|
disabled={record.proxyType !== 'response'}
|
|
789
|
-
size="small"
|
|
790
736
|
>
|
|
791
737
|
{record.responses.map(resp => (
|
|
792
738
|
<Option key={resp.id} value={resp.id}>
|
|
793
|
-
|
|
794
|
-
fontSize: '12px',
|
|
795
|
-
fontWeight: '500'
|
|
796
|
-
}}>
|
|
797
|
-
{resp.name}
|
|
798
|
-
</span>
|
|
739
|
+
{resp.name}
|
|
799
740
|
</Option>
|
|
800
741
|
))}
|
|
801
742
|
</Select>
|
|
@@ -973,28 +914,18 @@ const InterfaceManagement = () => {
|
|
|
973
914
|
width: 180,
|
|
974
915
|
render: (_, record) => (
|
|
975
916
|
<div className="action-buttons">
|
|
976
|
-
<
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
aria-label="编辑接口"
|
|
982
|
-
/>
|
|
983
|
-
</Tooltip>
|
|
917
|
+
<Button
|
|
918
|
+
type="text"
|
|
919
|
+
icon={<EditOutlined />}
|
|
920
|
+
onClick={() => handleEditInterface(record)}
|
|
921
|
+
/>
|
|
984
922
|
<Popconfirm
|
|
985
923
|
title="确定要删除此接口吗?"
|
|
986
924
|
onConfirm={() => handleDeleteInterface(record.id)}
|
|
987
925
|
okText="确定"
|
|
988
926
|
cancelText="取消"
|
|
989
927
|
>
|
|
990
|
-
<
|
|
991
|
-
<Button
|
|
992
|
-
type="text"
|
|
993
|
-
danger
|
|
994
|
-
icon={<DeleteOutlined />}
|
|
995
|
-
aria-label="删除接口"
|
|
996
|
-
/>
|
|
997
|
-
</Tooltip>
|
|
928
|
+
<Button type="text" danger icon={<DeleteOutlined />} />
|
|
998
929
|
</Popconfirm>
|
|
999
930
|
</div>
|
|
1000
931
|
),
|
|
@@ -1045,6 +976,27 @@ const InterfaceManagement = () => {
|
|
|
1045
976
|
重构后版本 V2
|
|
1046
977
|
</div>
|
|
1047
978
|
|
|
979
|
+
{/* 警告信息置顶显示 */}
|
|
980
|
+
{!features.length && (
|
|
981
|
+
<Alert
|
|
982
|
+
message="未找到功能模块"
|
|
983
|
+
description="请先在模拟数据页面创建功能模块,然后再添加接口"
|
|
984
|
+
type="warning"
|
|
985
|
+
showIcon
|
|
986
|
+
style={{ marginBottom: 16 }}
|
|
987
|
+
/>
|
|
988
|
+
)}
|
|
989
|
+
|
|
990
|
+
{selectedFeature?.active === false && (
|
|
991
|
+
<Alert
|
|
992
|
+
message="功能模块已禁用"
|
|
993
|
+
description="当前功能模块已被禁用,所有关联接口不会生效。您可以在模拟数据页面启用此功能模块。"
|
|
994
|
+
type="warning"
|
|
995
|
+
showIcon
|
|
996
|
+
style={{ marginBottom: 16 }}
|
|
997
|
+
/>
|
|
998
|
+
)}
|
|
999
|
+
|
|
1048
1000
|
<Card className="interface-control-panel">
|
|
1049
1001
|
<div className="control-panel-header">
|
|
1050
1002
|
<div className="control-left">
|
|
@@ -1135,14 +1087,9 @@ const InterfaceManagement = () => {
|
|
|
1135
1087
|
<div className="control-panel-stats">
|
|
1136
1088
|
<div className="stats-left">
|
|
1137
1089
|
<Space size="large">
|
|
1138
|
-
<span className="stat-item">
|
|
1139
|
-
<span className="stat-label">功能模块:</span>
|
|
1140
|
-
<span className="stat-value">{selectedFeature?.name}</span>
|
|
1141
|
-
</span>
|
|
1142
|
-
|
|
1143
1090
|
{selectedGroup && (
|
|
1144
1091
|
<span className="stat-item">
|
|
1145
|
-
<span className="stat-label"
|
|
1092
|
+
<span className="stat-label">当前分组:</span>
|
|
1146
1093
|
<Tag color="blue">{selectedGroup}</Tag>
|
|
1147
1094
|
</span>
|
|
1148
1095
|
)}
|
|
@@ -1268,16 +1215,13 @@ const InterfaceManagement = () => {
|
|
|
1268
1215
|
</div>
|
|
1269
1216
|
}
|
|
1270
1217
|
>
|
|
1271
|
-
<Tooltip title="
|
|
1218
|
+
<Tooltip title="自定义表格显示列">
|
|
1272
1219
|
<Button
|
|
1273
1220
|
icon={<SettingOutlined />}
|
|
1274
1221
|
type="text"
|
|
1275
|
-
size="
|
|
1276
|
-
className="column-settings-btn"
|
|
1277
|
-
style={{
|
|
1278
|
-
marginLeft: (selectedRowKeys.length > 0 || selectedGroup) ? 16 : 0,
|
|
1279
|
-
color: '#666'
|
|
1280
|
-
}}
|
|
1222
|
+
size="small"
|
|
1223
|
+
className="inline-column-settings-btn"
|
|
1224
|
+
style={{ marginLeft: (selectedRowKeys.length > 0 || selectedGroup) ? 16 : 0 }}
|
|
1281
1225
|
>
|
|
1282
1226
|
列设置
|
|
1283
1227
|
</Button>
|
|
@@ -1287,29 +1231,7 @@ const InterfaceManagement = () => {
|
|
|
1287
1231
|
</div>
|
|
1288
1232
|
</Card>
|
|
1289
1233
|
|
|
1290
|
-
{
|
|
1291
|
-
<Alert
|
|
1292
|
-
message="未找到功能模块"
|
|
1293
|
-
description="请先在模拟数据页面创建功能模块,然后再添加接口"
|
|
1294
|
-
type="warning"
|
|
1295
|
-
showIcon
|
|
1296
|
-
style={{ marginBottom: 16 }}
|
|
1297
|
-
/>
|
|
1298
|
-
)}
|
|
1299
|
-
|
|
1300
|
-
{selectedFeature?.active === false && (
|
|
1301
|
-
<Alert
|
|
1302
|
-
message="功能模块已禁用"
|
|
1303
|
-
description="当前功能模块已被禁用,所有关联接口不会生效。您可以在模拟数据页面启用此功能模块。"
|
|
1304
|
-
type="warning"
|
|
1305
|
-
showIcon
|
|
1306
|
-
style={{ marginBottom: 16 }}
|
|
1307
|
-
/>
|
|
1308
|
-
)}
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
<Card className="list-container-card" bordered={false} bodyStyle={{ padding: 0 }}>
|
|
1234
|
+
<Card className="list-container-card" bordered={false} bodyStyle={{ padding: 0 }}>
|
|
1313
1235
|
<div className="interface-list-container">
|
|
1314
1236
|
<Table
|
|
1315
1237
|
columns={columns}
|
|
@@ -1340,36 +1262,81 @@ const InterfaceManagement = () => {
|
|
|
1340
1262
|
|
|
1341
1263
|
{/* 接口编辑/创建模态框 */}
|
|
1342
1264
|
<Modal
|
|
1343
|
-
title={
|
|
1265
|
+
title={
|
|
1266
|
+
<div style={{
|
|
1267
|
+
fontSize: '18px',
|
|
1268
|
+
fontWeight: 600,
|
|
1269
|
+
color: '#262626',
|
|
1270
|
+
display: 'flex',
|
|
1271
|
+
alignItems: 'center',
|
|
1272
|
+
gap: '8px'
|
|
1273
|
+
}}>
|
|
1274
|
+
<span>{editingInterface ? '编辑接口' : '添加接口'}</span>
|
|
1275
|
+
<Badge
|
|
1276
|
+
count="配置向导"
|
|
1277
|
+
style={{
|
|
1278
|
+
backgroundColor: '#f0f9ff',
|
|
1279
|
+
color: '#1677ff',
|
|
1280
|
+
fontSize: '11px',
|
|
1281
|
+
fontWeight: 'normal'
|
|
1282
|
+
}}
|
|
1283
|
+
/>
|
|
1284
|
+
</div>
|
|
1285
|
+
}
|
|
1344
1286
|
open={modalVisible}
|
|
1345
1287
|
onOk={handleSubmit}
|
|
1346
1288
|
onCancel={handleCancel}
|
|
1347
|
-
width={
|
|
1289
|
+
width={1200}
|
|
1348
1290
|
destroyOnClose
|
|
1349
1291
|
okText={editingInterface ? '保存' : '创建'}
|
|
1350
1292
|
cancelText="取消"
|
|
1351
|
-
bodyStyle={{
|
|
1293
|
+
bodyStyle={{
|
|
1294
|
+
maxHeight: '75vh',
|
|
1295
|
+
overflow: 'auto',
|
|
1296
|
+
padding: '0',
|
|
1297
|
+
background: '#fafafa'
|
|
1298
|
+
}}
|
|
1299
|
+
className="interface-modal"
|
|
1352
1300
|
>
|
|
1353
|
-
<
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1301
|
+
<div style={{ padding: '24px' }}>
|
|
1302
|
+
<Form
|
|
1303
|
+
form={form}
|
|
1304
|
+
layout="vertical"
|
|
1305
|
+
initialValues={{
|
|
1306
|
+
name: '',
|
|
1307
|
+
group: '',
|
|
1308
|
+
pattern: '',
|
|
1309
|
+
proxyType: 'response',
|
|
1310
|
+
statusCode: '200',
|
|
1311
|
+
contentType: 'application/json; charset=utf-8',
|
|
1312
|
+
responses: [],
|
|
1313
|
+
httpMethod: 'ALL',
|
|
1314
|
+
targetUrl: '',
|
|
1315
|
+
headerItems: [],
|
|
1316
|
+
paramMatchers: [],
|
|
1317
|
+
responseDelay: '0'
|
|
1318
|
+
}}
|
|
1319
|
+
>
|
|
1320
|
+
<Collapse
|
|
1321
|
+
defaultActiveKey={
|
|
1322
|
+
editingInterface
|
|
1323
|
+
? (editingInterface.proxyType === 'response' ? ['3'] : ['1', '2'])
|
|
1324
|
+
: ['1', '2', '3']
|
|
1325
|
+
}
|
|
1326
|
+
style={{ marginBottom: '16px' }}
|
|
1327
|
+
ghost
|
|
1328
|
+
>
|
|
1329
|
+
{/* 第一步:基础信息 */}
|
|
1330
|
+
<Collapse.Panel
|
|
1331
|
+
header={
|
|
1332
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
1333
|
+
<Badge count="1" style={{ backgroundColor: '#1677ff' }} />
|
|
1334
|
+
<span>基础信息</span>
|
|
1335
|
+
</div>
|
|
1336
|
+
}
|
|
1337
|
+
key="1"
|
|
1338
|
+
>
|
|
1339
|
+
<div style={{ display: 'flex', flexDirection: 'row', gap: '16px' }}>
|
|
1373
1340
|
<div style={{ flex: 1 }}>
|
|
1374
1341
|
<Form.Item
|
|
1375
1342
|
name="name"
|
|
@@ -1413,10 +1380,21 @@ const InterfaceManagement = () => {
|
|
|
1413
1380
|
))}
|
|
1414
1381
|
</Select>
|
|
1415
1382
|
</Form.Item>
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1383
|
+
</div>
|
|
1384
|
+
</div>
|
|
1385
|
+
</Collapse.Panel>
|
|
1386
|
+
|
|
1387
|
+
{/* 第二步:URL配置 */}
|
|
1388
|
+
<Collapse.Panel
|
|
1389
|
+
header={
|
|
1390
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
1391
|
+
<Badge count="2" style={{ backgroundColor: '#1677ff' }} />
|
|
1392
|
+
<span>URL配置</span>
|
|
1393
|
+
</div>
|
|
1394
|
+
}
|
|
1395
|
+
key="2"
|
|
1396
|
+
>
|
|
1397
|
+
<div style={{ display: 'flex', flexDirection: 'row', gap: '16px' }}>
|
|
1420
1398
|
<div style={{ flex: 1 }}>
|
|
1421
1399
|
<Form.Item
|
|
1422
1400
|
name="pattern"
|
|
@@ -1556,7 +1534,19 @@ const InterfaceManagement = () => {
|
|
|
1556
1534
|
<div style={{ flex: 1 }}>
|
|
1557
1535
|
{/* 这里可以留空或添加其他字段 */}
|
|
1558
1536
|
</div>
|
|
1559
|
-
|
|
1537
|
+
</div>
|
|
1538
|
+
</Collapse.Panel>
|
|
1539
|
+
|
|
1540
|
+
{/* 第三步:高级配置 */}
|
|
1541
|
+
<Collapse.Panel
|
|
1542
|
+
header={
|
|
1543
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
1544
|
+
<Badge count="3" style={{ backgroundColor: '#1677ff' }} />
|
|
1545
|
+
<span>高级配置</span>
|
|
1546
|
+
</div>
|
|
1547
|
+
}
|
|
1548
|
+
key="3"
|
|
1549
|
+
>
|
|
1560
1550
|
|
|
1561
1551
|
{/* 根据proxyType显示不同的表单项 */}
|
|
1562
1552
|
<Form.Item noStyle shouldUpdate={(prevValues, currentValues) => prevValues.proxyType !== currentValues.proxyType}>
|
|
@@ -1670,30 +1660,42 @@ const InterfaceManagement = () => {
|
|
|
1670
1660
|
/>
|
|
1671
1661
|
</div>
|
|
1672
1662
|
))}
|
|
1673
|
-
<
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
<
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1663
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginTop: '8px' }}>
|
|
1664
|
+
<Button
|
|
1665
|
+
type="dashed"
|
|
1666
|
+
onClick={() => add()}
|
|
1667
|
+
icon={<PlusOutlined />}
|
|
1668
|
+
style={{ flex: 1 }}
|
|
1669
|
+
>
|
|
1670
|
+
添加参数匹配规则
|
|
1671
|
+
</Button>
|
|
1672
|
+
<Popover
|
|
1673
|
+
content={
|
|
1674
|
+
<div style={{ maxWidth: '300px' }}>
|
|
1675
|
+
<div style={{ marginBottom: '8px', fontWeight: 'bold' }}>匹配规则说明:</div>
|
|
1676
|
+
<div style={{ lineHeight: '1.6' }}>
|
|
1677
|
+
<div>• <strong>精确匹配</strong>:参数值完全相等</div>
|
|
1678
|
+
<div>• <strong>包含</strong>:参数值包含指定内容</div>
|
|
1679
|
+
<div>• <strong>正则</strong>:参数值符合正则表达式</div>
|
|
1680
|
+
<div>• <strong>嵌套路径</strong>:使用点号分隔,如 data.user.id</div>
|
|
1681
|
+
</div>
|
|
1682
|
+
</div>
|
|
1683
|
+
}
|
|
1684
|
+
title="参数匹配规则"
|
|
1685
|
+
trigger="click"
|
|
1686
|
+
placement="top"
|
|
1687
|
+
>
|
|
1688
|
+
<Button
|
|
1689
|
+
type="text"
|
|
1690
|
+
icon={<QuestionCircleOutlined />}
|
|
1691
|
+
style={{
|
|
1692
|
+
color: '#999',
|
|
1693
|
+
padding: '4px'
|
|
1694
|
+
}}
|
|
1695
|
+
size="small"
|
|
1696
|
+
/>
|
|
1697
|
+
</Popover>
|
|
1698
|
+
</div>
|
|
1697
1699
|
</>
|
|
1698
1700
|
)}
|
|
1699
1701
|
</Form.List>
|
|
@@ -1817,7 +1819,10 @@ const InterfaceManagement = () => {
|
|
|
1817
1819
|
return null;
|
|
1818
1820
|
}}
|
|
1819
1821
|
</Form.Item>
|
|
1820
|
-
|
|
1822
|
+
</Collapse.Panel>
|
|
1823
|
+
</Collapse>
|
|
1824
|
+
</Form>
|
|
1825
|
+
</div>
|
|
1821
1826
|
</Modal>
|
|
1822
1827
|
|
|
1823
1828
|
{/* 使用拆分后的预览模态框组件 */}
|