whistle.mock-plugins 1.1.1-dev.9 → 1.1.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.
@@ -4,11 +4,13 @@ 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, Tag
7
+ Popover, Checkbox, Tag, Input as AntInput, Radio, Drawer
8
8
  } from 'antd';
9
9
  import {
10
10
  PlusOutlined, EditOutlined, DeleteOutlined,
11
- FileTextOutlined, PlusCircleOutlined, SettingOutlined
11
+ FileTextOutlined, PlusCircleOutlined, SettingOutlined,
12
+ SearchOutlined, FilterOutlined, AppstoreOutlined,
13
+ UnorderedListOutlined, ReloadOutlined
12
14
  } from '@ant-design/icons';
13
15
  import '../styles/interface-management.css';
14
16
  import axios from 'axios';
@@ -27,6 +29,7 @@ import {
27
29
  } from '../components/interface-management';
28
30
 
29
31
  const { Option } = Select;
32
+ const { Search } = AntInput;
30
33
 
31
34
  // 列配置数据结构
32
35
  const COLUMN_CONFIG = [
@@ -75,6 +78,12 @@ const InterfaceManagement = () => {
75
78
  const [previewContent, setPreviewContent] = useState(null);
76
79
  const [currentResponseId, setCurrentResponseId] = useState(null);
77
80
 
81
+ // 搜索和视图状态
82
+ const [searchValue, setSearchValue] = useState('');
83
+ const [viewMode, setViewMode] = useState('table'); // 'table' or 'card'
84
+ const [selectedRowKeys, setSelectedRowKeys] = useState([]);
85
+ const [drawerVisible, setDrawerVisible] = useState(false);
86
+
78
87
  // 表单实例
79
88
  const [form] = Form.useForm();
80
89
 
@@ -172,6 +181,7 @@ const InterfaceManagement = () => {
172
181
 
173
182
  setInterfaces(processedInterfaces);
174
183
  console.log('处理后的接口列表:', processedInterfaces);
184
+ console.log('接口分组信息:', processedInterfaces.map(item => ({ id: item.id, name: item.name, group: item.group })));
175
185
 
176
186
  // 提取并更新分组列表
177
187
  updateGroups(processedInterfaces);
@@ -209,16 +219,25 @@ const InterfaceManagement = () => {
209
219
  }
210
220
  };
211
221
 
212
- // 根据分组筛选接口
222
+ // 根据分组和搜索关键词筛选接口
213
223
  const getFilteredInterfaces = () => {
214
224
  // 首先按功能模块筛选
215
- const featureFiltered = interfaces.filter(item =>
225
+ let featureFiltered = interfaces.filter(item =>
216
226
  !selectedFeatureId || item.featureId === selectedFeatureId
217
227
  );
218
228
 
219
229
  // 然后按分组筛选
220
230
  if (selectedGroup) {
221
- return featureFiltered.filter(item => item.group === selectedGroup);
231
+ featureFiltered = featureFiltered.filter(item => item.group === selectedGroup);
232
+ }
233
+
234
+ // 最后按搜索关键词筛选
235
+ if (searchValue) {
236
+ const searchLower = searchValue.toLowerCase();
237
+ return featureFiltered.filter(item =>
238
+ (item.name && item.name.toLowerCase().includes(searchLower)) ||
239
+ (item.urlPattern && item.urlPattern.toLowerCase().includes(searchLower))
240
+ );
222
241
  }
223
242
 
224
243
  return featureFiltered;
@@ -250,7 +269,8 @@ const InterfaceManagement = () => {
250
269
  activeResponseId: defaultResponseId,
251
270
  httpMethod: 'ALL',
252
271
  headerItems: [], // 初始化为空数组
253
- paramMatchers: [] // 初始化为空数组
272
+ paramMatchers: [], // 初始化为空数组
273
+ group: undefined // 确保分组字段为undefined,而不是空字符串
254
274
  });
255
275
 
256
276
  setCurrentResponseId(defaultResponseId);
@@ -297,10 +317,16 @@ const InterfaceManagement = () => {
297
317
  }));
298
318
  }
299
319
 
320
+ // 处理分组值,确保它是字符串而不是数组
321
+ let groupValue = record.group;
322
+ if (Array.isArray(groupValue)) {
323
+ groupValue = groupValue.length > 0 ? groupValue[0] : undefined;
324
+ }
325
+
300
326
  // 设置表单值
301
327
  form.setFieldsValue({
302
328
  name: record.name,
303
- group: record.group || '',
329
+ group: groupValue || undefined, // 使用undefined而不是空字符串
304
330
  pattern: record.urlPattern,
305
331
  proxyType: record.proxyType || 'response',
306
332
  statusCode: (record.httpStatus || record.statusCode || 200).toString(),
@@ -314,6 +340,8 @@ const InterfaceManagement = () => {
314
340
  responseDelay: record.responseDelay ? record.responseDelay.toString() : '0'
315
341
  });
316
342
 
343
+ console.log('编辑接口时设置的分组值:', groupValue);
344
+
317
345
  setCurrentResponseId(activeResponseId);
318
346
  setEditingInterface(record);
319
347
  setModalVisible(true);
@@ -373,10 +401,16 @@ const InterfaceManagement = () => {
373
401
  });
374
402
  }
375
403
 
404
+ // 处理分组值,确保它是字符串而不是数组
405
+ let groupValue = values.group;
406
+ if (Array.isArray(groupValue)) {
407
+ groupValue = groupValue.length > 0 ? groupValue[0] : '';
408
+ }
409
+
376
410
  // 构建接口数据
377
411
  const interfaceData = {
378
412
  name: values.name,
379
- group: values.group,
413
+ group: groupValue || '', // 确保group不为undefined
380
414
  urlPattern: values.pattern,
381
415
  proxyType: values.proxyType,
382
416
  featureId: selectedFeatureId,
@@ -389,6 +423,8 @@ const InterfaceManagement = () => {
389
423
  active: true
390
424
  };
391
425
 
426
+ console.log('提交的分组值:', groupValue);
427
+
392
428
  // 根据代理类型添加不同字段
393
429
  if (values.proxyType === 'redirect' || values.proxyType === 'url_redirect') {
394
430
  interfaceData.targetUrl = values.targetUrl;
@@ -423,6 +459,8 @@ const InterfaceManagement = () => {
423
459
  const response = await axios.post('/cgi-bin/interfaces', interfaceData);
424
460
  if (response.data && response.data.code === 0) {
425
461
  message.success('接口创建成功');
462
+ console.log('接口创建成功,返回数据:', response.data);
463
+ console.log('返回的接口数据中的分组信息:', response.data.data?.group);
426
464
  setModalVisible(false);
427
465
  fetchInterfaces();
428
466
 
@@ -552,6 +590,60 @@ const InterfaceManagement = () => {
552
590
  setColumnConfigVisible(visible);
553
591
  };
554
592
 
593
+ // 搜索处理
594
+ const handleSearch = (value) => {
595
+ setSearchValue(value);
596
+ };
597
+
598
+ // 清除搜索
599
+ const handleClearSearch = () => {
600
+ setSearchValue('');
601
+ };
602
+
603
+ // 表格行选择处理
604
+ const onSelectChange = (selectedKeys) => {
605
+ setSelectedRowKeys(selectedKeys);
606
+ };
607
+
608
+ // 切换视图模式
609
+ const toggleViewMode = () => {
610
+ setViewMode(viewMode === 'table' ? 'card' : 'table');
611
+ };
612
+
613
+ // 刷新数据
614
+ const refreshData = () => {
615
+ fetchInterfaces();
616
+ message.success('数据已刷新');
617
+ };
618
+
619
+ // 批量操作接口状态
620
+ const handleBatchOperation = async (active) => {
621
+ if (!selectedRowKeys || selectedRowKeys.length === 0) {
622
+ message.warning('请先选择要操作的接口');
623
+ return;
624
+ }
625
+
626
+ try {
627
+ setLoading(true);
628
+ const operations = selectedRowKeys.map(id =>
629
+ axios.patch(`/cgi-bin/interfaces/${id}`, { active })
630
+ );
631
+
632
+ await Promise.all(operations);
633
+ message.success(`已${active ? '启用' : '禁用'} ${selectedRowKeys.length} 个接口`);
634
+ setSelectedRowKeys([]);
635
+ fetchInterfaces();
636
+
637
+ // 刷新规则缓存
638
+ refreshCacheAfterUpdate();
639
+ } catch (error) {
640
+ console.error('批量操作失败:', error);
641
+ message.error('批量操作失败: ' + (error.response?.data?.message || error.message));
642
+ } finally {
643
+ setLoading(false);
644
+ }
645
+ };
646
+
555
647
  // 定义所有可用的列
556
648
  const allColumns = [
557
649
  {
@@ -868,35 +960,69 @@ const InterfaceManagement = () => {
868
960
  return (
869
961
  <AppLayout>
870
962
  <div className="interface-management-container">
871
- <div className="interface-management-header">
872
- <div className="feature-selector">
873
- <span>功能模块:</span>
874
- <Select
875
- value={selectedFeatureId}
876
- onChange={handleSelectFeature}
877
- style={{ width: 200 }}
878
- placeholder="选择功能模块"
879
- loading={featuresLoading}
880
- >
881
- {(features || []).map(feature => (
882
- <Option key={feature.id} value={feature.id}>
883
- {feature.name}
884
- {feature.active === false &&
885
- <span style={{ color: '#ff4d4f', marginLeft: 8 }}>(已禁用)</span>
886
- }
887
- </Option>
888
- ))}
889
- </Select>
963
+ <Card className="interface-header-card">
964
+ <div className="interface-management-header">
965
+ <div className="feature-selector-container">
966
+ <div className="feature-selector">
967
+ <span>功能模块:</span>
968
+ <Select
969
+ value={selectedFeatureId}
970
+ onChange={handleSelectFeature}
971
+ style={{ width: 240 }}
972
+ placeholder="选择功能模块"
973
+ loading={featuresLoading}
974
+ dropdownMatchSelectWidth={false}
975
+ >
976
+ {(features || []).map(feature => (
977
+ <Option key={feature.id} value={feature.id}>
978
+ {feature.name}
979
+ {feature.active === false &&
980
+ <span style={{ color: '#ff4d4f', marginLeft: 8 }}>(已禁用)</span>
981
+ }
982
+ </Option>
983
+ ))}
984
+ </Select>
985
+ </div>
986
+
987
+ <Search
988
+ placeholder="搜索接口名称或URL"
989
+ onSearch={handleSearch}
990
+ value={searchValue}
991
+ onChange={(e) => setSearchValue(e.target.value)}
992
+ style={{ width: 250, marginLeft: 16 }}
993
+ enterButton={<SearchOutlined />}
994
+ allowClear
995
+ />
996
+ </div>
997
+
998
+ <div className="interface-actions">
999
+ <Space>
1000
+ <Tooltip title="刷新数据">
1001
+ <Button
1002
+ icon={<ReloadOutlined />}
1003
+ onClick={refreshData}
1004
+ loading={interfacesLoading}
1005
+ />
1006
+ </Tooltip>
1007
+ <Tooltip title={viewMode === 'table' ? '切换到卡片视图' : '切换到表格视图'}>
1008
+ <Button
1009
+ icon={viewMode === 'table' ? <AppstoreOutlined /> : <UnorderedListOutlined />}
1010
+ onClick={toggleViewMode}
1011
+ />
1012
+ </Tooltip>
1013
+ <Button
1014
+ type="primary"
1015
+ icon={<PlusOutlined />}
1016
+ onClick={handleAddInterface}
1017
+ disabled={!selectedFeatureId || selectedFeature?.active === false}
1018
+ className="add-interface-button"
1019
+ >
1020
+ 添加接口
1021
+ </Button>
1022
+ </Space>
1023
+ </div>
890
1024
  </div>
891
- <Button
892
- type="primary"
893
- icon={<PlusOutlined />}
894
- onClick={handleAddInterface}
895
- disabled={!selectedFeatureId || selectedFeature?.active === false}
896
- >
897
- 添加接口
898
- </Button>
899
- </div>
1025
+ </Card>
900
1026
 
901
1027
  {!features.length && (
902
1028
  <Alert
@@ -919,30 +1045,11 @@ const InterfaceManagement = () => {
919
1045
  )}
920
1046
 
921
1047
  {/* 分组筛选和操作区域 */}
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>
1048
+ <Card className="filter-card" bordered={false}>
1049
+ <div className="filter-header">
1050
+ <div className="filter-title">
1051
+ <FilterOutlined /> 分组筛选
1052
+ </div>
946
1053
  {selectedGroup && (
947
1054
  <Button
948
1055
  type="link"
@@ -954,8 +1061,27 @@ const InterfaceManagement = () => {
954
1061
  )}
955
1062
  </div>
956
1063
 
1064
+ <div className="group-tags-container">
1065
+ {groups.length === 0 ? (
1066
+ <div className="empty-groups">暂无分组</div>
1067
+ ) : (
1068
+ <div className="group-tags">
1069
+ {groups.map(group => (
1070
+ <Tag
1071
+ key={group}
1072
+ color={selectedGroup === group ? "blue" : "default"}
1073
+ onClick={() => setSelectedGroup(group === selectedGroup ? null : group)}
1074
+ className={`group-tag ${selectedGroup === group ? 'active' : ''}`}
1075
+ >
1076
+ {group} ({interfaces.filter(item => item.group === group).length})
1077
+ </Tag>
1078
+ ))}
1079
+ </div>
1080
+ )}
1081
+ </div>
1082
+
957
1083
  {selectedGroup && (
958
- <div style={{ display: 'flex', gap: '8px' }}>
1084
+ <div className="group-actions">
959
1085
  <Popconfirm
960
1086
  title={`确定要启用分组 "${selectedGroup}" 中的所有接口吗?`}
961
1087
  onConfirm={() => handleBatchToggleActive(true)}
@@ -987,40 +1113,60 @@ const InterfaceManagement = () => {
987
1113
  </Popconfirm>
988
1114
  </div>
989
1115
  )}
990
- </div>
1116
+ </Card>
991
1117
 
992
1118
  {/* 接口列表状态栏 */}
993
- {filteredInterfaces.length > 0 && !interfacesLoading && (
994
- <div style={{
995
- marginBottom: 16,
996
- padding: '8px 12px',
997
- background: '#f8f9fa',
998
- borderRadius: '4px',
999
- fontSize: '13px',
1000
- color: '#666',
1001
- display: 'flex',
1002
- justifyContent: 'space-between',
1003
- alignItems: 'center'
1004
- }}>
1005
- <span>
1006
- 当前功能模块:<strong>{selectedFeature?.name}</strong>
1007
- {selectedGroup && (
1008
- <span style={{ marginLeft: 8 }}>
1009
- | 分组:<Tag color="blue">{selectedGroup}</Tag>
1010
- </span>
1011
- )}
1012
- </span>
1013
- <span>
1014
- 共 {filteredInterfaces.length} 个接口,每页显示 {tableConfig.pageSize} 个
1015
- {tableConfig.sortField && (
1016
- <span style={{ marginLeft: 8 }}>
1017
- | 按"{allColumns.find(col => col.key === tableConfig.sortField)?.title || tableConfig.sortField}"
1018
- {tableConfig.sortOrder === 'ascend' ? '升序' : '降序'}排列
1019
- </span>
1119
+ <Card className="list-header-card" bordered={false}>
1120
+ <div className="list-header">
1121
+ <div className="list-header-info">
1122
+ <div className="feature-info">
1123
+ <span className="label">功能模块:</span>
1124
+ <span className="value">{selectedFeature?.name}</span>
1125
+ {selectedGroup && (
1126
+ <Tag color="blue" className="group-badge">{selectedGroup}</Tag>
1127
+ )}
1128
+ </div>
1129
+ <div className="interface-stats">
1130
+ {searchValue ? (
1131
+ <Badge
1132
+ count={`搜索"${searchValue}" - ${filteredInterfaces.length}个结果`}
1133
+ style={{ backgroundColor: '#108ee9' }}
1134
+ />
1135
+ ) : (
1136
+ <Badge
1137
+ count={`共 ${filteredInterfaces.length} 个接口`}
1138
+ style={{ backgroundColor: '#52c41a' }}
1139
+ />
1140
+ )}
1141
+ </div>
1142
+ </div>
1143
+ <div className="batch-actions">
1144
+ {selectedRowKeys.length > 0 && (
1145
+ <Space>
1146
+ <span className="selected-count">
1147
+ 已选择 {selectedRowKeys.length} 项
1148
+ </span>
1149
+ <Popconfirm
1150
+ title="确定要批量启用选中的接口吗?"
1151
+ onConfirm={() => handleBatchOperation(true)}
1152
+ okText="确定"
1153
+ cancelText="取消"
1154
+ >
1155
+ <Button size="small" type="primary">批量启用</Button>
1156
+ </Popconfirm>
1157
+ <Popconfirm
1158
+ title="确定要批量禁用选中的接口吗?"
1159
+ onConfirm={() => handleBatchOperation(false)}
1160
+ okText="确定"
1161
+ cancelText="取消"
1162
+ >
1163
+ <Button size="small" danger>批量禁用</Button>
1164
+ </Popconfirm>
1165
+ </Space>
1020
1166
  )}
1021
- </span>
1167
+ </div>
1022
1168
  </div>
1023
- )}
1169
+ </Card>
1024
1170
 
1025
1171
  {/* 列配置区域 */}
1026
1172
  <div style={{
@@ -1085,26 +1231,156 @@ const InterfaceManagement = () => {
1085
1231
  </Popover>
1086
1232
  </div>
1087
1233
 
1088
- <div className="interface-list-container">
1089
- <Table
1090
- columns={columns}
1091
- dataSource={filteredInterfaces}
1092
- rowKey="id"
1093
- loading={interfacesLoading}
1094
- onChange={handleTableChange}
1095
- pagination={{
1096
- current: tableConfig.current,
1097
- pageSize: tableConfig.pageSize,
1098
- showSizeChanger: true,
1099
- showQuickJumper: true,
1100
- showTotal: (total, range) => `共 ${total} 个接口,显示第 ${range[0]}-${range[1]} 个`,
1101
- pageSizeOptions: ['10', '20', '50', '100'],
1102
- size: 'default'
1103
- }}
1104
- locale={{ emptyText: '暂无接口配置' }}
1105
- sortDirections={['ascend', 'descend']}
1106
- />
1107
- </div>
1234
+ <Card className="list-container-card" bordered={false} bodyStyle={{ padding: 0 }}>
1235
+ {/* 表格视图 */}
1236
+ {viewMode === 'table' && (
1237
+ <div className="interface-list-container">
1238
+ <Table
1239
+ columns={columns}
1240
+ dataSource={filteredInterfaces}
1241
+ rowKey="id"
1242
+ loading={interfacesLoading}
1243
+ onChange={handleTableChange}
1244
+ rowSelection={{
1245
+ selectedRowKeys,
1246
+ onChange: onSelectChange,
1247
+ }}
1248
+ size="middle"
1249
+ pagination={{
1250
+ current: tableConfig.current,
1251
+ pageSize: tableConfig.pageSize,
1252
+ showSizeChanger: true,
1253
+ showQuickJumper: true,
1254
+ showTotal: (total, range) => `共 ${total} 个接口,显示第 ${range[0]}-${range[1]} 个`,
1255
+ pageSizeOptions: ['10', '20', '50', '100'],
1256
+ size: 'default'
1257
+ }}
1258
+ locale={{ emptyText: '暂无接口配置' }}
1259
+ sortDirections={['ascend', 'descend']}
1260
+ className="interface-table"
1261
+ />
1262
+ </div>
1263
+ )}
1264
+
1265
+ {/* 卡片视图 */}
1266
+ {viewMode === 'card' && (
1267
+ <div className="interface-card-view">
1268
+ <Row gutter={[16, 16]} style={{ padding: 16 }}>
1269
+ {interfacesLoading ? (
1270
+ [1,2,3,4,5,6].map(i => (
1271
+ <Col xs={24} sm={12} md={8} lg={8} xl={6} key={`loading-${i}`}>
1272
+ <Card loading style={{ height: 180 }} />
1273
+ </Col>
1274
+ ))
1275
+ ) : filteredInterfaces.length === 0 ? (
1276
+ <Col span={24}>
1277
+ <div className="empty-data">暂无接口配置</div>
1278
+ </Col>
1279
+ ) : (
1280
+ filteredInterfaces.map(item => (
1281
+ <Col xs={24} sm={12} md={8} lg={8} xl={6} key={item.id}>
1282
+ <Card
1283
+ className={`interface-card ${item.active === false ? 'inactive' : ''}`}
1284
+ hoverable
1285
+ >
1286
+ <div className="interface-card-header">
1287
+ <Switch
1288
+ checked={item.active !== false}
1289
+ onChange={() => handleToggleActive(item.id, item.active)}
1290
+ size="small"
1291
+ className="interface-card-switch"
1292
+ />
1293
+ <div className="interface-card-title">{item.name}</div>
1294
+ {item.group && (
1295
+ <Tag
1296
+ color="blue"
1297
+ className="interface-card-group"
1298
+ onClick={() => setSelectedGroup(item.group)}
1299
+ >
1300
+ {item.group}
1301
+ </Tag>
1302
+ )}
1303
+ </div>
1304
+
1305
+ <div className="interface-card-content">
1306
+ <div className="url-pattern-container">
1307
+ <Tooltip title={item.urlPattern}>
1308
+ <div className="url-pattern">{item.urlPattern}</div>
1309
+ </Tooltip>
1310
+ </div>
1311
+
1312
+ <div className="interface-card-info">
1313
+ <div className="info-item">
1314
+ <span className="info-label">处理方式:</span>
1315
+ <Badge
1316
+ color={proxyTypes.find(t => t.value === item.proxyType)?.color || '#999'}
1317
+ text={proxyTypes.find(t => t.value === item.proxyType)?.label || item.proxyType}
1318
+ className="info-value"
1319
+ />
1320
+ </div>
1321
+ <div className="info-item">
1322
+ <span className="info-label">状态码:</span>
1323
+ <span className={`status-badge status-${item.httpStatus >= 400 ? 'error' : item.httpStatus >= 300 ? 'warning' : 'success'}`}>
1324
+ {item.httpStatus || 200}
1325
+ </span>
1326
+ </div>
1327
+ </div>
1328
+ </div>
1329
+
1330
+ <div className="interface-card-actions">
1331
+ <Button
1332
+ type="primary"
1333
+ size="small"
1334
+ icon={<EditOutlined />}
1335
+ onClick={() => handleEditInterface(item)}
1336
+ >
1337
+ 编辑
1338
+ </Button>
1339
+ <Popconfirm
1340
+ title="确定要删除此接口吗?"
1341
+ onConfirm={() => handleDeleteInterface(item.id)}
1342
+ okText="确定"
1343
+ cancelText="取消"
1344
+ >
1345
+ <Button
1346
+ danger
1347
+ size="small"
1348
+ icon={<DeleteOutlined />}
1349
+ >
1350
+ 删除
1351
+ </Button>
1352
+ </Popconfirm>
1353
+ </div>
1354
+ </Card>
1355
+ </Col>
1356
+ ))
1357
+ )}
1358
+ </Row>
1359
+
1360
+ {/* 卡片视图分页 */}
1361
+ {filteredInterfaces.length > 0 && (
1362
+ <div className="card-pagination">
1363
+ <Pagination
1364
+ current={tableConfig.current}
1365
+ pageSize={tableConfig.pageSize}
1366
+ total={filteredInterfaces.length}
1367
+ showSizeChanger
1368
+ showQuickJumper
1369
+ showTotal={(total, range) => `共 ${total} 个接口,显示第 ${range[0]}-${range[1]} 个`}
1370
+ pageSizeOptions={['10', '20', '50', '100']}
1371
+ size="default"
1372
+ onChange={(page, pageSize) => {
1373
+ saveTableConfig({
1374
+ current: page,
1375
+ pageSize: pageSize
1376
+ });
1377
+ }}
1378
+ />
1379
+ </div>
1380
+ )}
1381
+ </div>
1382
+ )}
1383
+ </Card>
1108
1384
 
1109
1385
  {/* 接口编辑/创建模态框 */}
1110
1386
  <Modal
@@ -1157,6 +1433,24 @@ const InterfaceManagement = () => {
1157
1433
  placeholder="选择或创建分组"
1158
1434
  showSearch
1159
1435
  allowClear
1436
+ style={{ width: '100%' }}
1437
+ mode="tags"
1438
+ maxTagCount="responsive"
1439
+ maxTagTextLength={10}
1440
+ onChange={(value) => {
1441
+ // 如果值是数组(tags模式),只取第一个元素
1442
+ if (Array.isArray(value) && value.length > 0) {
1443
+ // 如果第一个元素是空字符串,则设置为undefined
1444
+ const groupValue = value[0] === '' ? undefined : value[0];
1445
+ form.setFieldsValue({ group: groupValue });
1446
+ }
1447
+ }}
1448
+ onInputKeyDown={(e) => {
1449
+ // 防止回车键提交表单
1450
+ if (e.key === 'Enter') {
1451
+ e.stopPropagation();
1452
+ }
1453
+ }}
1160
1454
  >
1161
1455
  {Array.from(new Set(interfaces.map(item => item.group).filter(Boolean))).map(group => (
1162
1456
  <Option key={group} value={group}>{group}</Option>