whistle.mock-plugins 1.1.3-dev.8 → 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 +165 -91
- package/ui/src/pages/MockDataV2.js +124 -96
- package/ui/src/styles/interface-management.css +149 -46
- 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';
|
|
@@ -976,6 +976,27 @@ const InterfaceManagement = () => {
|
|
|
976
976
|
重构后版本 V2
|
|
977
977
|
</div>
|
|
978
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
|
+
|
|
979
1000
|
<Card className="interface-control-panel">
|
|
980
1001
|
<div className="control-panel-header">
|
|
981
1002
|
<div className="control-left">
|
|
@@ -1066,14 +1087,9 @@ const InterfaceManagement = () => {
|
|
|
1066
1087
|
<div className="control-panel-stats">
|
|
1067
1088
|
<div className="stats-left">
|
|
1068
1089
|
<Space size="large">
|
|
1069
|
-
<span className="stat-item">
|
|
1070
|
-
<span className="stat-label">功能模块:</span>
|
|
1071
|
-
<span className="stat-value">{selectedFeature?.name}</span>
|
|
1072
|
-
</span>
|
|
1073
|
-
|
|
1074
1090
|
{selectedGroup && (
|
|
1075
1091
|
<span className="stat-item">
|
|
1076
|
-
<span className="stat-label"
|
|
1092
|
+
<span className="stat-label">当前分组:</span>
|
|
1077
1093
|
<Tag color="blue">{selectedGroup}</Tag>
|
|
1078
1094
|
</span>
|
|
1079
1095
|
)}
|
|
@@ -1199,16 +1215,13 @@ const InterfaceManagement = () => {
|
|
|
1199
1215
|
</div>
|
|
1200
1216
|
}
|
|
1201
1217
|
>
|
|
1202
|
-
<Tooltip title="
|
|
1218
|
+
<Tooltip title="自定义表格显示列">
|
|
1203
1219
|
<Button
|
|
1204
1220
|
icon={<SettingOutlined />}
|
|
1205
1221
|
type="text"
|
|
1206
|
-
size="
|
|
1207
|
-
className="column-settings-btn"
|
|
1208
|
-
style={{
|
|
1209
|
-
marginLeft: (selectedRowKeys.length > 0 || selectedGroup) ? 16 : 0,
|
|
1210
|
-
color: '#666'
|
|
1211
|
-
}}
|
|
1222
|
+
size="small"
|
|
1223
|
+
className="inline-column-settings-btn"
|
|
1224
|
+
style={{ marginLeft: (selectedRowKeys.length > 0 || selectedGroup) ? 16 : 0 }}
|
|
1212
1225
|
>
|
|
1213
1226
|
列设置
|
|
1214
1227
|
</Button>
|
|
@@ -1218,29 +1231,7 @@ const InterfaceManagement = () => {
|
|
|
1218
1231
|
</div>
|
|
1219
1232
|
</Card>
|
|
1220
1233
|
|
|
1221
|
-
{
|
|
1222
|
-
<Alert
|
|
1223
|
-
message="未找到功能模块"
|
|
1224
|
-
description="请先在模拟数据页面创建功能模块,然后再添加接口"
|
|
1225
|
-
type="warning"
|
|
1226
|
-
showIcon
|
|
1227
|
-
style={{ marginBottom: 16 }}
|
|
1228
|
-
/>
|
|
1229
|
-
)}
|
|
1230
|
-
|
|
1231
|
-
{selectedFeature?.active === false && (
|
|
1232
|
-
<Alert
|
|
1233
|
-
message="功能模块已禁用"
|
|
1234
|
-
description="当前功能模块已被禁用,所有关联接口不会生效。您可以在模拟数据页面启用此功能模块。"
|
|
1235
|
-
type="warning"
|
|
1236
|
-
showIcon
|
|
1237
|
-
style={{ marginBottom: 16 }}
|
|
1238
|
-
/>
|
|
1239
|
-
)}
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
<Card className="list-container-card" bordered={false} bodyStyle={{ padding: 0 }}>
|
|
1234
|
+
<Card className="list-container-card" bordered={false} bodyStyle={{ padding: 0 }}>
|
|
1244
1235
|
<div className="interface-list-container">
|
|
1245
1236
|
<Table
|
|
1246
1237
|
columns={columns}
|
|
@@ -1271,36 +1262,81 @@ const InterfaceManagement = () => {
|
|
|
1271
1262
|
|
|
1272
1263
|
{/* 接口编辑/创建模态框 */}
|
|
1273
1264
|
<Modal
|
|
1274
|
-
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
|
+
}
|
|
1275
1286
|
open={modalVisible}
|
|
1276
1287
|
onOk={handleSubmit}
|
|
1277
1288
|
onCancel={handleCancel}
|
|
1278
|
-
width={
|
|
1289
|
+
width={1200}
|
|
1279
1290
|
destroyOnClose
|
|
1280
1291
|
okText={editingInterface ? '保存' : '创建'}
|
|
1281
1292
|
cancelText="取消"
|
|
1282
|
-
bodyStyle={{
|
|
1293
|
+
bodyStyle={{
|
|
1294
|
+
maxHeight: '75vh',
|
|
1295
|
+
overflow: 'auto',
|
|
1296
|
+
padding: '0',
|
|
1297
|
+
background: '#fafafa'
|
|
1298
|
+
}}
|
|
1299
|
+
className="interface-modal"
|
|
1283
1300
|
>
|
|
1284
|
-
<
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
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' }}>
|
|
1304
1340
|
<div style={{ flex: 1 }}>
|
|
1305
1341
|
<Form.Item
|
|
1306
1342
|
name="name"
|
|
@@ -1344,10 +1380,21 @@ const InterfaceManagement = () => {
|
|
|
1344
1380
|
))}
|
|
1345
1381
|
</Select>
|
|
1346
1382
|
</Form.Item>
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
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' }}>
|
|
1351
1398
|
<div style={{ flex: 1 }}>
|
|
1352
1399
|
<Form.Item
|
|
1353
1400
|
name="pattern"
|
|
@@ -1487,7 +1534,19 @@ const InterfaceManagement = () => {
|
|
|
1487
1534
|
<div style={{ flex: 1 }}>
|
|
1488
1535
|
{/* 这里可以留空或添加其他字段 */}
|
|
1489
1536
|
</div>
|
|
1490
|
-
|
|
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
|
+
>
|
|
1491
1550
|
|
|
1492
1551
|
{/* 根据proxyType显示不同的表单项 */}
|
|
1493
1552
|
<Form.Item noStyle shouldUpdate={(prevValues, currentValues) => prevValues.proxyType !== currentValues.proxyType}>
|
|
@@ -1601,30 +1660,42 @@ const InterfaceManagement = () => {
|
|
|
1601
1660
|
/>
|
|
1602
1661
|
</div>
|
|
1603
1662
|
))}
|
|
1604
|
-
<
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
<
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
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>
|
|
1628
1699
|
</>
|
|
1629
1700
|
)}
|
|
1630
1701
|
</Form.List>
|
|
@@ -1748,7 +1819,10 @@ const InterfaceManagement = () => {
|
|
|
1748
1819
|
return null;
|
|
1749
1820
|
}}
|
|
1750
1821
|
</Form.Item>
|
|
1751
|
-
|
|
1822
|
+
</Collapse.Panel>
|
|
1823
|
+
</Collapse>
|
|
1824
|
+
</Form>
|
|
1825
|
+
</div>
|
|
1752
1826
|
</Modal>
|
|
1753
1827
|
|
|
1754
1828
|
{/* 使用拆分后的预览模态框组件 */}
|
|
@@ -520,24 +520,22 @@ const MockData = () => {
|
|
|
520
520
|
return (
|
|
521
521
|
<AppLayout>
|
|
522
522
|
<div className="page-container">
|
|
523
|
-
{/* V2版本标识 */}
|
|
524
|
-
<div style={{
|
|
525
|
-
position: 'absolute',
|
|
526
|
-
top: '10px',
|
|
527
|
-
right: '10px',
|
|
528
|
-
backgroundColor: '#52c41a',
|
|
529
|
-
color: 'white',
|
|
530
|
-
padding: '4px 8px',
|
|
531
|
-
borderRadius: '4px',
|
|
532
|
-
fontSize: '12px',
|
|
533
|
-
zIndex: 1000
|
|
534
|
-
}}>
|
|
535
|
-
V2版本
|
|
536
|
-
</div>
|
|
537
|
-
|
|
538
523
|
<div className="page-title-bar">
|
|
539
|
-
<div>
|
|
540
|
-
<
|
|
524
|
+
<div className="title-section">
|
|
525
|
+
<div className="title-with-badge">
|
|
526
|
+
<h1 className="page-title">功能模块管理</h1>
|
|
527
|
+
<Badge
|
|
528
|
+
count="V2"
|
|
529
|
+
style={{
|
|
530
|
+
backgroundColor: '#52c41a',
|
|
531
|
+
fontSize: '12px',
|
|
532
|
+
height: '20px',
|
|
533
|
+
lineHeight: '20px',
|
|
534
|
+
borderRadius: '10px',
|
|
535
|
+
marginLeft: '12px'
|
|
536
|
+
}}
|
|
537
|
+
/>
|
|
538
|
+
</div>
|
|
541
539
|
<div className="page-description">
|
|
542
540
|
创建和管理功能模块,为每个功能配置独立的接口
|
|
543
541
|
</div>
|
|
@@ -561,117 +559,147 @@ const MockData = () => {
|
|
|
561
559
|
</div>
|
|
562
560
|
</div>
|
|
563
561
|
|
|
564
|
-
{/*
|
|
562
|
+
{/* 控制面板 */}
|
|
565
563
|
{mockFeatures.length > 0 && !loading && (
|
|
566
|
-
<
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
564
|
+
<Card className="control-panel-card" style={{ marginBottom: 24 }}>
|
|
565
|
+
<Row gutter={[24, 16]} align="middle">
|
|
566
|
+
{/* 统计信息区域 */}
|
|
567
|
+
<Col xs={24} sm={12} md={8} lg={6}>
|
|
568
|
+
<div className="stats-section">
|
|
569
|
+
<div className="stats-item">
|
|
570
|
+
<span className="stats-number">{mockFeatures.length}</span>
|
|
571
|
+
<span className="stats-label">功能模块</span>
|
|
572
|
+
</div>
|
|
573
|
+
<div className="stats-item">
|
|
574
|
+
<span className="stats-number">
|
|
575
|
+
{mockFeatures.filter(f => f.active).length}
|
|
576
|
+
</span>
|
|
577
|
+
<span className="stats-label">已启用</span>
|
|
578
|
+
</div>
|
|
579
|
+
<div className="stats-item">
|
|
580
|
+
<span className="stats-number">
|
|
581
|
+
{mockFeatures.reduce((sum, f) => sum + (f.interfaceCount || 0), 0)}
|
|
582
|
+
</span>
|
|
583
|
+
<span className="stats-label">接口总数</span>
|
|
584
|
+
</div>
|
|
585
|
+
</div>
|
|
586
|
+
</Col>
|
|
587
|
+
|
|
588
|
+
{/* 排序控制区域 */}
|
|
589
|
+
<Col xs={24} sm={12} md={8} lg={9}>
|
|
590
|
+
<div className="sort-controls">
|
|
591
|
+
<div className="control-group">
|
|
592
|
+
<span className="control-label">
|
|
593
|
+
<SortAscendingOutlined /> 排序方式
|
|
594
|
+
</span>
|
|
595
|
+
<Select
|
|
596
|
+
value={listConfig.sortBy}
|
|
597
|
+
onChange={handleSortChange}
|
|
598
|
+
style={{ width: 120 }}
|
|
599
|
+
size="middle"
|
|
600
|
+
>
|
|
601
|
+
<Select.Option value="name">名称</Select.Option>
|
|
602
|
+
<Select.Option value="createdAt">创建时间</Select.Option>
|
|
603
|
+
<Select.Option value="interfaceCount">接口数量</Select.Option>
|
|
604
|
+
<Select.Option value="active">状态</Select.Option>
|
|
605
|
+
</Select>
|
|
606
|
+
<Select
|
|
607
|
+
value={listConfig.sortOrder}
|
|
608
|
+
onChange={handleSortOrderChange}
|
|
609
|
+
style={{ width: 80 }}
|
|
610
|
+
size="middle"
|
|
611
|
+
>
|
|
612
|
+
<Select.Option value="ascend">升序</Select.Option>
|
|
613
|
+
<Select.Option value="descend">降序</Select.Option>
|
|
614
|
+
</Select>
|
|
615
|
+
</div>
|
|
616
|
+
</div>
|
|
617
|
+
</Col>
|
|
618
|
+
|
|
619
|
+
{/* 分页控制区域 */}
|
|
620
|
+
<Col xs={24} sm={24} md={8} lg={9}>
|
|
621
|
+
<div className="pagination-controls">
|
|
622
|
+
<div className="control-group">
|
|
623
|
+
<span className="control-label">每页显示</span>
|
|
624
|
+
<Select
|
|
625
|
+
value={listConfig.pageSize}
|
|
626
|
+
onChange={handlePageSizeChange}
|
|
627
|
+
style={{ width: 80 }}
|
|
628
|
+
size="middle"
|
|
629
|
+
>
|
|
630
|
+
<Select.Option value={8}>8</Select.Option>
|
|
631
|
+
<Select.Option value={12}>12</Select.Option>
|
|
632
|
+
<Select.Option value={16}>16</Select.Option>
|
|
633
|
+
<Select.Option value={24}>24</Select.Option>
|
|
634
|
+
</Select>
|
|
635
|
+
<span className="page-info">
|
|
636
|
+
第 {(listConfig.current - 1) * listConfig.pageSize + 1}-{Math.min(listConfig.current * listConfig.pageSize, mockFeatures.length)} 条
|
|
637
|
+
</span>
|
|
638
|
+
</div>
|
|
639
|
+
</div>
|
|
640
|
+
</Col>
|
|
641
|
+
</Row>
|
|
642
|
+
</Card>
|
|
621
643
|
)}
|
|
622
644
|
|
|
623
|
-
<
|
|
645
|
+
<Card className="feature-list-card">
|
|
624
646
|
{loading ? (
|
|
625
|
-
<div className="loading">
|
|
626
|
-
<
|
|
627
|
-
<div>正在加载功能模块...</div>
|
|
647
|
+
<div className="loading-state">
|
|
648
|
+
<Spin size="large" />
|
|
649
|
+
<div className="loading-text">正在加载功能模块...</div>
|
|
628
650
|
</div>
|
|
629
651
|
) : mockFeatures.length > 0 ? (
|
|
630
652
|
<>
|
|
631
|
-
<Row gutter={[
|
|
653
|
+
<Row gutter={[20, 20]} className="feature-grid">
|
|
632
654
|
{getPaginatedFeatures().map(feature => renderFeatureCard(feature))}
|
|
633
655
|
</Row>
|
|
634
656
|
|
|
635
657
|
{/* 分页组件 */}
|
|
636
658
|
{mockFeatures.length > listConfig.pageSize && (
|
|
637
|
-
<div
|
|
638
|
-
marginTop: 24,
|
|
639
|
-
textAlign: 'center',
|
|
640
|
-
padding: '16px',
|
|
641
|
-
borderTop: '1px solid #f0f0f0'
|
|
642
|
-
}}>
|
|
659
|
+
<div className="pagination-wrapper">
|
|
643
660
|
<Pagination
|
|
644
661
|
current={listConfig.current}
|
|
645
662
|
pageSize={listConfig.pageSize}
|
|
646
663
|
total={mockFeatures.length}
|
|
647
664
|
onChange={handlePageChange}
|
|
648
665
|
onShowSizeChange={handlePageChange}
|
|
649
|
-
showSizeChanger={
|
|
666
|
+
showSizeChanger={false}
|
|
650
667
|
showQuickJumper={true}
|
|
651
668
|
showTotal={(total, range) =>
|
|
652
669
|
`第 ${range[0]}-${range[1]} 条,共 ${total} 个功能模块`
|
|
653
670
|
}
|
|
654
|
-
pageSizeOptions={['8', '12', '16', '24']}
|
|
655
671
|
size="default"
|
|
672
|
+
className="custom-pagination"
|
|
656
673
|
/>
|
|
657
674
|
</div>
|
|
658
675
|
)}
|
|
659
676
|
</>
|
|
660
677
|
) : (
|
|
661
|
-
<
|
|
662
|
-
|
|
663
|
-
|
|
678
|
+
<Empty
|
|
679
|
+
className="custom-empty"
|
|
680
|
+
image={
|
|
681
|
+
<div className="empty-image">
|
|
682
|
+
<ApiOutlined style={{ fontSize: 64, color: '#d9d9d9' }} />
|
|
683
|
+
</div>
|
|
684
|
+
}
|
|
685
|
+
description={
|
|
686
|
+
<div className="empty-description">
|
|
687
|
+
<div className="empty-title">暂无功能模块</div>
|
|
688
|
+
<div className="empty-subtitle">创建您的第一个功能模块,开始管理接口</div>
|
|
689
|
+
</div>
|
|
690
|
+
}
|
|
691
|
+
>
|
|
664
692
|
<div className="empty-actions">
|
|
665
|
-
<
|
|
693
|
+
<Button type="primary" icon={<PlusOutlined />} onClick={() => openModal()}>
|
|
666
694
|
创建新功能
|
|
667
|
-
</
|
|
668
|
-
<
|
|
669
|
-
|
|
670
|
-
</
|
|
695
|
+
</Button>
|
|
696
|
+
<Button icon={<ExportOutlined />} onClick={importFeatureConfig}>
|
|
697
|
+
导入功能
|
|
698
|
+
</Button>
|
|
671
699
|
</div>
|
|
672
|
-
</
|
|
700
|
+
</Empty>
|
|
673
701
|
)}
|
|
674
|
-
</
|
|
702
|
+
</Card>
|
|
675
703
|
</div>
|
|
676
704
|
|
|
677
705
|
<Modal
|